Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: runtime/vm/intermediate_language.cc

Issue 2856543002: Use off-heap data for class check instructions (Closed)
Patch Set: Feedback from Slava: rejig inheritance of CallTargets Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698