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 CallTargets& targets, |
153 TokenPosition token_pos) | 148 TokenPosition token_pos) |
154 : TemplateInstruction(deopt_id), | 149 : TemplateInstruction(deopt_id), |
155 unary_checks_(unary_checks), | 150 targets_(targets), |
156 cids_(unary_checks.NumberOfChecks()), | |
157 licm_hoisted_(false), | 151 licm_hoisted_(false), |
158 is_dense_switch_(IsDenseCidRange(unary_checks)), | 152 is_dense_switch_(IsDenseCidRange(targets)), |
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 = targets.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 || targets[0].cid_start != targets[0].cid_end || |
169 (unary_checks_.GetReceiverClassIdAt(0) != kSmiCid)); | 160 targets[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 targets().Equals(other_check->targets()); |
181 if (number_of_checks != other_check->unary_checks().NumberOfChecks()) { | 168 } |
182 return false; | 169 |
183 } | 170 |
184 for (intptr_t i = 0; i < number_of_checks; ++i) { | 171 bool CallTargets::AreAllChecksImmutable() const { |
Vyacheslav Egorov (Google)
2017/05/01 12:21:25
this name is very confusing. maybe rename it to Co
erikcorry
2017/05/05 15:15:51
Done.
| |
185 // TODO(fschneider): Make sure ic_data are sorted to hit more cases. | 172 for (intptr_t i = 0; i < length(); i++) { |
186 if (unary_checks().GetReceiverClassIdAt(i) != | 173 for (intptr_t cid = cid_ranges_[i].cid_start; cid <= cid_ranges_[i].cid_end; |
187 other_check->unary_checks().GetReceiverClassIdAt(i)) { | 174 cid++) { |
188 return false; | 175 if (Field::IsExternalizableCid(cid)) { |
176 return false; | |
177 } | |
189 } | 178 } |
190 } | 179 } |
191 return true; | 180 return true; |
192 } | 181 } |
193 | 182 |
194 | 183 |
195 static bool AreAllChecksImmutable(const ICData& checks) { | 184 bool CallTargets::HasReceiverClassId(intptr_t cid) const { |
Vyacheslav Egorov (Google)
2017/05/01 12:21:25
I think this is the same as HasClassId()?
erikcorry
2017/05/05 15:15:51
Merged
| |
196 const intptr_t len = checks.NumberOfChecks(); | 185 for (int i = 0; i < length(); i++) { |
197 for (intptr_t i = 0; i < len; i++) { | 186 if (cid_ranges_[i].cid_start <= cid && cid <= cid_ranges_[i].cid_end) { |
198 if (checks.IsUsedAt(i)) { | 187 return true; |
199 if (Field::IsExternalizableCid(checks.GetReceiverClassIdAt(i))) { | 188 } |
189 } | |
190 return false; | |
191 } | |
192 | |
193 | |
194 bool CallTargets::Equals(const CallTargets& other) const { | |
195 if (length() != other.length()) return false; | |
196 for (int i = 0; i < length(); i++) { | |
197 if (cid_ranges_[i].cid_start != other.cid_ranges_[i].cid_start || | |
198 cid_ranges_[i].cid_end != other.cid_ranges_[i].cid_end) { | |
199 return false; | |
200 } | |
201 const Function* target = cid_ranges_[i].target; | |
202 const Function* other_target = other.cid_ranges_[i].target; | |
203 if (target == NULL) { | |
204 if (other_target != NULL) { | |
205 return false; | |
206 } | |
207 } else { | |
208 if (other_target == NULL || target->raw() != other_target->raw()) { | |
200 return false; | 209 return false; |
201 } | 210 } |
202 } | 211 } |
203 } | 212 } |
204 return true; | 213 return true; |
205 } | 214 } |
206 | 215 |
207 | 216 |
208 EffectSet CheckClassInstr::Dependencies() const { | 217 EffectSet CheckClassInstr::Dependencies() const { |
209 // Externalization of strings via the API can change the class-id. | 218 // Externalization of strings via the API can change the class-id. |
210 return !AreAllChecksImmutable(unary_checks()) ? EffectSet::Externalization() | 219 return targets_.AreAllChecksImmutable() ? EffectSet::None() |
211 : EffectSet::None(); | 220 : EffectSet::Externalization(); |
212 } | 221 } |
213 | 222 |
214 | 223 |
215 EffectSet CheckClassIdInstr::Dependencies() const { | 224 EffectSet CheckClassIdInstr::Dependencies() const { |
216 // Externalization of strings via the API can change the class-id. | 225 // Externalization of strings via the API can change the class-id. |
217 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() | 226 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() |
218 : EffectSet::None(); | 227 : EffectSet::None(); |
219 } | 228 } |
220 | 229 |
221 | 230 |
222 bool CheckClassInstr::DeoptIfNull() const { | 231 bool CheckClassInstr::IsDeoptIfNull() const { |
223 if (!unary_checks().NumberOfChecksIs(1)) { | 232 if (!targets().IsMonomorphic()) { |
224 return false; | 233 return false; |
225 } | 234 } |
226 CompileType* in_type = value()->Type(); | 235 CompileType* in_type = value()->Type(); |
227 const intptr_t cid = unary_checks().GetCidAt(0); | 236 const intptr_t cid = targets().MonomorphicReceiverCid(); |
228 // Performance check: use CheckSmiInstr instead. | 237 // Performance check: use CheckSmiInstr instead. |
229 ASSERT(cid != kSmiCid); | 238 ASSERT(cid != kSmiCid); |
230 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); | 239 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); |
231 } | 240 } |
232 | 241 |
233 | 242 |
234 // Null object is a singleton of null-class (except for some sentinel, | 243 // Null object is a singleton of null-class (except for some sentinel, |
235 // transitional temporaries). Instead of checking against the null class only | 244 // transitional temporaries). Instead of checking against the null class only |
236 // we can check against null instance instead. | 245 // we can check against null instance instead. |
237 bool CheckClassInstr::DeoptIfNotNull() const { | 246 bool CheckClassInstr::IsDeoptIfNotNull() const { |
238 if (!unary_checks().NumberOfChecksIs(1)) { | 247 if (!targets().IsMonomorphic()) { |
239 return false; | 248 return false; |
240 } | 249 } |
241 const intptr_t cid = unary_checks().GetCidAt(0); | 250 const intptr_t cid = targets().MonomorphicReceiverCid(); |
242 return cid == kNullCid; | 251 return cid == kNullCid; |
243 } | 252 } |
244 | 253 |
245 | 254 |
246 bool CheckClassInstr::IsDenseCidRange(const ICData& unary_checks) { | 255 bool CheckClassInstr::IsDenseCidRange(const CallTargets& targets) { |
247 ASSERT(unary_checks.NumArgsTested() == 1); | 256 const intptr_t number_of_checks = targets.length(); |
257 if (number_of_checks <= 2) return false; | |
258 intptr_t min = targets.ComputeLowestCid(); | |
259 intptr_t max = targets.ComputeHighestCid(); | |
260 | |
248 // TODO(fschneider): Support smis in dense cid checks. | 261 // TODO(fschneider): Support smis in dense cid checks. |
249 if (unary_checks.GetReceiverClassIdAt(0) == kSmiCid) return false; | 262 if (min <= kSmiCid && kSmiCid <= max) return false; |
Vyacheslav Egorov (Google)
2017/05/01 12:21:25
this is not equivalent: it is fine to have kSmiCid
erikcorry
2017/05/05 15:15:51
Done.
| |
250 const intptr_t number_of_checks = unary_checks.NumberOfChecks(); | |
251 if (number_of_checks <= 2) return false; | |
252 intptr_t max = 0; | |
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; | 263 return (max - min) < kBitsPerWord; |
260 } | 264 } |
261 | 265 |
262 | 266 |
263 bool CheckClassInstr::IsDenseSwitch() const { | 267 bool CheckClassInstr::IsDenseSwitch() const { |
264 return is_dense_switch_; | 268 return is_dense_switch_; |
265 } | 269 } |
266 | 270 |
267 | 271 |
272 intptr_t CallTargets::ComputeLowestCid() const { | |
273 intptr_t min = kIntptrMax; | |
274 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | |
275 min = Utils::Minimum(min, cid_ranges_[i].cid_start); | |
276 } | |
277 return min; | |
278 } | |
279 | |
280 | |
281 intptr_t CallTargets::ComputeHighestCid() const { | |
282 intptr_t max = -1; | |
283 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | |
284 max = Utils::Maximum(max, cid_ranges_[i].cid_end); | |
285 } | |
286 return max; | |
287 } | |
288 | |
289 | |
268 intptr_t CheckClassInstr::ComputeCidMask() const { | 290 intptr_t CheckClassInstr::ComputeCidMask() const { |
269 ASSERT(IsDenseSwitch()); | 291 ASSERT(IsDenseSwitch()); |
292 intptr_t min = targets_.ComputeLowestCid(); | |
270 intptr_t mask = 0; | 293 intptr_t mask = 0; |
271 for (intptr_t i = 0; i < cids_.length(); ++i) { | 294 for (intptr_t i = 0; i < targets_.length(); ++i) { |
272 mask |= static_cast<intptr_t>(1) << (cids_[i] - cids_[0]); | 295 intptr_t cid_start = targets_[i].cid_start; |
296 intptr_t cid_end = targets_[i].cid_start; | |
297 intptr_t run = (1 << (1 + cid_end - cid_start)) - 1; | |
Vyacheslav Egorov (Google)
2017/05/01 12:21:24
I don't think this works if (cid_end - cid_start +
erikcorry
2017/05/05 15:15:51
Done.
| |
298 mask |= run << (cid_start - min); | |
273 } | 299 } |
274 return mask; | 300 return mask; |
275 } | 301 } |
276 | 302 |
277 | 303 |
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 { | 304 bool LoadFieldInstr::IsUnboxedLoad() const { |
286 return FLAG_unbox_numeric_fields && (field() != NULL) && | 305 return FLAG_unbox_numeric_fields && (field() != NULL) && |
287 FlowGraphCompiler::IsUnboxedField(*field()); | 306 FlowGraphCompiler::IsUnboxedField(*field()); |
288 } | 307 } |
289 | 308 |
290 | 309 |
291 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { | 310 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { |
292 return FLAG_unbox_numeric_fields && (field() != NULL) && | 311 return FLAG_unbox_numeric_fields && (field() != NULL) && |
293 FlowGraphCompiler::IsPotentialUnboxedField(*field()); | 312 FlowGraphCompiler::IsPotentialUnboxedField(*field()); |
294 } | 313 } |
(...skipping 2264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2559 Definition* replacement = CanonicalizeStrictCompare(this, &negated, | 2578 Definition* replacement = CanonicalizeStrictCompare(this, &negated, |
2560 /* is_branch = */ false); | 2579 /* is_branch = */ false); |
2561 if (negated && replacement->IsComparison()) { | 2580 if (negated && replacement->IsComparison()) { |
2562 ASSERT(replacement != this); | 2581 ASSERT(replacement != this); |
2563 replacement->AsComparison()->NegateComparison(); | 2582 replacement->AsComparison()->NegateComparison(); |
2564 } | 2583 } |
2565 return replacement; | 2584 return replacement; |
2566 } | 2585 } |
2567 | 2586 |
2568 | 2587 |
2588 bool CallTargets::HasClassId(intptr_t cid) const { | |
2589 for (int i = 0; i < length(); i++) { | |
2590 if (cid_ranges_[i].cid_start <= cid && cid <= cid_ranges_[i].cid_end) { | |
2591 return true; | |
2592 } | |
2593 } | |
2594 return false; | |
2595 } | |
2596 | |
2597 | |
2569 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { | 2598 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { |
2570 const intptr_t value_cid = value()->Type()->ToCid(); | 2599 const intptr_t value_cid = value()->Type()->ToCid(); |
2571 if (value_cid == kDynamicCid) { | 2600 if (value_cid == kDynamicCid) { |
2572 return this; | 2601 return this; |
2573 } | 2602 } |
2574 | 2603 |
2575 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; | 2604 return targets().HasReceiverClassId(value_cid) ? NULL : this; |
2576 } | 2605 } |
2577 | 2606 |
2578 | 2607 |
2579 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { | 2608 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { |
2580 if (value()->BindsToConstant()) { | 2609 if (value()->BindsToConstant()) { |
2581 const Object& constant_value = value()->BoundConstant(); | 2610 const Object& constant_value = value()->BoundConstant(); |
2582 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { | 2611 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { |
2583 return NULL; | 2612 return NULL; |
2584 } | 2613 } |
2585 } | 2614 } |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2748 return a->cid_start - b->cid_start; | 2777 return a->cid_start - b->cid_start; |
2749 } | 2778 } |
2750 | 2779 |
2751 | 2780 |
2752 static int OrderByFrequency(const CidRangeTarget* a, const CidRangeTarget* b) { | 2781 static int OrderByFrequency(const CidRangeTarget* a, const CidRangeTarget* b) { |
2753 // Negative if 'a' should sort before 'b'. | 2782 // Negative if 'a' should sort before 'b'. |
2754 return b->count - a->count; | 2783 return b->count - a->count; |
2755 } | 2784 } |
2756 | 2785 |
2757 | 2786 |
2758 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { | 2787 CallTargets* CallTargets::Create(Zone* zone, |
2788 const ICData& ic_data, | |
2789 int argument_number) { | |
2790 CallTargets* targets = CreateHelper(zone, ic_data, argument_number); | |
2791 targets->Sort(OrderById); | |
2792 targets->MergeIntoRanges(); | |
2793 return targets; | |
2794 } | |
2795 | |
2796 | |
2797 CallTargets* CallTargets::CreateHelper(Zone* zone, | |
2798 const ICData& ic_data, | |
2799 int argument_number) { | |
2800 ASSERT(argument_number < ic_data.NumArgsTested()); | |
2801 | |
2759 CallTargets* targets = new (zone) CallTargets(); | 2802 CallTargets* targets = new (zone) CallTargets(); |
2760 if (ic_data.NumberOfChecks() == 0) return targets; | 2803 if (ic_data.NumberOfChecks() == 0) return targets; |
2761 | 2804 |
2762 Function& dummy = Function::Handle(zone); | 2805 Function& dummy = Function::Handle(zone); |
2763 | 2806 |
2764 bool check_one_arg = ic_data.NumArgsTested() == 1; | 2807 bool check_one_arg = ic_data.NumArgsTested() == 1; |
2765 | 2808 |
2766 int checks = ic_data.NumberOfChecks(); | 2809 int checks = ic_data.NumberOfChecks(); |
2767 for (int i = 0; i < checks; i++) { | 2810 for (int i = 0; i < checks; i++) { |
2811 if (ic_data.GetCountAt(i) == 0) continue; | |
2768 intptr_t id = 0; | 2812 intptr_t id = 0; |
2769 if (check_one_arg) { | 2813 if (check_one_arg) { |
2770 ic_data.GetOneClassCheckAt(i, &id, &dummy); | 2814 ic_data.GetOneClassCheckAt(i, &id, &dummy); |
2771 } else { | 2815 } 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; | 2816 GrowableArray<intptr_t> arg_ids; |
2776 ic_data.GetCheckAt(i, &arg_ids, &dummy); | 2817 ic_data.GetCheckAt(i, &arg_ids, &dummy); |
2777 id = arg_ids[0]; | 2818 id = arg_ids[argument_number]; |
2778 } | 2819 } |
2779 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); | 2820 if (argument_number == 0) { |
2780 targets->Add(CidRangeTarget(id, id, &function, ic_data.GetCountAt(i))); | 2821 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); |
2822 targets->Add(CidRangeTarget(id, id, &function, ic_data.GetCountAt(i))); | |
2823 } else { | |
2824 targets->Add(CidRangeTarget(id, id, NULL, ic_data.GetCountAt(i))); | |
2825 } | |
2781 } | 2826 } |
2827 return targets; | |
2828 } | |
2782 | 2829 |
2830 | |
2831 CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) { | |
2832 CallTargets* targets = CreateHelper(zone, ic_data, 0); | |
2783 targets->Sort(OrderById); | 2833 targets->Sort(OrderById); |
2784 | 2834 |
2785 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); | 2835 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); |
2786 ArgumentsDescriptor args_desc(args_desc_array); | 2836 ArgumentsDescriptor args_desc(args_desc_array); |
2787 String& name = String::Handle(zone, ic_data.target_name()); | 2837 String& name = String::Handle(zone, ic_data.target_name()); |
2788 | 2838 |
2789 Function& fn = Function::Handle(zone); | 2839 Function& fn = Function::Handle(zone); |
2790 | 2840 |
2791 intptr_t length = targets->length(); | 2841 intptr_t length = targets->length(); |
2792 | 2842 |
(...skipping 11 matching lines...) Expand all Loading... | |
2804 } else { | 2854 } else { |
2805 break; | 2855 break; |
2806 } | 2856 } |
2807 } | 2857 } |
2808 } | 2858 } |
2809 // Spread class-ids to following classes where a lookup yields the same | 2859 // Spread class-ids to following classes where a lookup yields the same |
2810 // method. | 2860 // method. |
2811 for (int idx = 0; idx < length; idx++) { | 2861 for (int idx = 0; idx < length; idx++) { |
2812 int upper_limit_cid = | 2862 int upper_limit_cid = |
2813 (idx == length - 1) ? 1000000000 : targets->At(idx + 1).cid_start; | 2863 (idx == length - 1) ? 1000000000 : targets->At(idx + 1).cid_start; |
2864 ASSERT(targets->At(idx).target != NULL); | |
2814 const Function& target = *targets->At(idx).target; | 2865 const Function& target = *targets->At(idx).target; |
2815 for (int i = targets->At(idx).cid_end + 1; i < upper_limit_cid; i++) { | 2866 for (int i = targets->At(idx).cid_end + 1; i < upper_limit_cid; i++) { |
2816 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && | 2867 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && |
2817 fn.raw() == target.raw()) { | 2868 fn.raw() == target.raw()) { |
2818 (*targets)[idx].cid_end = i; | 2869 (*targets)[idx].cid_end = i; |
2819 } else { | 2870 } else { |
2820 break; | 2871 break; |
2821 } | 2872 } |
2822 } | 2873 } |
2823 } | 2874 } |
2824 // Merge adjacent class id ranges. | 2875 targets->MergeIntoRanges(); |
2825 int dest = 0; | |
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; | 2876 return targets; |
2839 } | 2877 } |
2840 | 2878 |
2841 | 2879 |
2880 void CallTargets::MergeIntoRanges() { | |
2881 // Merge adjacent class id ranges. | |
2882 int dest = 0; | |
2883 for (int src = 1; src < length(); src++) { | |
2884 if (cid_ranges_[dest].cid_end + 1 >= cid_ranges_[src].cid_start && | |
2885 (cid_ranges_[dest].target == NULL || | |
2886 cid_ranges_[dest].target->raw() == cid_ranges_[src].target->raw())) { | |
2887 cid_ranges_[dest].cid_end = cid_ranges_[src].cid_end; | |
2888 cid_ranges_[dest].count += cid_ranges_[src].count; | |
2889 } else { | |
2890 dest++; | |
2891 if (src != dest) cid_ranges_[dest] = cid_ranges_[src]; | |
2892 } | |
2893 } | |
2894 SetLength(dest + 1); | |
2895 Sort(OrderByFrequency); | |
2896 } | |
2897 | |
2898 | |
2842 // Shared code generation methods (EmitNativeCode and | 2899 // Shared code generation methods (EmitNativeCode and |
2843 // MakeLocationSummary). Only assembly code that can be shared across all | 2900 // MakeLocationSummary). Only assembly code that can be shared across all |
2844 // architectures can be used. Machine specific register allocation and code | 2901 // architectures can be used. Machine specific register allocation and code |
2845 // generation is located in intermediate_language_<arch>.cc | 2902 // generation is located in intermediate_language_<arch>.cc |
2846 | 2903 |
2847 #define __ compiler->assembler()-> | 2904 #define __ compiler->assembler()-> |
2848 | 2905 |
2849 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, | 2906 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, |
2850 bool optimizing) const { | 2907 bool optimizing) const { |
2851 UNREACHABLE(); | 2908 UNREACHABLE(); |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3289 return cid_ranges_[0].cid_start == cid_ranges_[0].cid_end; | 3346 return cid_ranges_[0].cid_start == cid_ranges_[0].cid_end; |
3290 } | 3347 } |
3291 | 3348 |
3292 | 3349 |
3293 intptr_t CallTargets::MonomorphicReceiverCid() const { | 3350 intptr_t CallTargets::MonomorphicReceiverCid() const { |
3294 ASSERT(IsMonomorphic()); | 3351 ASSERT(IsMonomorphic()); |
3295 return cid_ranges_[0].cid_start; | 3352 return cid_ranges_[0].cid_start; |
3296 } | 3353 } |
3297 | 3354 |
3298 | 3355 |
3299 Function& CallTargets::FirstTarget() const { | 3356 const Function& CallTargets::FirstTarget() const { |
3300 ASSERT(length() != 0); | 3357 ASSERT(length() != 0); |
3301 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | 3358 ASSERT(cid_ranges_[0].target->IsZoneHandle()); |
3302 return *cid_ranges_[0].target; | 3359 return *cid_ranges_[0].target; |
3303 } | 3360 } |
3304 | 3361 |
3305 | 3362 |
3306 Function& CallTargets::MostPopularTarget() const { | 3363 const Function& CallTargets::MostPopularTarget() const { |
3307 ASSERT(length() != 0); | 3364 ASSERT(length() != 0); |
3308 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | 3365 ASSERT(cid_ranges_[0].target->IsZoneHandle()); |
3309 for (int i = 1; i < length(); i++) { | 3366 for (int i = 1; i < length(); i++) { |
3310 ASSERT(cid_ranges_[i].count <= cid_ranges_[0].count); | 3367 ASSERT(cid_ranges_[i].count <= cid_ranges_[0].count); |
3311 } | 3368 } |
3312 return *cid_ranges_[0].target; | 3369 return *cid_ranges_[0].target; |
3313 } | 3370 } |
3314 | 3371 |
3315 | 3372 |
3316 intptr_t CallTargets::AggregateCallCount() const { | 3373 intptr_t CallTargets::AggregateCallCount() const { |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3546 | 3603 |
3547 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3604 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3548 #if !defined(TARGET_ARCH_DBC) | 3605 #if !defined(TARGET_ARCH_DBC) |
3549 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | 3606 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); |
3550 #else | 3607 #else |
3551 compiler->EmitDeopt(deopt_id(), deopt_reason_); | 3608 compiler->EmitDeopt(deopt_id(), deopt_reason_); |
3552 #endif | 3609 #endif |
3553 } | 3610 } |
3554 | 3611 |
3555 | 3612 |
3613 #if !defined(TARGET_ARCH_DBC) | |
3614 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
3615 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass, | |
3616 licm_hoisted_ ? ICData::kHoisted : 0); | |
3617 if (IsNullCheck()) { | |
3618 EmitNullCheck(compiler, deopt); | |
3619 return; | |
3620 } | |
3621 | |
3622 ASSERT(!targets_.IsMonomorphic() || !targets_.HasReceiverClassId(kSmiCid)); | |
3623 Register value = locs()->in(0).reg(); | |
3624 Register temp = locs()->temp(0).reg(); | |
3625 Label is_ok; | |
3626 | |
3627 __ BranchIfSmi(value, targets_.HasReceiverClassId(kSmiCid) ? &is_ok : deopt); | |
3628 | |
3629 __ LoadClassId(temp, value); | |
3630 | |
3631 if (IsDenseSwitch()) { | |
3632 intptr_t min = targets_.ComputeLowestCid(); | |
3633 intptr_t max = targets_.ComputeHighestCid(); | |
3634 EmitDenseSwitch(compiler, min, max, ComputeCidMask(), deopt); | |
3635 } else { | |
3636 const intptr_t num_checks = targets_.length(); | |
3637 const bool use_near_jump = num_checks < 5; | |
3638 int bias = 0; | |
3639 for (intptr_t i = 0; i < num_checks; i++) { | |
3640 intptr_t cid_start = targets_[i].cid_start; | |
3641 intptr_t cid_end = targets_[i].cid_end; | |
3642 if (cid_start == kSmiCid && cid_end == kSmiCid) { | |
3643 continue; // We already handled Smi above. | |
3644 } | |
3645 if (cid_start == kSmiCid) cid_start++; | |
3646 if (cid_end == kSmiCid) cid_end--; | |
3647 const bool is_last = | |
3648 (i == num_checks - 1) || | |
3649 (i == num_checks - 2 && targets_[i + 1].cid_start == kSmiCid && | |
3650 targets_[i + 1].cid_end == kSmiCid); | |
3651 bias = EmitCheckCid(compiler, bias, cid_start, cid_end, is_last, &is_ok, | |
3652 deopt, use_near_jump); | |
3653 } | |
3654 } | |
3655 __ Bind(&is_ok); | |
3656 } | |
3657 #endif | |
3658 | |
3659 | |
3556 Environment* Environment::From(Zone* zone, | 3660 Environment* Environment::From(Zone* zone, |
3557 const GrowableArray<Definition*>& definitions, | 3661 const GrowableArray<Definition*>& definitions, |
3558 intptr_t fixed_parameter_count, | 3662 intptr_t fixed_parameter_count, |
3559 const ParsedFunction& parsed_function) { | 3663 const ParsedFunction& parsed_function) { |
3560 Environment* env = | 3664 Environment* env = |
3561 new (zone) Environment(definitions.length(), fixed_parameter_count, | 3665 new (zone) Environment(definitions.length(), fixed_parameter_count, |
3562 Thread::kNoDeoptId, parsed_function, NULL); | 3666 Thread::kNoDeoptId, parsed_function, NULL); |
3563 for (intptr_t i = 0; i < definitions.length(); ++i) { | 3667 for (intptr_t i = 0; i < definitions.length(); ++i) { |
3564 env->values_.Add(new (zone) Value(definitions[i])); | 3668 env->values_.Add(new (zone) Value(definitions[i])); |
3565 } | 3669 } |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4183 "native function '%s' (%" Pd " arguments) cannot be found", | 4287 "native function '%s' (%" Pd " arguments) cannot be found", |
4184 native_name().ToCString(), function().NumParameters()); | 4288 native_name().ToCString(), function().NumParameters()); |
4185 } | 4289 } |
4186 set_is_auto_scope(auto_setup_scope); | 4290 set_is_auto_scope(auto_setup_scope); |
4187 set_native_c_function(native_function); | 4291 set_native_c_function(native_function); |
4188 } | 4292 } |
4189 | 4293 |
4190 #undef __ | 4294 #undef __ |
4191 | 4295 |
4192 } // namespace dart | 4296 } // namespace dart |
OLD | NEW |