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

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

Issue 2856543002: Use off-heap data for class check instructions (Closed)
Patch Set: 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 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698