OLD | NEW |
---|---|
1 // Copyright (c) 2013, 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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/bootstrap.h" | 8 #include "vm/bootstrap.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/constant_propagator.h" | 10 #include "vm/constant_propagator.h" |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 compiler->Bailout(ToCString()); | 135 compiler->Bailout(ToCString()); |
136 UNREACHABLE(); | 136 UNREACHABLE(); |
137 } | 137 } |
138 | 138 |
139 | 139 |
140 bool Value::Equals(Value* other) const { | 140 bool Value::Equals(Value* other) const { |
141 return definition() == other->definition(); | 141 return definition() == other->definition(); |
142 } | 142 } |
143 | 143 |
144 | 144 |
145 static int LowestFirst(const intptr_t* a, const intptr_t* b) { | |
146 return *a - *b; | |
147 } | |
148 | |
149 | |
150 CheckClassInstr::CheckClassInstr(Value* value, | 145 CheckClassInstr::CheckClassInstr(Value* value, |
151 intptr_t deopt_id, | 146 intptr_t deopt_id, |
152 const ICData& unary_checks, | 147 const Cids& cids, |
153 TokenPosition token_pos) | 148 TokenPosition token_pos) |
154 : TemplateInstruction(deopt_id), | 149 : TemplateInstruction(deopt_id), |
155 unary_checks_(unary_checks), | 150 cids_(cids), |
156 cids_(unary_checks.NumberOfChecks()), | |
157 licm_hoisted_(false), | 151 licm_hoisted_(false), |
158 is_dense_switch_(IsDenseCidRange(unary_checks)), | 152 is_bit_test_(IsCompactCidRange(cids)), |
159 token_pos_(token_pos) { | 153 token_pos_(token_pos) { |
160 ASSERT(unary_checks.IsZoneHandle()); | |
161 // Expected useful check data. | 154 // Expected useful check data. |
162 ASSERT(!unary_checks_.IsNull()); | 155 const intptr_t number_of_checks = cids.length(); |
163 const intptr_t number_of_checks = unary_checks_.NumberOfChecks(); | |
164 ASSERT(number_of_checks > 0); | 156 ASSERT(number_of_checks > 0); |
165 ASSERT(unary_checks_.NumArgsTested() == 1); | |
166 SetInputAt(0, value); | 157 SetInputAt(0, value); |
167 // Otherwise use CheckSmiInstr. | 158 // Otherwise use CheckSmiInstr. |
168 ASSERT(number_of_checks != 1 || | 159 ASSERT(number_of_checks != 1 || cids[0].cid_start != cids[0].cid_end || |
169 (unary_checks_.GetReceiverClassIdAt(0) != kSmiCid)); | 160 cids[0].cid_start != kSmiCid); |
170 for (intptr_t i = 0; i < number_of_checks; ++i) { | |
171 cids_.Add(unary_checks.GetReceiverClassIdAt(i)); | |
172 } | |
173 cids_.Sort(LowestFirst); | |
174 } | 161 } |
175 | 162 |
176 | 163 |
177 bool CheckClassInstr::AttributesEqual(Instruction* other) const { | 164 bool CheckClassInstr::AttributesEqual(Instruction* other) const { |
178 CheckClassInstr* other_check = other->AsCheckClass(); | 165 CheckClassInstr* other_check = other->AsCheckClass(); |
179 ASSERT(other_check != NULL); | 166 ASSERT(other_check != NULL); |
180 const intptr_t number_of_checks = unary_checks_.NumberOfChecks(); | 167 return cids().Equals(other_check->cids()); |
181 if (number_of_checks != other_check->unary_checks().NumberOfChecks()) { | 168 } |
182 return false; | 169 |
170 | |
171 bool Cids::ContainsExternalizableCids() const { | |
Vyacheslav Egorov (Google)
2017/05/09 21:07:27
How about moving Cids methods all together instead
erikcorry
2017/05/10 08:47:43
Done.
| |
172 for (intptr_t i = 0; i < length(); i++) { | |
173 for (intptr_t cid = cid_ranges_[i]->cid_start; | |
174 cid <= cid_ranges_[i]->cid_end; cid++) { | |
175 if (Field::IsExternalizableCid(cid)) { | |
176 return true; | |
177 } | |
178 } | |
183 } | 179 } |
184 for (intptr_t i = 0; i < number_of_checks; ++i) { | 180 return false; |
185 // TODO(fschneider): Make sure ic_data are sorted to hit more cases. | 181 } |
186 if (unary_checks().GetReceiverClassIdAt(i) != | 182 |
187 other_check->unary_checks().GetReceiverClassIdAt(i)) { | 183 |
184 bool Cids::Equals(const Cids& other) const { | |
185 if (length() != other.length()) return false; | |
186 for (int i = 0; i < length(); i++) { | |
187 if (cid_ranges_[i]->cid_start != other.cid_ranges_[i]->cid_start || | |
188 cid_ranges_[i]->cid_end != other.cid_ranges_[i]->cid_end) { | |
188 return false; | 189 return false; |
189 } | 190 } |
190 } | 191 } |
191 return true; | 192 return true; |
192 } | |
193 | |
194 | |
195 static bool AreAllChecksImmutable(const ICData& checks) { | |
196 const intptr_t len = checks.NumberOfChecks(); | |
197 for (intptr_t i = 0; i < len; i++) { | |
198 if (checks.IsUsedAt(i)) { | |
199 if (Field::IsExternalizableCid(checks.GetReceiverClassIdAt(i))) { | |
200 return false; | |
201 } | |
202 } | |
203 } | |
204 return true; | |
205 } | 193 } |
206 | 194 |
207 | 195 |
208 EffectSet CheckClassInstr::Dependencies() const { | 196 EffectSet CheckClassInstr::Dependencies() const { |
209 // Externalization of strings via the API can change the class-id. | 197 // Externalization of strings via the API can change the class-id. |
210 return !AreAllChecksImmutable(unary_checks()) ? EffectSet::Externalization() | 198 return cids_.ContainsExternalizableCids() ? EffectSet::Externalization() |
211 : EffectSet::None(); | 199 : EffectSet::None(); |
212 } | 200 } |
213 | 201 |
214 | 202 |
215 EffectSet CheckClassIdInstr::Dependencies() const { | 203 EffectSet CheckClassIdInstr::Dependencies() const { |
216 // Externalization of strings via the API can change the class-id. | 204 // Externalization of strings via the API can change the class-id. |
217 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() | 205 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() |
218 : EffectSet::None(); | 206 : EffectSet::None(); |
219 } | 207 } |
220 | 208 |
221 | 209 |
222 bool CheckClassInstr::DeoptIfNull() const { | 210 bool CheckClassInstr::IsDeoptIfNull() const { |
223 if (!unary_checks().NumberOfChecksIs(1)) { | 211 if (!cids().IsMonomorphic()) { |
224 return false; | 212 return false; |
225 } | 213 } |
226 CompileType* in_type = value()->Type(); | 214 CompileType* in_type = value()->Type(); |
227 const intptr_t cid = unary_checks().GetCidAt(0); | 215 const intptr_t cid = cids().MonomorphicReceiverCid(); |
228 // Performance check: use CheckSmiInstr instead. | 216 // Performance check: use CheckSmiInstr instead. |
229 ASSERT(cid != kSmiCid); | 217 ASSERT(cid != kSmiCid); |
230 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); | 218 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); |
231 } | 219 } |
232 | 220 |
233 | 221 |
234 // Null object is a singleton of null-class (except for some sentinel, | 222 // Null object is a singleton of null-class (except for some sentinel, |
235 // transitional temporaries). Instead of checking against the null class only | 223 // transitional temporaries). Instead of checking against the null class only |
236 // we can check against null instance instead. | 224 // we can check against null instance instead. |
237 bool CheckClassInstr::DeoptIfNotNull() const { | 225 bool CheckClassInstr::IsDeoptIfNotNull() const { |
238 if (!unary_checks().NumberOfChecksIs(1)) { | 226 if (!cids().IsMonomorphic()) { |
239 return false; | 227 return false; |
240 } | 228 } |
241 const intptr_t cid = unary_checks().GetCidAt(0); | 229 const intptr_t cid = cids().MonomorphicReceiverCid(); |
242 return cid == kNullCid; | 230 return cid == kNullCid; |
243 } | 231 } |
244 | 232 |
245 | 233 |
246 bool CheckClassInstr::IsDenseCidRange(const ICData& unary_checks) { | 234 bool CheckClassInstr::IsCompactCidRange(const Cids& cids) { |
247 ASSERT(unary_checks.NumArgsTested() == 1); | 235 const intptr_t number_of_checks = cids.length(); |
236 // If there are only two checks, the extra register pressure needed for the | |
237 // dense-cid-range code is not justified. | |
238 if (number_of_checks <= 2) return false; | |
239 | |
248 // TODO(fschneider): Support smis in dense cid checks. | 240 // TODO(fschneider): Support smis in dense cid checks. |
249 if (unary_checks.GetReceiverClassIdAt(0) == kSmiCid) return false; | 241 if (cids.HasClassId(kSmiCid)) return false; |
250 const intptr_t number_of_checks = unary_checks.NumberOfChecks(); | 242 |
251 if (number_of_checks <= 2) return false; | 243 intptr_t min = cids.ComputeLowestCid(); |
252 intptr_t max = 0; | 244 intptr_t max = cids.ComputeHighestCid(); |
253 intptr_t min = kIntptrMax; | |
254 for (intptr_t i = 0; i < number_of_checks; ++i) { | |
255 intptr_t cid = unary_checks.GetCidAt(i); | |
256 if (cid < min) min = cid; | |
257 if (cid > max) max = cid; | |
258 } | |
259 return (max - min) < kBitsPerWord; | 245 return (max - min) < kBitsPerWord; |
260 } | 246 } |
261 | 247 |
262 | 248 |
263 bool CheckClassInstr::IsDenseSwitch() const { | 249 bool CheckClassInstr::IsBitTest() const { |
264 return is_dense_switch_; | 250 return is_bit_test_; |
251 } | |
252 | |
253 | |
254 intptr_t Cids::ComputeLowestCid() const { | |
255 intptr_t min = kIntptrMax; | |
256 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | |
257 min = Utils::Minimum(min, cid_ranges_[i]->cid_start); | |
258 } | |
259 return min; | |
260 } | |
261 | |
262 | |
263 intptr_t Cids::ComputeHighestCid() const { | |
264 intptr_t max = -1; | |
265 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | |
266 max = Utils::Maximum(max, cid_ranges_[i]->cid_end); | |
267 } | |
268 return max; | |
265 } | 269 } |
266 | 270 |
267 | 271 |
268 intptr_t CheckClassInstr::ComputeCidMask() const { | 272 intptr_t CheckClassInstr::ComputeCidMask() const { |
269 ASSERT(IsDenseSwitch()); | 273 ASSERT(IsBitTest()); |
274 intptr_t min = cids_.ComputeLowestCid(); | |
270 intptr_t mask = 0; | 275 intptr_t mask = 0; |
271 for (intptr_t i = 0; i < cids_.length(); ++i) { | 276 for (intptr_t i = 0; i < cids_.length(); ++i) { |
272 mask |= static_cast<intptr_t>(1) << (cids_[i] - cids_[0]); | 277 intptr_t cid_start = cids_[i].cid_start; |
278 intptr_t cid_end = cids_[i].cid_end; | |
279 intptr_t run; | |
280 if (1ul + cid_end - cid_start >= sizeof(intptr_t) * 8) { | |
Vyacheslav Egorov (Google)
2017/05/09 21:07:27
there is kBitsPerWord
make a variable for cid_end
erikcorry
2017/05/10 08:47:43
Done.
| |
281 run = -1; | |
282 } else { | |
283 run = (1 << (1 + cid_end - cid_start)) - 1; | |
284 } | |
285 mask |= run << (cid_start - min); | |
273 } | 286 } |
274 return mask; | 287 return mask; |
275 } | 288 } |
276 | 289 |
277 | 290 |
278 bool CheckClassInstr::IsDenseMask(intptr_t mask) { | |
279 // Returns true if the mask is a continuous sequence of ones in its binary | |
280 // representation (i.e. no holes) | |
281 return mask == -1 || Utils::IsPowerOfTwo(mask + 1); | |
282 } | |
283 | |
284 | |
285 bool LoadFieldInstr::IsUnboxedLoad() const { | 291 bool LoadFieldInstr::IsUnboxedLoad() const { |
286 return FLAG_unbox_numeric_fields && (field() != NULL) && | 292 return FLAG_unbox_numeric_fields && (field() != NULL) && |
287 FlowGraphCompiler::IsUnboxedField(*field()); | 293 FlowGraphCompiler::IsUnboxedField(*field()); |
288 } | 294 } |
289 | 295 |
290 | 296 |
291 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { | 297 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { |
292 return FLAG_unbox_numeric_fields && (field() != NULL) && | 298 return FLAG_unbox_numeric_fields && (field() != NULL) && |
293 FlowGraphCompiler::IsPotentialUnboxedField(*field()); | 299 FlowGraphCompiler::IsPotentialUnboxedField(*field()); |
294 } | 300 } |
(...skipping 2264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2559 Definition* replacement = CanonicalizeStrictCompare(this, &negated, | 2565 Definition* replacement = CanonicalizeStrictCompare(this, &negated, |
2560 /* is_branch = */ false); | 2566 /* is_branch = */ false); |
2561 if (negated && replacement->IsComparison()) { | 2567 if (negated && replacement->IsComparison()) { |
2562 ASSERT(replacement != this); | 2568 ASSERT(replacement != this); |
2563 replacement->AsComparison()->NegateComparison(); | 2569 replacement->AsComparison()->NegateComparison(); |
2564 } | 2570 } |
2565 return replacement; | 2571 return replacement; |
2566 } | 2572 } |
2567 | 2573 |
2568 | 2574 |
2575 bool Cids::HasClassId(intptr_t cid) const { | |
2576 for (int i = 0; i < length(); i++) { | |
2577 if (cid_ranges_[i]->cid_start <= cid && cid <= cid_ranges_[i]->cid_end) { | |
2578 return true; | |
2579 } | |
2580 } | |
2581 return false; | |
2582 } | |
2583 | |
2584 | |
2569 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { | 2585 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { |
2570 const intptr_t value_cid = value()->Type()->ToCid(); | 2586 const intptr_t value_cid = value()->Type()->ToCid(); |
2571 if (value_cid == kDynamicCid) { | 2587 if (value_cid == kDynamicCid) { |
2572 return this; | 2588 return this; |
2573 } | 2589 } |
2574 | 2590 |
2575 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; | 2591 return cids().HasClassId(value_cid) ? NULL : this; |
2576 } | 2592 } |
2577 | 2593 |
2578 | 2594 |
2579 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { | 2595 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { |
2580 if (value()->BindsToConstant()) { | 2596 if (value()->BindsToConstant()) { |
2581 const Object& constant_value = value()->BoundConstant(); | 2597 const Object& constant_value = value()->BoundConstant(); |
2582 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { | 2598 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { |
2583 return NULL; | 2599 return NULL; |
2584 } | 2600 } |
2585 } | 2601 } |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2734 case kUnboxedInt32x4: | 2750 case kUnboxedInt32x4: |
2735 return false; | 2751 return false; |
2736 | 2752 |
2737 default: | 2753 default: |
2738 UNREACHABLE(); | 2754 UNREACHABLE(); |
2739 return false; | 2755 return false; |
2740 } | 2756 } |
2741 } | 2757 } |
2742 | 2758 |
2743 | 2759 |
2744 static int OrderById(const CidRangeTarget* a, const CidRangeTarget* b) { | 2760 static int OrderById(CidRange* const* a, CidRange* const* b) { |
2745 // Negative if 'a' should sort before 'b'. | 2761 // Negative if 'a' should sort before 'b'. |
2746 ASSERT(a->cid_start == a->cid_end); | 2762 ASSERT((*a)->cid_start == (*a)->cid_end); |
2747 ASSERT(b->cid_start == b->cid_end); | 2763 ASSERT((*b)->cid_start == (*b)->cid_end); |
2748 return a->cid_start - b->cid_start; | 2764 return (*a)->cid_start - (*b)->cid_start; |
2749 } | 2765 } |
2750 | 2766 |
2751 | 2767 |
2752 static int OrderByFrequency(const CidRangeTarget* a, const CidRangeTarget* b) { | 2768 static int OrderByFrequency(CidRange* const* a, CidRange* const* b) { |
2769 const TargetInfo* target_info_a = reinterpret_cast<const TargetInfo*>(*a); | |
Vyacheslav Egorov (Google)
2017/05/09 21:07:27
static_cast instead.
erikcorry
2017/05/10 08:47:43
Done.
| |
2770 const TargetInfo* target_info_b = reinterpret_cast<const TargetInfo*>(*b); | |
2753 // Negative if 'a' should sort before 'b'. | 2771 // Negative if 'a' should sort before 'b'. |
2754 return b->count - a->count; | 2772 return target_info_b->count - target_info_a->count; |
2755 } | 2773 } |
2756 | 2774 |
2757 | 2775 |
2758 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { | 2776 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { |
2759 CallTargets* targets = new (zone) CallTargets(); | 2777 CallTargets* targets = new (zone) CallTargets(zone); |
2760 if (ic_data.NumberOfChecks() == 0) return targets; | 2778 targets->CreateHelper(zone, ic_data, /* argument_number = */ 0, |
2779 /* include_targets = */ true); | |
2780 targets->Sort(OrderById); | |
2781 targets->MergeIntoRanges(); | |
2782 return targets; | |
2783 } | |
2784 | |
2785 | |
2786 Cids* Cids::CreateMonomorphic(Zone* zone, intptr_t cid) { | |
2787 Cids* cids = new (zone) Cids(zone); | |
2788 cids->Add(new (zone) CidRange(cid, cid)); | |
2789 return cids; | |
2790 } | |
2791 | |
2792 | |
2793 Cids* Cids::Create(Zone* zone, const ICData& ic_data, int argument_number) { | |
2794 Cids* cids = new (zone) Cids(zone); | |
2795 cids->CreateHelper(zone, ic_data, argument_number, | |
2796 /* include_targets = */ false); | |
2797 cids->Sort(OrderById); | |
2798 | |
2799 // Merge adjacent class id ranges. | |
2800 int dest = 0; | |
2801 for (int src = 1; src < cids->length(); src++) { | |
2802 if (cids->cid_ranges_[dest]->cid_end + 1 >= | |
2803 cids->cid_ranges_[src]->cid_start) { | |
2804 cids->cid_ranges_[dest]->cid_end = cids->cid_ranges_[src]->cid_end; | |
2805 } else { | |
2806 dest++; | |
2807 if (src != dest) cids->cid_ranges_[dest] = cids->cid_ranges_[src]; | |
2808 } | |
2809 } | |
2810 cids->SetLength(dest + 1); | |
2811 | |
2812 return cids; | |
2813 } | |
2814 | |
2815 | |
2816 void Cids::CreateHelper(Zone* zone, | |
2817 const ICData& ic_data, | |
2818 int argument_number, | |
2819 bool include_targets) { | |
2820 ASSERT(argument_number < ic_data.NumArgsTested()); | |
2821 | |
2822 if (ic_data.NumberOfChecks() == 0) return; | |
2761 | 2823 |
2762 Function& dummy = Function::Handle(zone); | 2824 Function& dummy = Function::Handle(zone); |
2763 | 2825 |
2764 bool check_one_arg = ic_data.NumArgsTested() == 1; | 2826 bool check_one_arg = ic_data.NumArgsTested() == 1; |
2765 | 2827 |
2766 int checks = ic_data.NumberOfChecks(); | 2828 int checks = ic_data.NumberOfChecks(); |
2767 for (int i = 0; i < checks; i++) { | 2829 for (int i = 0; i < checks; i++) { |
2830 if (ic_data.GetCountAt(i) == 0) continue; | |
2768 intptr_t id = 0; | 2831 intptr_t id = 0; |
2769 if (check_one_arg) { | 2832 if (check_one_arg) { |
2770 ic_data.GetOneClassCheckAt(i, &id, &dummy); | 2833 ic_data.GetOneClassCheckAt(i, &id, &dummy); |
2771 } else { | 2834 } else { |
2772 // The API works for multi dispatch ICs that check more than one | |
2773 // argument, but we know we will only check one arg here, so only the 0th | |
2774 // element of id will be used. | |
2775 GrowableArray<intptr_t> arg_ids; | 2835 GrowableArray<intptr_t> arg_ids; |
2776 ic_data.GetCheckAt(i, &arg_ids, &dummy); | 2836 ic_data.GetCheckAt(i, &arg_ids, &dummy); |
2777 id = arg_ids[0]; | 2837 id = arg_ids[argument_number]; |
2778 } | 2838 } |
2779 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); | 2839 if (include_targets) { |
2780 targets->Add(CidRangeTarget(id, id, &function, ic_data.GetCountAt(i))); | 2840 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); |
2841 cid_ranges_.Add(new (zone) | |
2842 TargetInfo(id, id, &function, ic_data.GetCountAt(i))); | |
2843 } else { | |
2844 cid_ranges_.Add(new (zone) CidRange(id, id)); | |
2845 } | |
2781 } | 2846 } |
2847 } | |
2782 | 2848 |
2783 targets->Sort(OrderById); | 2849 |
2850 CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) { | |
2851 CallTargets& targets = *new (zone) CallTargets(zone); | |
2852 targets.CreateHelper(zone, ic_data, /* argument_number = */ 0, | |
2853 /* include_targets = */ true); | |
2854 targets.Sort(OrderById); | |
2784 | 2855 |
2785 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); | 2856 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); |
2786 ArgumentsDescriptor args_desc(args_desc_array); | 2857 ArgumentsDescriptor args_desc(args_desc_array); |
2787 String& name = String::Handle(zone, ic_data.target_name()); | 2858 String& name = String::Handle(zone, ic_data.target_name()); |
2788 | 2859 |
2789 Function& fn = Function::Handle(zone); | 2860 Function& fn = Function::Handle(zone); |
2790 | 2861 |
2791 intptr_t length = targets->length(); | 2862 intptr_t length = targets.length(); |
2792 | 2863 |
2793 // Spread class-ids to preceding classes where a lookup yields the same | 2864 // Spread class-ids to preceding classes where a lookup yields the same |
2794 // method. | 2865 // method. |
2795 for (int idx = 0; idx < length; idx++) { | 2866 for (int idx = 0; idx < length; idx++) { |
2796 int lower_limit_cid = (idx == 0) ? -1 : targets->At(idx - 1).cid_end; | 2867 int lower_limit_cid = (idx == 0) ? -1 : targets[idx - 1].cid_end; |
2797 const Function& target = *targets->At(idx).target; | 2868 const Function& target = *targets.TargetAt(idx)->target; |
2798 for (int i = targets->At(idx).cid_start - 1; i > lower_limit_cid; i--) { | 2869 for (int i = targets[idx].cid_start - 1; i > lower_limit_cid; i--) { |
2799 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && | 2870 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && |
2800 fn.raw() == target.raw()) { | 2871 fn.raw() == target.raw()) { |
2801 CidRangeTarget t = targets->At(idx); | 2872 targets[idx].cid_start = i; |
2802 t.cid_start = i; | |
2803 (*targets)[idx] = t; | |
2804 } else { | 2873 } else { |
2805 break; | 2874 break; |
2806 } | 2875 } |
2807 } | 2876 } |
2808 } | 2877 } |
2809 // Spread class-ids to following classes where a lookup yields the same | 2878 // Spread class-ids to following classes where a lookup yields the same |
2810 // method. | 2879 // method. |
2811 for (int idx = 0; idx < length; idx++) { | 2880 for (int idx = 0; idx < length; idx++) { |
2812 int upper_limit_cid = | 2881 int upper_limit_cid = |
2813 (idx == length - 1) ? 1000000000 : targets->At(idx + 1).cid_start; | 2882 (idx == length - 1) ? 1000000000 : targets[idx + 1].cid_start; |
2814 const Function& target = *targets->At(idx).target; | 2883 const Function& target = *targets.TargetAt(idx)->target; |
2815 for (int i = targets->At(idx).cid_end + 1; i < upper_limit_cid; i++) { | 2884 for (int i = targets[idx].cid_end + 1; i < upper_limit_cid; i++) { |
2816 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && | 2885 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && |
2817 fn.raw() == target.raw()) { | 2886 fn.raw() == target.raw()) { |
2818 (*targets)[idx].cid_end = i; | 2887 targets[idx].cid_end = i; |
2819 } else { | 2888 } else { |
2820 break; | 2889 break; |
2821 } | 2890 } |
2822 } | 2891 } |
2823 } | 2892 } |
2824 // Merge adjacent class id ranges. | 2893 targets.MergeIntoRanges(); |
2825 int dest = 0; | 2894 return &targets; |
2826 for (int src = 1; src < length; src++) { | |
2827 if (targets->At(dest).cid_end + 1 == targets->At(src).cid_start && | |
2828 targets->At(dest).target->raw() == targets->At(src).target->raw()) { | |
2829 (*targets)[dest].cid_end = targets->At(src).cid_end; | |
2830 (*targets)[dest].count += targets->At(src).count; | |
2831 } else { | |
2832 dest++; | |
2833 if (src != dest) (*targets)[dest] = targets->At(src); | |
2834 } | |
2835 } | |
2836 targets->SetLength(dest + 1); | |
2837 targets->Sort(OrderByFrequency); | |
2838 return targets; | |
2839 } | 2895 } |
2840 | 2896 |
2841 | 2897 |
2898 void CallTargets::MergeIntoRanges() { | |
2899 // Merge adjacent class id ranges. | |
2900 int dest = 0; | |
2901 for (int src = 1; src < length(); src++) { | |
2902 if (cid_ranges_[dest]->cid_end + 1 >= cid_ranges_[src]->cid_start && | |
Vyacheslav Egorov (Google)
2017/05/09 21:07:27
for uniformity use TargetAt(x) instead of cid_rang
erikcorry
2017/05/10 08:47:43
Done, but the assignment in the else clause needs
| |
2903 TargetAt(dest)->target->raw() == TargetAt(src)->target->raw()) { | |
2904 cid_ranges_[dest]->cid_end = cid_ranges_[src]->cid_end; | |
2905 TargetAt(dest)->count += TargetAt(src)->count; | |
2906 } else { | |
2907 dest++; | |
2908 if (src != dest) { | |
2909 cid_ranges_[dest] = cid_ranges_[src]; | |
2910 } | |
2911 } | |
2912 } | |
2913 SetLength(dest + 1); | |
2914 Sort(OrderByFrequency); | |
2915 } | |
2916 | |
2917 | |
2842 // Shared code generation methods (EmitNativeCode and | 2918 // Shared code generation methods (EmitNativeCode and |
2843 // MakeLocationSummary). Only assembly code that can be shared across all | 2919 // MakeLocationSummary). Only assembly code that can be shared across all |
2844 // architectures can be used. Machine specific register allocation and code | 2920 // architectures can be used. Machine specific register allocation and code |
2845 // generation is located in intermediate_language_<arch>.cc | 2921 // generation is located in intermediate_language_<arch>.cc |
2846 | 2922 |
2847 #define __ compiler->assembler()-> | 2923 #define __ compiler->assembler()-> |
2848 | 2924 |
2849 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, | 2925 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, |
2850 bool optimizing) const { | 2926 bool optimizing) const { |
2851 UNREACHABLE(); | 2927 UNREACHABLE(); |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3270 bool CallTargets::HasSingleRecognizedTarget() const { | 3346 bool CallTargets::HasSingleRecognizedTarget() const { |
3271 if (!HasSingleTarget()) return false; | 3347 if (!HasSingleTarget()) return false; |
3272 return MethodRecognizer::RecognizeKind(FirstTarget()) != | 3348 return MethodRecognizer::RecognizeKind(FirstTarget()) != |
3273 MethodRecognizer::kUnknown; | 3349 MethodRecognizer::kUnknown; |
3274 } | 3350 } |
3275 | 3351 |
3276 | 3352 |
3277 bool CallTargets::HasSingleTarget() const { | 3353 bool CallTargets::HasSingleTarget() const { |
3278 ASSERT(length() != 0); | 3354 ASSERT(length() != 0); |
3279 for (int i = 0; i < length(); i++) { | 3355 for (int i = 0; i < length(); i++) { |
3280 if (cid_ranges_[i].target->raw() != cid_ranges_[0].target->raw()) | 3356 if (TargetAt(i)->target->raw() != TargetAt(0)->target->raw()) return false; |
3281 return false; | |
3282 } | 3357 } |
3283 return true; | 3358 return true; |
3284 } | 3359 } |
3285 | 3360 |
3286 | 3361 |
3287 bool CallTargets::IsMonomorphic() const { | 3362 bool Cids::IsMonomorphic() const { |
3288 if (length() != 1) return false; | 3363 if (length() != 1) return false; |
3289 return cid_ranges_[0].cid_start == cid_ranges_[0].cid_end; | 3364 return cid_ranges_[0]->cid_start == cid_ranges_[0]->cid_end; |
3290 } | 3365 } |
3291 | 3366 |
3292 | 3367 |
3293 intptr_t CallTargets::MonomorphicReceiverCid() const { | 3368 intptr_t Cids::MonomorphicReceiverCid() const { |
3294 ASSERT(IsMonomorphic()); | 3369 ASSERT(IsMonomorphic()); |
3295 return cid_ranges_[0].cid_start; | 3370 return cid_ranges_[0]->cid_start; |
3296 } | 3371 } |
3297 | 3372 |
3298 | 3373 |
3299 Function& CallTargets::FirstTarget() const { | 3374 const Function& CallTargets::FirstTarget() const { |
3300 ASSERT(length() != 0); | 3375 ASSERT(length() != 0); |
3301 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | 3376 ASSERT(TargetAt(0)->target->IsZoneHandle()); |
3302 return *cid_ranges_[0].target; | 3377 return *TargetAt(0)->target; |
3303 } | 3378 } |
3304 | 3379 |
3305 | 3380 |
3306 Function& CallTargets::MostPopularTarget() const { | 3381 const Function& CallTargets::MostPopularTarget() const { |
3307 ASSERT(length() != 0); | 3382 ASSERT(length() != 0); |
3308 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | 3383 ASSERT(TargetAt(0)->target->IsZoneHandle()); |
3309 for (int i = 1; i < length(); i++) { | 3384 for (int i = 1; i < length(); i++) { |
3310 ASSERT(cid_ranges_[i].count <= cid_ranges_[0].count); | 3385 ASSERT(TargetAt(i)->count <= TargetAt(0)->count); |
3311 } | 3386 } |
3312 return *cid_ranges_[0].target; | 3387 return *TargetAt(0)->target; |
3313 } | 3388 } |
3314 | 3389 |
3315 | 3390 |
3316 intptr_t CallTargets::AggregateCallCount() const { | 3391 intptr_t CallTargets::AggregateCallCount() const { |
3317 intptr_t sum = 0; | 3392 intptr_t sum = 0; |
3318 for (int i = 0; i < length(); i++) { | 3393 for (int i = 0; i < length(); i++) { |
3319 sum += cid_ranges_[i].count; | 3394 sum += TargetAt(i)->count; |
3320 } | 3395 } |
3321 return sum; | 3396 return sum; |
3322 } | 3397 } |
3323 | 3398 |
3324 | 3399 |
3325 bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() | 3400 bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() |
3326 const { | 3401 const { |
3327 const intptr_t len = targets_.length(); | 3402 const intptr_t len = targets_.length(); |
3328 Function& target = Function::Handle(); | 3403 Function& target = Function::Handle(); |
3329 for (intptr_t i = 0; i < len; i++) { | 3404 for (intptr_t i = 0; i < len; i++) { |
3330 target ^= targets_[i].target->raw(); | 3405 target ^= targets_.TargetAt(i)->target->raw(); |
3331 if (!target.IsDispatcherOrImplicitAccessor()) { | 3406 if (!target.IsDispatcherOrImplicitAccessor()) { |
3332 return false; | 3407 return false; |
3333 } | 3408 } |
3334 } | 3409 } |
3335 return true; | 3410 return true; |
3336 } | 3411 } |
3337 | 3412 |
3338 | 3413 |
3339 intptr_t PolymorphicInstanceCallInstr::CallCount() const { | 3414 intptr_t PolymorphicInstanceCallInstr::CallCount() const { |
3340 return targets().AggregateCallCount(); | 3415 return targets().AggregateCallCount(); |
(...skipping 23 matching lines...) Expand all Loading... | |
3364 | 3439 |
3365 | 3440 |
3366 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( | 3441 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
3367 const CallTargets& targets) { | 3442 const CallTargets& targets) { |
3368 bool is_string = true; | 3443 bool is_string = true; |
3369 bool is_integer = true; | 3444 bool is_integer = true; |
3370 bool is_double = true; | 3445 bool is_double = true; |
3371 | 3446 |
3372 const intptr_t num_checks = targets.length(); | 3447 const intptr_t num_checks = targets.length(); |
3373 for (intptr_t i = 0; i < num_checks; i++) { | 3448 for (intptr_t i = 0; i < num_checks; i++) { |
3374 ASSERT(targets[i].target->raw() == targets[0].target->raw()); | 3449 ASSERT(targets.TargetAt(i)->target->raw() == |
3450 targets.TargetAt(0)->target->raw()); | |
3375 const intptr_t start = targets[i].cid_start; | 3451 const intptr_t start = targets[i].cid_start; |
3376 const intptr_t end = targets[i].cid_end; | 3452 const intptr_t end = targets[i].cid_end; |
3377 for (intptr_t cid = start; cid <= end; cid++) { | 3453 for (intptr_t cid = start; cid <= end; cid++) { |
3378 is_string = is_string && RawObject::IsStringClassId(cid); | 3454 is_string = is_string && RawObject::IsStringClassId(cid); |
3379 is_integer = is_integer && RawObject::IsIntegerClassId(cid); | 3455 is_integer = is_integer && RawObject::IsIntegerClassId(cid); |
3380 is_double = is_double && (cid == kDoubleCid); | 3456 is_double = is_double && (cid == kDoubleCid); |
3381 } | 3457 } |
3382 } | 3458 } |
3383 | 3459 |
3384 if (is_string) { | 3460 if (is_string) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3546 | 3622 |
3547 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3623 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3548 #if !defined(TARGET_ARCH_DBC) | 3624 #if !defined(TARGET_ARCH_DBC) |
3549 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | 3625 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); |
3550 #else | 3626 #else |
3551 compiler->EmitDeopt(deopt_id(), deopt_reason_); | 3627 compiler->EmitDeopt(deopt_id(), deopt_reason_); |
3552 #endif | 3628 #endif |
3553 } | 3629 } |
3554 | 3630 |
3555 | 3631 |
3632 #if !defined(TARGET_ARCH_DBC) | |
3633 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
3634 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass, | |
3635 licm_hoisted_ ? ICData::kHoisted : 0); | |
3636 if (IsNullCheck()) { | |
3637 EmitNullCheck(compiler, deopt); | |
3638 return; | |
3639 } | |
3640 | |
3641 ASSERT(!cids_.IsMonomorphic() || !cids_.HasClassId(kSmiCid)); | |
3642 Register value = locs()->in(0).reg(); | |
3643 Register temp = locs()->temp(0).reg(); | |
3644 Label is_ok; | |
3645 | |
3646 __ BranchIfSmi(value, cids_.HasClassId(kSmiCid) ? &is_ok : deopt); | |
3647 | |
3648 __ LoadClassId(temp, value); | |
3649 | |
3650 if (IsBitTest()) { | |
3651 intptr_t min = cids_.ComputeLowestCid(); | |
3652 intptr_t max = cids_.ComputeHighestCid(); | |
3653 EmitBitTest(compiler, min, max, ComputeCidMask(), deopt); | |
3654 } else { | |
3655 const intptr_t num_checks = cids_.length(); | |
3656 const bool use_near_jump = num_checks < 5; | |
3657 int bias = 0; | |
3658 for (intptr_t i = 0; i < num_checks; i++) { | |
3659 intptr_t cid_start = cids_[i].cid_start; | |
3660 intptr_t cid_end = cids_[i].cid_end; | |
3661 if (cid_start == kSmiCid && cid_end == kSmiCid) { | |
3662 continue; // We already handled Smi above. | |
3663 } | |
3664 if (cid_start == kSmiCid) cid_start++; | |
3665 if (cid_end == kSmiCid) cid_end--; | |
3666 const bool is_last = | |
3667 (i == num_checks - 1) || | |
3668 (i == num_checks - 2 && cids_[i + 1].cid_start == kSmiCid && | |
3669 cids_[i + 1].cid_end == kSmiCid); | |
3670 bias = EmitCheckCid(compiler, bias, cid_start, cid_end, is_last, &is_ok, | |
3671 deopt, use_near_jump); | |
3672 } | |
3673 } | |
3674 __ Bind(&is_ok); | |
3675 } | |
3676 #endif | |
3677 | |
3678 | |
3556 Environment* Environment::From(Zone* zone, | 3679 Environment* Environment::From(Zone* zone, |
3557 const GrowableArray<Definition*>& definitions, | 3680 const GrowableArray<Definition*>& definitions, |
3558 intptr_t fixed_parameter_count, | 3681 intptr_t fixed_parameter_count, |
3559 const ParsedFunction& parsed_function) { | 3682 const ParsedFunction& parsed_function) { |
3560 Environment* env = | 3683 Environment* env = |
3561 new (zone) Environment(definitions.length(), fixed_parameter_count, | 3684 new (zone) Environment(definitions.length(), fixed_parameter_count, |
3562 Thread::kNoDeoptId, parsed_function, NULL); | 3685 Thread::kNoDeoptId, parsed_function, NULL); |
3563 for (intptr_t i = 0; i < definitions.length(); ++i) { | 3686 for (intptr_t i = 0; i < definitions.length(); ++i) { |
3564 env->values_.Add(new (zone) Value(definitions[i])); | 3687 env->values_.Add(new (zone) Value(definitions[i])); |
3565 } | 3688 } |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4183 "native function '%s' (%" Pd " arguments) cannot be found", | 4306 "native function '%s' (%" Pd " arguments) cannot be found", |
4184 native_name().ToCString(), function().NumParameters()); | 4307 native_name().ToCString(), function().NumParameters()); |
4185 } | 4308 } |
4186 set_is_auto_scope(auto_setup_scope); | 4309 set_is_auto_scope(auto_setup_scope); |
4187 set_native_c_function(native_function); | 4310 set_native_c_function(native_function); |
4188 } | 4311 } |
4189 | 4312 |
4190 #undef __ | 4313 #undef __ |
4191 | 4314 |
4192 } // namespace dart | 4315 } // namespace dart |
OLD | NEW |