Chromium Code Reviews| 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 |