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 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 |