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 26 matching lines...) Expand all Loading... |
37 two_args_smi_icd, | 37 two_args_smi_icd, |
38 true, | 38 true, |
39 "Generate special IC stubs for two args Smi operations"); | 39 "Generate special IC stubs for two args Smi operations"); |
40 DEFINE_FLAG(bool, | 40 DEFINE_FLAG(bool, |
41 unbox_numeric_fields, | 41 unbox_numeric_fields, |
42 !USING_DBC, | 42 !USING_DBC, |
43 "Support unboxed double and float32x4 fields."); | 43 "Support unboxed double and float32x4 fields."); |
44 DECLARE_FLAG(bool, eliminate_type_checks); | 44 DECLARE_FLAG(bool, eliminate_type_checks); |
45 DECLARE_FLAG(bool, support_externalizable_strings); | 45 DECLARE_FLAG(bool, support_externalizable_strings); |
46 | 46 |
47 | |
48 #if defined(DEBUG) | 47 #if defined(DEBUG) |
49 void Instruction::CheckField(const Field& field) const { | 48 void Instruction::CheckField(const Field& field) const { |
50 ASSERT(field.IsZoneHandle()); | 49 ASSERT(field.IsZoneHandle()); |
51 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); | 50 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); |
52 } | 51 } |
53 #endif // DEBUG | 52 #endif // DEBUG |
54 | 53 |
55 | |
56 Definition::Definition(intptr_t deopt_id) | 54 Definition::Definition(intptr_t deopt_id) |
57 : Instruction(deopt_id), | 55 : Instruction(deopt_id), |
58 range_(NULL), | 56 range_(NULL), |
59 type_(NULL), | 57 type_(NULL), |
60 temp_index_(-1), | 58 temp_index_(-1), |
61 ssa_temp_index_(-1), | 59 ssa_temp_index_(-1), |
62 input_use_list_(NULL), | 60 input_use_list_(NULL), |
63 env_use_list_(NULL), | 61 env_use_list_(NULL), |
64 constant_value_(NULL) {} | 62 constant_value_(NULL) {} |
65 | 63 |
66 | |
67 // A value in the constant propagation lattice. | 64 // A value in the constant propagation lattice. |
68 // - non-constant sentinel | 65 // - non-constant sentinel |
69 // - a constant (any non-sentinel value) | 66 // - a constant (any non-sentinel value) |
70 // - unknown sentinel | 67 // - unknown sentinel |
71 Object& Definition::constant_value() { | 68 Object& Definition::constant_value() { |
72 if (constant_value_ == NULL) { | 69 if (constant_value_ == NULL) { |
73 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); | 70 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); |
74 } | 71 } |
75 return *constant_value_; | 72 return *constant_value_; |
76 } | 73 } |
77 | 74 |
78 | |
79 Definition* Definition::OriginalDefinition() { | 75 Definition* Definition::OriginalDefinition() { |
80 Definition* defn = this; | 76 Definition* defn = this; |
81 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { | 77 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { |
82 if (defn->IsRedefinition()) { | 78 if (defn->IsRedefinition()) { |
83 defn = defn->AsRedefinition()->value()->definition(); | 79 defn = defn->AsRedefinition()->value()->definition(); |
84 } else { | 80 } else { |
85 defn = defn->AsAssertAssignable()->value()->definition(); | 81 defn = defn->AsAssertAssignable()->value()->definition(); |
86 } | 82 } |
87 } | 83 } |
88 return defn; | 84 return defn; |
89 } | 85 } |
90 | 86 |
91 | |
92 const ICData* Instruction::GetICData( | 87 const ICData* Instruction::GetICData( |
93 const ZoneGrowableArray<const ICData*>& ic_data_array) const { | 88 const ZoneGrowableArray<const ICData*>& ic_data_array) const { |
94 // The deopt_id can be outside the range of the IC data array for | 89 // The deopt_id can be outside the range of the IC data array for |
95 // computations added in the optimizing compiler. | 90 // computations added in the optimizing compiler. |
96 ASSERT(deopt_id_ != Thread::kNoDeoptId); | 91 ASSERT(deopt_id_ != Thread::kNoDeoptId); |
97 if (deopt_id_ < ic_data_array.length()) { | 92 if (deopt_id_ < ic_data_array.length()) { |
98 const ICData* result = ic_data_array[deopt_id_]; | 93 const ICData* result = ic_data_array[deopt_id_]; |
99 #if defined(TAG_IC_DATA) | 94 #if defined(TAG_IC_DATA) |
100 if (result != NULL) { | 95 if (result != NULL) { |
101 if (result->tag() == -1) { | 96 if (result->tag() == -1) { |
102 result->set_tag(tag()); | 97 result->set_tag(tag()); |
103 } else if (result->tag() != tag()) { | 98 } else if (result->tag() != tag()) { |
104 FATAL("ICData tag mismatch"); | 99 FATAL("ICData tag mismatch"); |
105 } | 100 } |
106 } | 101 } |
107 #endif | 102 #endif |
108 return result; | 103 return result; |
109 } | 104 } |
110 return NULL; | 105 return NULL; |
111 } | 106 } |
112 | 107 |
113 | |
114 intptr_t Instruction::Hashcode() const { | 108 intptr_t Instruction::Hashcode() const { |
115 intptr_t result = tag(); | 109 intptr_t result = tag(); |
116 for (intptr_t i = 0; i < InputCount(); ++i) { | 110 for (intptr_t i = 0; i < InputCount(); ++i) { |
117 Value* value = InputAt(i); | 111 Value* value = InputAt(i); |
118 intptr_t j = value->definition()->ssa_temp_index(); | 112 intptr_t j = value->definition()->ssa_temp_index(); |
119 result = result * 31 + j; | 113 result = result * 31 + j; |
120 } | 114 } |
121 return result; | 115 return result; |
122 } | 116 } |
123 | 117 |
124 | |
125 bool Instruction::Equals(Instruction* other) const { | 118 bool Instruction::Equals(Instruction* other) const { |
126 if (tag() != other->tag()) return false; | 119 if (tag() != other->tag()) return false; |
127 for (intptr_t i = 0; i < InputCount(); ++i) { | 120 for (intptr_t i = 0; i < InputCount(); ++i) { |
128 if (!InputAt(i)->Equals(other->InputAt(i))) return false; | 121 if (!InputAt(i)->Equals(other->InputAt(i))) return false; |
129 } | 122 } |
130 return AttributesEqual(other); | 123 return AttributesEqual(other); |
131 } | 124 } |
132 | 125 |
133 | |
134 void Instruction::Unsupported(FlowGraphCompiler* compiler) { | 126 void Instruction::Unsupported(FlowGraphCompiler* compiler) { |
135 compiler->Bailout(ToCString()); | 127 compiler->Bailout(ToCString()); |
136 UNREACHABLE(); | 128 UNREACHABLE(); |
137 } | 129 } |
138 | 130 |
139 | |
140 bool Value::Equals(Value* other) const { | 131 bool Value::Equals(Value* other) const { |
141 return definition() == other->definition(); | 132 return definition() == other->definition(); |
142 } | 133 } |
143 | 134 |
144 | |
145 static int OrderById(CidRange* const* a, CidRange* const* b) { | 135 static int OrderById(CidRange* const* a, CidRange* const* b) { |
146 // Negative if 'a' should sort before 'b'. | 136 // Negative if 'a' should sort before 'b'. |
147 ASSERT((*a)->IsSingleCid()); | 137 ASSERT((*a)->IsSingleCid()); |
148 ASSERT((*b)->IsSingleCid()); | 138 ASSERT((*b)->IsSingleCid()); |
149 return (*a)->cid_start - (*b)->cid_start; | 139 return (*a)->cid_start - (*b)->cid_start; |
150 } | 140 } |
151 | 141 |
152 | |
153 static int OrderByFrequency(CidRange* const* a, CidRange* const* b) { | 142 static int OrderByFrequency(CidRange* const* a, CidRange* const* b) { |
154 const TargetInfo* target_info_a = static_cast<const TargetInfo*>(*a); | 143 const TargetInfo* target_info_a = static_cast<const TargetInfo*>(*a); |
155 const TargetInfo* target_info_b = static_cast<const TargetInfo*>(*b); | 144 const TargetInfo* target_info_b = static_cast<const TargetInfo*>(*b); |
156 // Negative if 'a' should sort before 'b'. | 145 // Negative if 'a' should sort before 'b'. |
157 return target_info_b->count - target_info_a->count; | 146 return target_info_b->count - target_info_a->count; |
158 } | 147 } |
159 | 148 |
160 | |
161 bool Cids::ContainsExternalizableCids() const { | 149 bool Cids::ContainsExternalizableCids() const { |
162 for (intptr_t i = 0; i < length(); i++) { | 150 for (intptr_t i = 0; i < length(); i++) { |
163 for (intptr_t cid = cid_ranges_[i]->cid_start; | 151 for (intptr_t cid = cid_ranges_[i]->cid_start; |
164 cid <= cid_ranges_[i]->cid_end; cid++) { | 152 cid <= cid_ranges_[i]->cid_end; cid++) { |
165 if (Field::IsExternalizableCid(cid)) { | 153 if (Field::IsExternalizableCid(cid)) { |
166 return true; | 154 return true; |
167 } | 155 } |
168 } | 156 } |
169 } | 157 } |
170 return false; | 158 return false; |
171 } | 159 } |
172 | 160 |
173 | |
174 bool Cids::Equals(const Cids& other) const { | 161 bool Cids::Equals(const Cids& other) const { |
175 if (length() != other.length()) return false; | 162 if (length() != other.length()) return false; |
176 for (int i = 0; i < length(); i++) { | 163 for (int i = 0; i < length(); i++) { |
177 if (cid_ranges_[i]->cid_start != other.cid_ranges_[i]->cid_start || | 164 if (cid_ranges_[i]->cid_start != other.cid_ranges_[i]->cid_start || |
178 cid_ranges_[i]->cid_end != other.cid_ranges_[i]->cid_end) { | 165 cid_ranges_[i]->cid_end != other.cid_ranges_[i]->cid_end) { |
179 return false; | 166 return false; |
180 } | 167 } |
181 } | 168 } |
182 return true; | 169 return true; |
183 } | 170 } |
184 | 171 |
185 | |
186 intptr_t Cids::ComputeLowestCid() const { | 172 intptr_t Cids::ComputeLowestCid() const { |
187 intptr_t min = kIntptrMax; | 173 intptr_t min = kIntptrMax; |
188 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | 174 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { |
189 min = Utils::Minimum(min, cid_ranges_[i]->cid_start); | 175 min = Utils::Minimum(min, cid_ranges_[i]->cid_start); |
190 } | 176 } |
191 return min; | 177 return min; |
192 } | 178 } |
193 | 179 |
194 | |
195 intptr_t Cids::ComputeHighestCid() const { | 180 intptr_t Cids::ComputeHighestCid() const { |
196 intptr_t max = -1; | 181 intptr_t max = -1; |
197 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { | 182 for (intptr_t i = 0; i < cid_ranges_.length(); ++i) { |
198 max = Utils::Maximum(max, cid_ranges_[i]->cid_end); | 183 max = Utils::Maximum(max, cid_ranges_[i]->cid_end); |
199 } | 184 } |
200 return max; | 185 return max; |
201 } | 186 } |
202 | 187 |
203 | |
204 bool Cids::HasClassId(intptr_t cid) const { | 188 bool Cids::HasClassId(intptr_t cid) const { |
205 for (int i = 0; i < length(); i++) { | 189 for (int i = 0; i < length(); i++) { |
206 if (cid_ranges_[i]->Contains(cid)) { | 190 if (cid_ranges_[i]->Contains(cid)) { |
207 return true; | 191 return true; |
208 } | 192 } |
209 } | 193 } |
210 return false; | 194 return false; |
211 } | 195 } |
212 | 196 |
213 | |
214 Cids* Cids::CreateMonomorphic(Zone* zone, intptr_t cid) { | 197 Cids* Cids::CreateMonomorphic(Zone* zone, intptr_t cid) { |
215 Cids* cids = new (zone) Cids(zone); | 198 Cids* cids = new (zone) Cids(zone); |
216 cids->Add(new (zone) CidRange(cid, cid)); | 199 cids->Add(new (zone) CidRange(cid, cid)); |
217 return cids; | 200 return cids; |
218 } | 201 } |
219 | 202 |
220 | |
221 Cids* Cids::Create(Zone* zone, const ICData& ic_data, int argument_number) { | 203 Cids* Cids::Create(Zone* zone, const ICData& ic_data, int argument_number) { |
222 Cids* cids = new (zone) Cids(zone); | 204 Cids* cids = new (zone) Cids(zone); |
223 cids->CreateHelper(zone, ic_data, argument_number, | 205 cids->CreateHelper(zone, ic_data, argument_number, |
224 /* include_targets = */ false); | 206 /* include_targets = */ false); |
225 cids->Sort(OrderById); | 207 cids->Sort(OrderById); |
226 | 208 |
227 // Merge adjacent class id ranges. | 209 // Merge adjacent class id ranges. |
228 int dest = 0; | 210 int dest = 0; |
229 for (int src = 1; src < cids->length(); src++) { | 211 for (int src = 1; src < cids->length(); src++) { |
230 if (cids->cid_ranges_[dest]->cid_end + 1 >= | 212 if (cids->cid_ranges_[dest]->cid_end + 1 >= |
231 cids->cid_ranges_[src]->cid_start) { | 213 cids->cid_ranges_[src]->cid_start) { |
232 cids->cid_ranges_[dest]->cid_end = cids->cid_ranges_[src]->cid_end; | 214 cids->cid_ranges_[dest]->cid_end = cids->cid_ranges_[src]->cid_end; |
233 } else { | 215 } else { |
234 dest++; | 216 dest++; |
235 if (src != dest) cids->cid_ranges_[dest] = cids->cid_ranges_[src]; | 217 if (src != dest) cids->cid_ranges_[dest] = cids->cid_ranges_[src]; |
236 } | 218 } |
237 } | 219 } |
238 cids->SetLength(dest + 1); | 220 cids->SetLength(dest + 1); |
239 | 221 |
240 return cids; | 222 return cids; |
241 } | 223 } |
242 | 224 |
243 | |
244 void Cids::CreateHelper(Zone* zone, | 225 void Cids::CreateHelper(Zone* zone, |
245 const ICData& ic_data, | 226 const ICData& ic_data, |
246 int argument_number, | 227 int argument_number, |
247 bool include_targets) { | 228 bool include_targets) { |
248 ASSERT(argument_number < ic_data.NumArgsTested()); | 229 ASSERT(argument_number < ic_data.NumArgsTested()); |
249 | 230 |
250 if (ic_data.NumberOfChecks() == 0) return; | 231 if (ic_data.NumberOfChecks() == 0) return; |
251 | 232 |
252 Function& dummy = Function::Handle(zone); | 233 Function& dummy = Function::Handle(zone); |
253 | 234 |
(...skipping 13 matching lines...) Expand all Loading... |
267 if (include_targets) { | 248 if (include_targets) { |
268 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); | 249 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); |
269 cid_ranges_.Add(new (zone) | 250 cid_ranges_.Add(new (zone) |
270 TargetInfo(id, id, &function, ic_data.GetCountAt(i))); | 251 TargetInfo(id, id, &function, ic_data.GetCountAt(i))); |
271 } else { | 252 } else { |
272 cid_ranges_.Add(new (zone) CidRange(id, id)); | 253 cid_ranges_.Add(new (zone) CidRange(id, id)); |
273 } | 254 } |
274 } | 255 } |
275 } | 256 } |
276 | 257 |
277 | |
278 bool Cids::IsMonomorphic() const { | 258 bool Cids::IsMonomorphic() const { |
279 if (length() != 1) return false; | 259 if (length() != 1) return false; |
280 return cid_ranges_[0]->IsSingleCid(); | 260 return cid_ranges_[0]->IsSingleCid(); |
281 } | 261 } |
282 | 262 |
283 | |
284 intptr_t Cids::MonomorphicReceiverCid() const { | 263 intptr_t Cids::MonomorphicReceiverCid() const { |
285 ASSERT(IsMonomorphic()); | 264 ASSERT(IsMonomorphic()); |
286 return cid_ranges_[0]->cid_start; | 265 return cid_ranges_[0]->cid_start; |
287 } | 266 } |
288 | 267 |
289 | |
290 CheckClassInstr::CheckClassInstr(Value* value, | 268 CheckClassInstr::CheckClassInstr(Value* value, |
291 intptr_t deopt_id, | 269 intptr_t deopt_id, |
292 const Cids& cids, | 270 const Cids& cids, |
293 TokenPosition token_pos) | 271 TokenPosition token_pos) |
294 : TemplateInstruction(deopt_id), | 272 : TemplateInstruction(deopt_id), |
295 cids_(cids), | 273 cids_(cids), |
296 licm_hoisted_(false), | 274 licm_hoisted_(false), |
297 is_bit_test_(IsCompactCidRange(cids)), | 275 is_bit_test_(IsCompactCidRange(cids)), |
298 token_pos_(token_pos) { | 276 token_pos_(token_pos) { |
299 // Expected useful check data. | 277 // Expected useful check data. |
300 const intptr_t number_of_checks = cids.length(); | 278 const intptr_t number_of_checks = cids.length(); |
301 ASSERT(number_of_checks > 0); | 279 ASSERT(number_of_checks > 0); |
302 SetInputAt(0, value); | 280 SetInputAt(0, value); |
303 // Otherwise use CheckSmiInstr. | 281 // Otherwise use CheckSmiInstr. |
304 ASSERT(number_of_checks != 1 || !cids[0].IsSingleCid() || | 282 ASSERT(number_of_checks != 1 || !cids[0].IsSingleCid() || |
305 cids[0].cid_start != kSmiCid); | 283 cids[0].cid_start != kSmiCid); |
306 } | 284 } |
307 | 285 |
308 | |
309 bool CheckClassInstr::AttributesEqual(Instruction* other) const { | 286 bool CheckClassInstr::AttributesEqual(Instruction* other) const { |
310 CheckClassInstr* other_check = other->AsCheckClass(); | 287 CheckClassInstr* other_check = other->AsCheckClass(); |
311 ASSERT(other_check != NULL); | 288 ASSERT(other_check != NULL); |
312 return cids().Equals(other_check->cids()); | 289 return cids().Equals(other_check->cids()); |
313 } | 290 } |
314 | 291 |
315 | |
316 EffectSet CheckClassInstr::Dependencies() const { | 292 EffectSet CheckClassInstr::Dependencies() const { |
317 // Externalization of strings via the API can change the class-id. | 293 // Externalization of strings via the API can change the class-id. |
318 return cids_.ContainsExternalizableCids() ? EffectSet::Externalization() | 294 return cids_.ContainsExternalizableCids() ? EffectSet::Externalization() |
319 : EffectSet::None(); | 295 : EffectSet::None(); |
320 } | 296 } |
321 | 297 |
322 | |
323 EffectSet CheckClassIdInstr::Dependencies() const { | 298 EffectSet CheckClassIdInstr::Dependencies() const { |
324 // Externalization of strings via the API can change the class-id. | 299 // Externalization of strings via the API can change the class-id. |
325 for (intptr_t i = cids_.cid_start; i <= cids_.cid_end; i++) { | 300 for (intptr_t i = cids_.cid_start; i <= cids_.cid_end; i++) { |
326 if (Field::IsExternalizableCid(i)) return EffectSet::Externalization(); | 301 if (Field::IsExternalizableCid(i)) return EffectSet::Externalization(); |
327 } | 302 } |
328 return EffectSet::None(); | 303 return EffectSet::None(); |
329 } | 304 } |
330 | 305 |
331 | |
332 bool CheckClassInstr::IsDeoptIfNull() const { | 306 bool CheckClassInstr::IsDeoptIfNull() const { |
333 if (!cids().IsMonomorphic()) { | 307 if (!cids().IsMonomorphic()) { |
334 return false; | 308 return false; |
335 } | 309 } |
336 CompileType* in_type = value()->Type(); | 310 CompileType* in_type = value()->Type(); |
337 const intptr_t cid = cids().MonomorphicReceiverCid(); | 311 const intptr_t cid = cids().MonomorphicReceiverCid(); |
338 // Performance check: use CheckSmiInstr instead. | 312 // Performance check: use CheckSmiInstr instead. |
339 ASSERT(cid != kSmiCid); | 313 ASSERT(cid != kSmiCid); |
340 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); | 314 return in_type->is_nullable() && (in_type->ToNullableCid() == cid); |
341 } | 315 } |
342 | 316 |
343 | |
344 // Null object is a singleton of null-class (except for some sentinel, | 317 // Null object is a singleton of null-class (except for some sentinel, |
345 // transitional temporaries). Instead of checking against the null class only | 318 // transitional temporaries). Instead of checking against the null class only |
346 // we can check against null instance instead. | 319 // we can check against null instance instead. |
347 bool CheckClassInstr::IsDeoptIfNotNull() const { | 320 bool CheckClassInstr::IsDeoptIfNotNull() const { |
348 if (!cids().IsMonomorphic()) { | 321 if (!cids().IsMonomorphic()) { |
349 return false; | 322 return false; |
350 } | 323 } |
351 const intptr_t cid = cids().MonomorphicReceiverCid(); | 324 const intptr_t cid = cids().MonomorphicReceiverCid(); |
352 return cid == kNullCid; | 325 return cid == kNullCid; |
353 } | 326 } |
354 | 327 |
355 | |
356 bool CheckClassInstr::IsCompactCidRange(const Cids& cids) { | 328 bool CheckClassInstr::IsCompactCidRange(const Cids& cids) { |
357 const intptr_t number_of_checks = cids.length(); | 329 const intptr_t number_of_checks = cids.length(); |
358 // If there are only two checks, the extra register pressure needed for the | 330 // If there are only two checks, the extra register pressure needed for the |
359 // dense-cid-range code is not justified. | 331 // dense-cid-range code is not justified. |
360 if (number_of_checks <= 2) return false; | 332 if (number_of_checks <= 2) return false; |
361 | 333 |
362 // TODO(fschneider): Support smis in dense cid checks. | 334 // TODO(fschneider): Support smis in dense cid checks. |
363 if (cids.HasClassId(kSmiCid)) return false; | 335 if (cids.HasClassId(kSmiCid)) return false; |
364 | 336 |
365 intptr_t min = cids.ComputeLowestCid(); | 337 intptr_t min = cids.ComputeLowestCid(); |
366 intptr_t max = cids.ComputeHighestCid(); | 338 intptr_t max = cids.ComputeHighestCid(); |
367 return (max - min) < kBitsPerWord; | 339 return (max - min) < kBitsPerWord; |
368 } | 340 } |
369 | 341 |
370 | |
371 bool CheckClassInstr::IsBitTest() const { | 342 bool CheckClassInstr::IsBitTest() const { |
372 return is_bit_test_; | 343 return is_bit_test_; |
373 } | 344 } |
374 | 345 |
375 | |
376 intptr_t CheckClassInstr::ComputeCidMask() const { | 346 intptr_t CheckClassInstr::ComputeCidMask() const { |
377 ASSERT(IsBitTest()); | 347 ASSERT(IsBitTest()); |
378 intptr_t min = cids_.ComputeLowestCid(); | 348 intptr_t min = cids_.ComputeLowestCid(); |
379 intptr_t mask = 0; | 349 intptr_t mask = 0; |
380 for (intptr_t i = 0; i < cids_.length(); ++i) { | 350 for (intptr_t i = 0; i < cids_.length(); ++i) { |
381 intptr_t run; | 351 intptr_t run; |
382 uintptr_t range = 1ul + cids_[i].Extent(); | 352 uintptr_t range = 1ul + cids_[i].Extent(); |
383 if (range >= static_cast<uintptr_t>(kBitsPerWord)) { | 353 if (range >= static_cast<uintptr_t>(kBitsPerWord)) { |
384 run = -1; | 354 run = -1; |
385 } else { | 355 } else { |
386 run = (1 << range) - 1; | 356 run = (1 << range) - 1; |
387 } | 357 } |
388 mask |= run << (cids_[i].cid_start - min); | 358 mask |= run << (cids_[i].cid_start - min); |
389 } | 359 } |
390 return mask; | 360 return mask; |
391 } | 361 } |
392 | 362 |
393 | |
394 bool LoadFieldInstr::IsUnboxedLoad() const { | 363 bool LoadFieldInstr::IsUnboxedLoad() const { |
395 return FLAG_unbox_numeric_fields && (field() != NULL) && | 364 return FLAG_unbox_numeric_fields && (field() != NULL) && |
396 FlowGraphCompiler::IsUnboxedField(*field()); | 365 FlowGraphCompiler::IsUnboxedField(*field()); |
397 } | 366 } |
398 | 367 |
399 | |
400 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { | 368 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { |
401 return FLAG_unbox_numeric_fields && (field() != NULL) && | 369 return FLAG_unbox_numeric_fields && (field() != NULL) && |
402 FlowGraphCompiler::IsPotentialUnboxedField(*field()); | 370 FlowGraphCompiler::IsPotentialUnboxedField(*field()); |
403 } | 371 } |
404 | 372 |
405 | |
406 Representation LoadFieldInstr::representation() const { | 373 Representation LoadFieldInstr::representation() const { |
407 if (IsUnboxedLoad()) { | 374 if (IsUnboxedLoad()) { |
408 const intptr_t cid = field()->UnboxedFieldCid(); | 375 const intptr_t cid = field()->UnboxedFieldCid(); |
409 switch (cid) { | 376 switch (cid) { |
410 case kDoubleCid: | 377 case kDoubleCid: |
411 return kUnboxedDouble; | 378 return kUnboxedDouble; |
412 case kFloat32x4Cid: | 379 case kFloat32x4Cid: |
413 return kUnboxedFloat32x4; | 380 return kUnboxedFloat32x4; |
414 case kFloat64x2Cid: | 381 case kFloat64x2Cid: |
415 return kUnboxedFloat64x2; | 382 return kUnboxedFloat64x2; |
416 default: | 383 default: |
417 UNREACHABLE(); | 384 UNREACHABLE(); |
418 } | 385 } |
419 } | 386 } |
420 return kTagged; | 387 return kTagged; |
421 } | 388 } |
422 | 389 |
423 | |
424 bool StoreInstanceFieldInstr::IsUnboxedStore() const { | 390 bool StoreInstanceFieldInstr::IsUnboxedStore() const { |
425 return FLAG_unbox_numeric_fields && !field().IsNull() && | 391 return FLAG_unbox_numeric_fields && !field().IsNull() && |
426 FlowGraphCompiler::IsUnboxedField(field()); | 392 FlowGraphCompiler::IsUnboxedField(field()); |
427 } | 393 } |
428 | 394 |
429 | |
430 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { | 395 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { |
431 return FLAG_unbox_numeric_fields && !field().IsNull() && | 396 return FLAG_unbox_numeric_fields && !field().IsNull() && |
432 FlowGraphCompiler::IsPotentialUnboxedField(field()); | 397 FlowGraphCompiler::IsPotentialUnboxedField(field()); |
433 } | 398 } |
434 | 399 |
435 | |
436 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( | 400 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( |
437 intptr_t index) const { | 401 intptr_t index) const { |
438 ASSERT((index == 0) || (index == 1)); | 402 ASSERT((index == 0) || (index == 1)); |
439 if ((index == 1) && IsUnboxedStore()) { | 403 if ((index == 1) && IsUnboxedStore()) { |
440 const intptr_t cid = field().UnboxedFieldCid(); | 404 const intptr_t cid = field().UnboxedFieldCid(); |
441 switch (cid) { | 405 switch (cid) { |
442 case kDoubleCid: | 406 case kDoubleCid: |
443 return kUnboxedDouble; | 407 return kUnboxedDouble; |
444 case kFloat32x4Cid: | 408 case kFloat32x4Cid: |
445 return kUnboxedFloat32x4; | 409 return kUnboxedFloat32x4; |
446 case kFloat64x2Cid: | 410 case kFloat64x2Cid: |
447 return kUnboxedFloat64x2; | 411 return kUnboxedFloat64x2; |
448 default: | 412 default: |
449 UNREACHABLE(); | 413 UNREACHABLE(); |
450 } | 414 } |
451 } | 415 } |
452 return kTagged; | 416 return kTagged; |
453 } | 417 } |
454 | 418 |
455 | |
456 bool GuardFieldClassInstr::AttributesEqual(Instruction* other) const { | 419 bool GuardFieldClassInstr::AttributesEqual(Instruction* other) const { |
457 return field().raw() == other->AsGuardFieldClass()->field().raw(); | 420 return field().raw() == other->AsGuardFieldClass()->field().raw(); |
458 } | 421 } |
459 | 422 |
460 | |
461 bool GuardFieldLengthInstr::AttributesEqual(Instruction* other) const { | 423 bool GuardFieldLengthInstr::AttributesEqual(Instruction* other) const { |
462 return field().raw() == other->AsGuardFieldLength()->field().raw(); | 424 return field().raw() == other->AsGuardFieldLength()->field().raw(); |
463 } | 425 } |
464 | 426 |
465 | |
466 bool AssertAssignableInstr::AttributesEqual(Instruction* other) const { | 427 bool AssertAssignableInstr::AttributesEqual(Instruction* other) const { |
467 AssertAssignableInstr* other_assert = other->AsAssertAssignable(); | 428 AssertAssignableInstr* other_assert = other->AsAssertAssignable(); |
468 ASSERT(other_assert != NULL); | 429 ASSERT(other_assert != NULL); |
469 // This predicate has to be commutative for DominatorBasedCSE to work. | 430 // This predicate has to be commutative for DominatorBasedCSE to work. |
470 // TODO(fschneider): Eliminate more asserts with subtype relation. | 431 // TODO(fschneider): Eliminate more asserts with subtype relation. |
471 return dst_type().raw() == other_assert->dst_type().raw(); | 432 return dst_type().raw() == other_assert->dst_type().raw(); |
472 } | 433 } |
473 | 434 |
474 | |
475 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { | 435 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { |
476 StrictCompareInstr* other_op = other->AsStrictCompare(); | 436 StrictCompareInstr* other_op = other->AsStrictCompare(); |
477 ASSERT(other_op != NULL); | 437 ASSERT(other_op != NULL); |
478 return ComparisonInstr::AttributesEqual(other) && | 438 return ComparisonInstr::AttributesEqual(other) && |
479 (needs_number_check() == other_op->needs_number_check()); | 439 (needs_number_check() == other_op->needs_number_check()); |
480 } | 440 } |
481 | 441 |
482 | |
483 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { | 442 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { |
484 MathMinMaxInstr* other_op = other->AsMathMinMax(); | 443 MathMinMaxInstr* other_op = other->AsMathMinMax(); |
485 ASSERT(other_op != NULL); | 444 ASSERT(other_op != NULL); |
486 return (op_kind() == other_op->op_kind()) && | 445 return (op_kind() == other_op->op_kind()) && |
487 (result_cid() == other_op->result_cid()); | 446 (result_cid() == other_op->result_cid()); |
488 } | 447 } |
489 | 448 |
490 | |
491 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { | 449 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { |
492 ASSERT(other->tag() == tag()); | 450 ASSERT(other->tag() == tag()); |
493 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); | 451 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); |
494 return (op_kind() == other_op->op_kind()) && | 452 return (op_kind() == other_op->op_kind()) && |
495 (can_overflow() == other_op->can_overflow()) && | 453 (can_overflow() == other_op->can_overflow()) && |
496 (is_truncating() == other_op->is_truncating()); | 454 (is_truncating() == other_op->is_truncating()); |
497 } | 455 } |
498 | 456 |
499 | |
500 EffectSet LoadFieldInstr::Dependencies() const { | 457 EffectSet LoadFieldInstr::Dependencies() const { |
501 return immutable_ ? EffectSet::None() : EffectSet::All(); | 458 return immutable_ ? EffectSet::None() : EffectSet::All(); |
502 } | 459 } |
503 | 460 |
504 | |
505 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 461 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
506 LoadFieldInstr* other_load = other->AsLoadField(); | 462 LoadFieldInstr* other_load = other->AsLoadField(); |
507 ASSERT(other_load != NULL); | 463 ASSERT(other_load != NULL); |
508 if (field() != NULL) { | 464 if (field() != NULL) { |
509 return (other_load->field() != NULL) && | 465 return (other_load->field() != NULL) && |
510 (field()->raw() == other_load->field()->raw()); | 466 (field()->raw() == other_load->field()->raw()); |
511 } | 467 } |
512 return (other_load->field() == NULL) && | 468 return (other_load->field() == NULL) && |
513 (offset_in_bytes() == other_load->offset_in_bytes()); | 469 (offset_in_bytes() == other_load->offset_in_bytes()); |
514 } | 470 } |
515 | 471 |
516 | |
517 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { | 472 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { |
518 const bool is_initialized = | 473 const bool is_initialized = |
519 (field_.StaticValue() != Object::sentinel().raw()) && | 474 (field_.StaticValue() != Object::sentinel().raw()) && |
520 (field_.StaticValue() != Object::transition_sentinel().raw()); | 475 (field_.StaticValue() != Object::transition_sentinel().raw()); |
521 // When precompiling, the fact that a field is currently initialized does not | 476 // When precompiling, the fact that a field is currently initialized does not |
522 // make it safe to omit code that checks if the field needs initialization | 477 // make it safe to omit code that checks if the field needs initialization |
523 // because the field will be reset so it starts uninitialized in the process | 478 // because the field will be reset so it starts uninitialized in the process |
524 // running the precompiled code. We must be prepared to reinitialize fields. | 479 // running the precompiled code. We must be prepared to reinitialize fields. |
525 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; | 480 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; |
526 } | 481 } |
527 | 482 |
528 | |
529 EffectSet LoadStaticFieldInstr::Dependencies() const { | 483 EffectSet LoadStaticFieldInstr::Dependencies() const { |
530 return (StaticField().is_final() && !FLAG_fields_may_be_reset) | 484 return (StaticField().is_final() && !FLAG_fields_may_be_reset) |
531 ? EffectSet::None() | 485 ? EffectSet::None() |
532 : EffectSet::All(); | 486 : EffectSet::All(); |
533 } | 487 } |
534 | 488 |
535 | |
536 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { | 489 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
537 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 490 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
538 ASSERT(other_load != NULL); | 491 ASSERT(other_load != NULL); |
539 // Assert that the field is initialized. | 492 // Assert that the field is initialized. |
540 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); | 493 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); |
541 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); | 494 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); |
542 return StaticField().raw() == other_load->StaticField().raw(); | 495 return StaticField().raw() == other_load->StaticField().raw(); |
543 } | 496 } |
544 | 497 |
545 | |
546 const Field& LoadStaticFieldInstr::StaticField() const { | 498 const Field& LoadStaticFieldInstr::StaticField() const { |
547 Field& field = Field::ZoneHandle(); | 499 Field& field = Field::ZoneHandle(); |
548 field ^= field_value()->BoundConstant().raw(); | 500 field ^= field_value()->BoundConstant().raw(); |
549 return field; | 501 return field; |
550 } | 502 } |
551 | 503 |
552 | |
553 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) | 504 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) |
554 : value_(value), token_pos_(token_pos) { | 505 : value_(value), token_pos_(token_pos) { |
555 // Check that the value is not an incorrect Integer representation. | 506 // Check that the value is not an incorrect Integer representation. |
556 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); | 507 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); |
557 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); | 508 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); |
558 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); | 509 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); |
559 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 510 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
560 } | 511 } |
561 | 512 |
562 | |
563 bool ConstantInstr::AttributesEqual(Instruction* other) const { | 513 bool ConstantInstr::AttributesEqual(Instruction* other) const { |
564 ConstantInstr* other_constant = other->AsConstant(); | 514 ConstantInstr* other_constant = other->AsConstant(); |
565 ASSERT(other_constant != NULL); | 515 ASSERT(other_constant != NULL); |
566 return (value().raw() == other_constant->value().raw()); | 516 return (value().raw() == other_constant->value().raw()); |
567 } | 517 } |
568 | 518 |
569 | |
570 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value, | 519 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value, |
571 Representation representation) | 520 Representation representation) |
572 : ConstantInstr(value), | 521 : ConstantInstr(value), |
573 representation_(representation), | 522 representation_(representation), |
574 constant_address_(0) { | 523 constant_address_(0) { |
575 if (representation_ == kUnboxedDouble) { | 524 if (representation_ == kUnboxedDouble) { |
576 ASSERT(value.IsDouble()); | 525 ASSERT(value.IsDouble()); |
577 constant_address_ = | 526 constant_address_ = |
578 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); | 527 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); |
579 } | 528 } |
580 } | 529 } |
581 | 530 |
582 | |
583 // Returns true if the value represents a constant. | 531 // Returns true if the value represents a constant. |
584 bool Value::BindsToConstant() const { | 532 bool Value::BindsToConstant() const { |
585 return definition()->IsConstant(); | 533 return definition()->IsConstant(); |
586 } | 534 } |
587 | 535 |
588 | |
589 // Returns true if the value represents constant null. | 536 // Returns true if the value represents constant null. |
590 bool Value::BindsToConstantNull() const { | 537 bool Value::BindsToConstantNull() const { |
591 ConstantInstr* constant = definition()->AsConstant(); | 538 ConstantInstr* constant = definition()->AsConstant(); |
592 return (constant != NULL) && constant->value().IsNull(); | 539 return (constant != NULL) && constant->value().IsNull(); |
593 } | 540 } |
594 | 541 |
595 | |
596 const Object& Value::BoundConstant() const { | 542 const Object& Value::BoundConstant() const { |
597 ASSERT(BindsToConstant()); | 543 ASSERT(BindsToConstant()); |
598 ConstantInstr* constant = definition()->AsConstant(); | 544 ConstantInstr* constant = definition()->AsConstant(); |
599 ASSERT(constant != NULL); | 545 ASSERT(constant != NULL); |
600 return constant->value(); | 546 return constant->value(); |
601 } | 547 } |
602 | 548 |
603 | |
604 GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function, | 549 GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function, |
605 TargetEntryInstr* normal_entry, | 550 TargetEntryInstr* normal_entry, |
606 intptr_t osr_id) | 551 intptr_t osr_id) |
607 : BlockEntryInstr(0, | 552 : BlockEntryInstr(0, |
608 CatchClauseNode::kInvalidTryIndex, | 553 CatchClauseNode::kInvalidTryIndex, |
609 Thread::Current()->GetNextDeoptId()), | 554 Thread::Current()->GetNextDeoptId()), |
610 parsed_function_(parsed_function), | 555 parsed_function_(parsed_function), |
611 normal_entry_(normal_entry), | 556 normal_entry_(normal_entry), |
612 catch_entries_(), | 557 catch_entries_(), |
613 indirect_entries_(), | 558 indirect_entries_(), |
614 initial_definitions_(), | 559 initial_definitions_(), |
615 osr_id_(osr_id), | 560 osr_id_(osr_id), |
616 entry_count_(0), | 561 entry_count_(0), |
617 spill_slot_count_(0), | 562 spill_slot_count_(0), |
618 fixed_slot_count_(0) {} | 563 fixed_slot_count_(0) {} |
619 | 564 |
620 | |
621 ConstantInstr* GraphEntryInstr::constant_null() { | 565 ConstantInstr* GraphEntryInstr::constant_null() { |
622 ASSERT(initial_definitions_.length() > 0); | 566 ASSERT(initial_definitions_.length() > 0); |
623 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { | 567 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { |
624 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); | 568 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); |
625 if (defn != NULL && defn->value().IsNull()) return defn; | 569 if (defn != NULL && defn->value().IsNull()) return defn; |
626 } | 570 } |
627 UNREACHABLE(); | 571 UNREACHABLE(); |
628 return NULL; | 572 return NULL; |
629 } | 573 } |
630 | 574 |
631 | |
632 CatchBlockEntryInstr* GraphEntryInstr::GetCatchEntry(intptr_t index) { | 575 CatchBlockEntryInstr* GraphEntryInstr::GetCatchEntry(intptr_t index) { |
633 // TODO(fschneider): Sort the catch entries by catch_try_index to avoid | 576 // TODO(fschneider): Sort the catch entries by catch_try_index to avoid |
634 // searching. | 577 // searching. |
635 for (intptr_t i = 0; i < catch_entries_.length(); ++i) { | 578 for (intptr_t i = 0; i < catch_entries_.length(); ++i) { |
636 if (catch_entries_[i]->catch_try_index() == index) return catch_entries_[i]; | 579 if (catch_entries_[i]->catch_try_index() == index) return catch_entries_[i]; |
637 } | 580 } |
638 return NULL; | 581 return NULL; |
639 } | 582 } |
640 | 583 |
641 | |
642 bool GraphEntryInstr::IsCompiledForOsr() const { | 584 bool GraphEntryInstr::IsCompiledForOsr() const { |
643 return osr_id_ != Compiler::kNoOSRDeoptId; | 585 return osr_id_ != Compiler::kNoOSRDeoptId; |
644 } | 586 } |
645 | 587 |
646 | |
647 // ==== Support for visiting flow graphs. | 588 // ==== Support for visiting flow graphs. |
648 | 589 |
649 #define DEFINE_ACCEPT(ShortName) \ | 590 #define DEFINE_ACCEPT(ShortName) \ |
650 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ | 591 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ |
651 visitor->Visit##ShortName(this); \ | 592 visitor->Visit##ShortName(this); \ |
652 } | 593 } |
653 | 594 |
654 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) | 595 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) |
655 | 596 |
656 #undef DEFINE_ACCEPT | 597 #undef DEFINE_ACCEPT |
657 | 598 |
658 | |
659 void Instruction::SetEnvironment(Environment* deopt_env) { | 599 void Instruction::SetEnvironment(Environment* deopt_env) { |
660 intptr_t use_index = 0; | 600 intptr_t use_index = 0; |
661 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | 601 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { |
662 Value* use = it.CurrentValue(); | 602 Value* use = it.CurrentValue(); |
663 use->set_instruction(this); | 603 use->set_instruction(this); |
664 use->set_use_index(use_index++); | 604 use->set_use_index(use_index++); |
665 } | 605 } |
666 env_ = deopt_env; | 606 env_ = deopt_env; |
667 } | 607 } |
668 | 608 |
669 | |
670 void Instruction::RemoveEnvironment() { | 609 void Instruction::RemoveEnvironment() { |
671 for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) { | 610 for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) { |
672 it.CurrentValue()->RemoveFromUseList(); | 611 it.CurrentValue()->RemoveFromUseList(); |
673 } | 612 } |
674 env_ = NULL; | 613 env_ = NULL; |
675 } | 614 } |
676 | 615 |
677 | |
678 Instruction* Instruction::RemoveFromGraph(bool return_previous) { | 616 Instruction* Instruction::RemoveFromGraph(bool return_previous) { |
679 ASSERT(!IsBlockEntry()); | 617 ASSERT(!IsBlockEntry()); |
680 ASSERT(!IsBranch()); | 618 ASSERT(!IsBranch()); |
681 ASSERT(!IsThrow()); | 619 ASSERT(!IsThrow()); |
682 ASSERT(!IsReturn()); | 620 ASSERT(!IsReturn()); |
683 ASSERT(!IsReThrow()); | 621 ASSERT(!IsReThrow()); |
684 ASSERT(!IsGoto()); | 622 ASSERT(!IsGoto()); |
685 ASSERT(previous() != NULL); | 623 ASSERT(previous() != NULL); |
686 // We cannot assert that the instruction, if it is a definition, has no | 624 // We cannot assert that the instruction, if it is a definition, has no |
687 // uses. This function is used to remove instructions from the graph and | 625 // uses. This function is used to remove instructions from the graph and |
688 // reinsert them elsewhere (e.g., hoisting). | 626 // reinsert them elsewhere (e.g., hoisting). |
689 Instruction* prev_instr = previous(); | 627 Instruction* prev_instr = previous(); |
690 Instruction* next_instr = next(); | 628 Instruction* next_instr = next(); |
691 ASSERT(next_instr != NULL); | 629 ASSERT(next_instr != NULL); |
692 ASSERT(!next_instr->IsBlockEntry()); | 630 ASSERT(!next_instr->IsBlockEntry()); |
693 prev_instr->LinkTo(next_instr); | 631 prev_instr->LinkTo(next_instr); |
694 UnuseAllInputs(); | 632 UnuseAllInputs(); |
695 // Reset the successor and previous instruction to indicate that the | 633 // Reset the successor and previous instruction to indicate that the |
696 // instruction is removed from the graph. | 634 // instruction is removed from the graph. |
697 set_previous(NULL); | 635 set_previous(NULL); |
698 set_next(NULL); | 636 set_next(NULL); |
699 return return_previous ? prev_instr : next_instr; | 637 return return_previous ? prev_instr : next_instr; |
700 } | 638 } |
701 | 639 |
702 | |
703 void Instruction::InsertAfter(Instruction* prev) { | 640 void Instruction::InsertAfter(Instruction* prev) { |
704 ASSERT(previous_ == NULL); | 641 ASSERT(previous_ == NULL); |
705 ASSERT(next_ == NULL); | 642 ASSERT(next_ == NULL); |
706 previous_ = prev; | 643 previous_ = prev; |
707 next_ = prev->next_; | 644 next_ = prev->next_; |
708 next_->previous_ = this; | 645 next_->previous_ = this; |
709 previous_->next_ = this; | 646 previous_->next_ = this; |
710 | 647 |
711 // Update def-use chains whenever instructions are added to the graph | 648 // Update def-use chains whenever instructions are added to the graph |
712 // after initial graph construction. | 649 // after initial graph construction. |
713 for (intptr_t i = InputCount() - 1; i >= 0; --i) { | 650 for (intptr_t i = InputCount() - 1; i >= 0; --i) { |
714 Value* input = InputAt(i); | 651 Value* input = InputAt(i); |
715 input->definition()->AddInputUse(input); | 652 input->definition()->AddInputUse(input); |
716 } | 653 } |
717 } | 654 } |
718 | 655 |
719 | |
720 Instruction* Instruction::AppendInstruction(Instruction* tail) { | 656 Instruction* Instruction::AppendInstruction(Instruction* tail) { |
721 LinkTo(tail); | 657 LinkTo(tail); |
722 // Update def-use chains whenever instructions are added to the graph | 658 // Update def-use chains whenever instructions are added to the graph |
723 // after initial graph construction. | 659 // after initial graph construction. |
724 for (intptr_t i = tail->InputCount() - 1; i >= 0; --i) { | 660 for (intptr_t i = tail->InputCount() - 1; i >= 0; --i) { |
725 Value* input = tail->InputAt(i); | 661 Value* input = tail->InputAt(i); |
726 input->definition()->AddInputUse(input); | 662 input->definition()->AddInputUse(input); |
727 } | 663 } |
728 return tail; | 664 return tail; |
729 } | 665 } |
730 | 666 |
731 | |
732 BlockEntryInstr* Instruction::GetBlock() { | 667 BlockEntryInstr* Instruction::GetBlock() { |
733 // TODO(fschneider): Implement a faster way to get the block of an | 668 // TODO(fschneider): Implement a faster way to get the block of an |
734 // instruction. | 669 // instruction. |
735 ASSERT(previous() != NULL); | 670 ASSERT(previous() != NULL); |
736 Instruction* result = previous(); | 671 Instruction* result = previous(); |
737 while (!result->IsBlockEntry()) | 672 while (!result->IsBlockEntry()) |
738 result = result->previous(); | 673 result = result->previous(); |
739 return result->AsBlockEntry(); | 674 return result->AsBlockEntry(); |
740 } | 675 } |
741 | 676 |
742 | |
743 void ForwardInstructionIterator::RemoveCurrentFromGraph() { | 677 void ForwardInstructionIterator::RemoveCurrentFromGraph() { |
744 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. | 678 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. |
745 } | 679 } |
746 | 680 |
747 | |
748 void BackwardInstructionIterator::RemoveCurrentFromGraph() { | 681 void BackwardInstructionIterator::RemoveCurrentFromGraph() { |
749 current_ = current_->RemoveFromGraph(false); // Set current_ to next. | 682 current_ = current_->RemoveFromGraph(false); // Set current_ to next. |
750 } | 683 } |
751 | 684 |
752 | |
753 // Default implementation of visiting basic blocks. Can be overridden. | 685 // Default implementation of visiting basic blocks. Can be overridden. |
754 void FlowGraphVisitor::VisitBlocks() { | 686 void FlowGraphVisitor::VisitBlocks() { |
755 ASSERT(current_iterator_ == NULL); | 687 ASSERT(current_iterator_ == NULL); |
756 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 688 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
757 BlockEntryInstr* entry = block_order_[i]; | 689 BlockEntryInstr* entry = block_order_[i]; |
758 entry->Accept(this); | 690 entry->Accept(this); |
759 ForwardInstructionIterator it(entry); | 691 ForwardInstructionIterator it(entry); |
760 current_iterator_ = ⁢ | 692 current_iterator_ = ⁢ |
761 for (; !it.Done(); it.Advance()) { | 693 for (; !it.Done(); it.Advance()) { |
762 it.Current()->Accept(this); | 694 it.Current()->Accept(this); |
763 } | 695 } |
764 current_iterator_ = NULL; | 696 current_iterator_ = NULL; |
765 } | 697 } |
766 } | 698 } |
767 | 699 |
768 | |
769 bool Value::NeedsStoreBuffer() { | 700 bool Value::NeedsStoreBuffer() { |
770 if (Type()->IsNull() || (Type()->ToNullableCid() == kSmiCid) || | 701 if (Type()->IsNull() || (Type()->ToNullableCid() == kSmiCid) || |
771 (Type()->ToNullableCid() == kBoolCid)) { | 702 (Type()->ToNullableCid() == kBoolCid)) { |
772 return false; | 703 return false; |
773 } | 704 } |
774 | 705 |
775 return !BindsToConstant(); | 706 return !BindsToConstant(); |
776 } | 707 } |
777 | 708 |
778 | |
779 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { | 709 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { |
780 // Require the predecessors to be sorted by block_id to make managing | 710 // Require the predecessors to be sorted by block_id to make managing |
781 // their corresponding phi inputs simpler. | 711 // their corresponding phi inputs simpler. |
782 intptr_t pred_id = predecessor->block_id(); | 712 intptr_t pred_id = predecessor->block_id(); |
783 intptr_t index = 0; | 713 intptr_t index = 0; |
784 while ((index < predecessors_.length()) && | 714 while ((index < predecessors_.length()) && |
785 (predecessors_[index]->block_id() < pred_id)) { | 715 (predecessors_[index]->block_id() < pred_id)) { |
786 ++index; | 716 ++index; |
787 } | 717 } |
788 #if defined(DEBUG) | 718 #if defined(DEBUG) |
789 for (intptr_t i = index; i < predecessors_.length(); ++i) { | 719 for (intptr_t i = index; i < predecessors_.length(); ++i) { |
790 ASSERT(predecessors_[i]->block_id() != pred_id); | 720 ASSERT(predecessors_[i]->block_id() != pred_id); |
791 } | 721 } |
792 #endif | 722 #endif |
793 predecessors_.InsertAt(index, predecessor); | 723 predecessors_.InsertAt(index, predecessor); |
794 } | 724 } |
795 | 725 |
796 | |
797 intptr_t JoinEntryInstr::IndexOfPredecessor(BlockEntryInstr* pred) const { | 726 intptr_t JoinEntryInstr::IndexOfPredecessor(BlockEntryInstr* pred) const { |
798 for (intptr_t i = 0; i < predecessors_.length(); ++i) { | 727 for (intptr_t i = 0; i < predecessors_.length(); ++i) { |
799 if (predecessors_[i] == pred) return i; | 728 if (predecessors_[i] == pred) return i; |
800 } | 729 } |
801 return -1; | 730 return -1; |
802 } | 731 } |
803 | 732 |
804 | |
805 void Value::AddToList(Value* value, Value** list) { | 733 void Value::AddToList(Value* value, Value** list) { |
806 Value* next = *list; | 734 Value* next = *list; |
807 *list = value; | 735 *list = value; |
808 value->set_next_use(next); | 736 value->set_next_use(next); |
809 value->set_previous_use(NULL); | 737 value->set_previous_use(NULL); |
810 if (next != NULL) next->set_previous_use(value); | 738 if (next != NULL) next->set_previous_use(value); |
811 } | 739 } |
812 | 740 |
813 | |
814 void Value::RemoveFromUseList() { | 741 void Value::RemoveFromUseList() { |
815 Definition* def = definition(); | 742 Definition* def = definition(); |
816 Value* next = next_use(); | 743 Value* next = next_use(); |
817 if (this == def->input_use_list()) { | 744 if (this == def->input_use_list()) { |
818 def->set_input_use_list(next); | 745 def->set_input_use_list(next); |
819 if (next != NULL) next->set_previous_use(NULL); | 746 if (next != NULL) next->set_previous_use(NULL); |
820 } else if (this == def->env_use_list()) { | 747 } else if (this == def->env_use_list()) { |
821 def->set_env_use_list(next); | 748 def->set_env_use_list(next); |
822 if (next != NULL) next->set_previous_use(NULL); | 749 if (next != NULL) next->set_previous_use(NULL); |
823 } else { | 750 } else { |
824 Value* prev = previous_use(); | 751 Value* prev = previous_use(); |
825 prev->set_next_use(next); | 752 prev->set_next_use(next); |
826 if (next != NULL) next->set_previous_use(prev); | 753 if (next != NULL) next->set_previous_use(prev); |
827 } | 754 } |
828 | 755 |
829 set_previous_use(NULL); | 756 set_previous_use(NULL); |
830 set_next_use(NULL); | 757 set_next_use(NULL); |
831 } | 758 } |
832 | 759 |
833 | |
834 // True if the definition has a single input use and is used only in | 760 // True if the definition has a single input use and is used only in |
835 // environments at the same instruction as that input use. | 761 // environments at the same instruction as that input use. |
836 bool Definition::HasOnlyUse(Value* use) const { | 762 bool Definition::HasOnlyUse(Value* use) const { |
837 if (!HasOnlyInputUse(use)) { | 763 if (!HasOnlyInputUse(use)) { |
838 return false; | 764 return false; |
839 } | 765 } |
840 | 766 |
841 Instruction* target = use->instruction(); | 767 Instruction* target = use->instruction(); |
842 for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) { | 768 for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) { |
843 if (it.Current()->instruction() != target) return false; | 769 if (it.Current()->instruction() != target) return false; |
844 } | 770 } |
845 return true; | 771 return true; |
846 } | 772 } |
847 | 773 |
848 | |
849 bool Definition::HasOnlyInputUse(Value* use) const { | 774 bool Definition::HasOnlyInputUse(Value* use) const { |
850 return (input_use_list() == use) && (use->next_use() == NULL); | 775 return (input_use_list() == use) && (use->next_use() == NULL); |
851 } | 776 } |
852 | 777 |
853 | |
854 void Definition::ReplaceUsesWith(Definition* other) { | 778 void Definition::ReplaceUsesWith(Definition* other) { |
855 ASSERT(other != NULL); | 779 ASSERT(other != NULL); |
856 ASSERT(this != other); | 780 ASSERT(this != other); |
857 | 781 |
858 Value* current = NULL; | 782 Value* current = NULL; |
859 Value* next = input_use_list(); | 783 Value* next = input_use_list(); |
860 if (next != NULL) { | 784 if (next != NULL) { |
861 // Change all the definitions. | 785 // Change all the definitions. |
862 while (next != NULL) { | 786 while (next != NULL) { |
863 current = next; | 787 current = next; |
(...skipping 19 matching lines...) Expand all Loading... |
883 next = current->next_use(); | 807 next = current->next_use(); |
884 } | 808 } |
885 next = other->env_use_list(); | 809 next = other->env_use_list(); |
886 current->set_next_use(next); | 810 current->set_next_use(next); |
887 if (next != NULL) next->set_previous_use(current); | 811 if (next != NULL) next->set_previous_use(current); |
888 other->set_env_use_list(env_use_list()); | 812 other->set_env_use_list(env_use_list()); |
889 set_env_use_list(NULL); | 813 set_env_use_list(NULL); |
890 } | 814 } |
891 } | 815 } |
892 | 816 |
893 | |
894 void Instruction::UnuseAllInputs() { | 817 void Instruction::UnuseAllInputs() { |
895 for (intptr_t i = InputCount() - 1; i >= 0; --i) { | 818 for (intptr_t i = InputCount() - 1; i >= 0; --i) { |
896 InputAt(i)->RemoveFromUseList(); | 819 InputAt(i)->RemoveFromUseList(); |
897 } | 820 } |
898 for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) { | 821 for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) { |
899 it.CurrentValue()->RemoveFromUseList(); | 822 it.CurrentValue()->RemoveFromUseList(); |
900 } | 823 } |
901 } | 824 } |
902 | 825 |
903 | |
904 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, | 826 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, |
905 Definition* call, | 827 Definition* call, |
906 Definition* result) { | 828 Definition* result) { |
907 ASSERT(call->env() != NULL); | 829 ASSERT(call->env() != NULL); |
908 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); | 830 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); |
909 call->env()->DeepCopyAfterTo( | 831 call->env()->DeepCopyAfterTo( |
910 flow_graph->zone(), this, call->ArgumentCount(), | 832 flow_graph->zone(), this, call->ArgumentCount(), |
911 flow_graph->constant_dead(), | 833 flow_graph->constant_dead(), |
912 result != NULL ? result : flow_graph->constant_dead()); | 834 result != NULL ? result : flow_graph->constant_dead()); |
913 env()->set_deopt_id(deopt_id_); | 835 env()->set_deopt_id(deopt_id_); |
914 } | 836 } |
915 | 837 |
916 | |
917 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { | 838 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { |
918 ASSERT(other->env() != NULL); | 839 ASSERT(other->env() != NULL); |
919 CopyDeoptIdFrom(*other); | 840 CopyDeoptIdFrom(*other); |
920 other->env()->DeepCopyTo(zone, this); | 841 other->env()->DeepCopyTo(zone, this); |
921 env()->set_deopt_id(deopt_id_); | 842 env()->set_deopt_id(deopt_id_); |
922 } | 843 } |
923 | 844 |
924 | |
925 void BranchInstr::InheritDeoptTarget(Zone* zone, Instruction* other) { | 845 void BranchInstr::InheritDeoptTarget(Zone* zone, Instruction* other) { |
926 ASSERT(env() == NULL); | 846 ASSERT(env() == NULL); |
927 Instruction::InheritDeoptTarget(zone, other); | 847 Instruction::InheritDeoptTarget(zone, other); |
928 comparison()->SetDeoptId(*this); | 848 comparison()->SetDeoptId(*this); |
929 } | 849 } |
930 | 850 |
931 | |
932 bool Instruction::IsDominatedBy(Instruction* dom) { | 851 bool Instruction::IsDominatedBy(Instruction* dom) { |
933 BlockEntryInstr* block = GetBlock(); | 852 BlockEntryInstr* block = GetBlock(); |
934 BlockEntryInstr* dom_block = dom->GetBlock(); | 853 BlockEntryInstr* dom_block = dom->GetBlock(); |
935 | 854 |
936 if (dom->IsPhi()) { | 855 if (dom->IsPhi()) { |
937 dom = dom_block; | 856 dom = dom_block; |
938 } | 857 } |
939 | 858 |
940 if (block == dom_block) { | 859 if (block == dom_block) { |
941 if ((block == dom) || (this == block->last_instruction())) { | 860 if ((block == dom) || (this == block->last_instruction())) { |
942 return true; | 861 return true; |
943 } | 862 } |
944 | 863 |
945 if (IsPhi()) { | 864 if (IsPhi()) { |
946 return false; | 865 return false; |
947 } | 866 } |
948 | 867 |
949 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) { | 868 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) { |
950 if (curr == this) return true; | 869 if (curr == this) return true; |
951 } | 870 } |
952 | 871 |
953 return false; | 872 return false; |
954 } | 873 } |
955 | 874 |
956 return dom_block->Dominates(block); | 875 return dom_block->Dominates(block); |
957 } | 876 } |
958 | 877 |
959 | |
960 bool Instruction::HasUnmatchedInputRepresentations() const { | 878 bool Instruction::HasUnmatchedInputRepresentations() const { |
961 for (intptr_t i = 0; i < InputCount(); i++) { | 879 for (intptr_t i = 0; i < InputCount(); i++) { |
962 Definition* input = InputAt(i)->definition(); | 880 Definition* input = InputAt(i)->definition(); |
963 if (RequiredInputRepresentation(i) != input->representation()) { | 881 if (RequiredInputRepresentation(i) != input->representation()) { |
964 return true; | 882 return true; |
965 } | 883 } |
966 } | 884 } |
967 | 885 |
968 return false; | 886 return false; |
969 } | 887 } |
970 | 888 |
971 | |
972 void Definition::ReplaceWith(Definition* other, | 889 void Definition::ReplaceWith(Definition* other, |
973 ForwardInstructionIterator* iterator) { | 890 ForwardInstructionIterator* iterator) { |
974 // Record other's input uses. | 891 // Record other's input uses. |
975 for (intptr_t i = other->InputCount() - 1; i >= 0; --i) { | 892 for (intptr_t i = other->InputCount() - 1; i >= 0; --i) { |
976 Value* input = other->InputAt(i); | 893 Value* input = other->InputAt(i); |
977 input->definition()->AddInputUse(input); | 894 input->definition()->AddInputUse(input); |
978 } | 895 } |
979 // Take other's environment from this definition. | 896 // Take other's environment from this definition. |
980 ASSERT(other->env() == NULL); | 897 ASSERT(other->env() == NULL); |
981 other->SetEnvironment(env()); | 898 other->SetEnvironment(env()); |
(...skipping 14 matching lines...) Expand all Loading... |
996 iterator->RemoveCurrentFromGraph(); | 913 iterator->RemoveCurrentFromGraph(); |
997 } else { | 914 } else { |
998 other->LinkTo(next()); | 915 other->LinkTo(next()); |
999 // Remove this definition's input uses. | 916 // Remove this definition's input uses. |
1000 UnuseAllInputs(); | 917 UnuseAllInputs(); |
1001 } | 918 } |
1002 set_previous(NULL); | 919 set_previous(NULL); |
1003 set_next(NULL); | 920 set_next(NULL); |
1004 } | 921 } |
1005 | 922 |
1006 | |
1007 void BranchInstr::SetComparison(ComparisonInstr* new_comparison) { | 923 void BranchInstr::SetComparison(ComparisonInstr* new_comparison) { |
1008 for (intptr_t i = new_comparison->InputCount() - 1; i >= 0; --i) { | 924 for (intptr_t i = new_comparison->InputCount() - 1; i >= 0; --i) { |
1009 Value* input = new_comparison->InputAt(i); | 925 Value* input = new_comparison->InputAt(i); |
1010 input->definition()->AddInputUse(input); | 926 input->definition()->AddInputUse(input); |
1011 input->set_instruction(this); | 927 input->set_instruction(this); |
1012 } | 928 } |
1013 // There should be no need to copy or unuse an environment. | 929 // There should be no need to copy or unuse an environment. |
1014 ASSERT(comparison()->env() == NULL); | 930 ASSERT(comparison()->env() == NULL); |
1015 ASSERT(new_comparison->env() == NULL); | 931 ASSERT(new_comparison->env() == NULL); |
1016 // Remove the current comparison's input uses. | 932 // Remove the current comparison's input uses. |
1017 comparison()->UnuseAllInputs(); | 933 comparison()->UnuseAllInputs(); |
1018 ASSERT(!new_comparison->HasUses()); | 934 ASSERT(!new_comparison->HasUses()); |
1019 comparison_ = new_comparison; | 935 comparison_ = new_comparison; |
1020 } | 936 } |
1021 | 937 |
1022 | |
1023 // ==== Postorder graph traversal. | 938 // ==== Postorder graph traversal. |
1024 static bool IsMarked(BlockEntryInstr* block, | 939 static bool IsMarked(BlockEntryInstr* block, |
1025 GrowableArray<BlockEntryInstr*>* preorder) { | 940 GrowableArray<BlockEntryInstr*>* preorder) { |
1026 // Detect that a block has been visited as part of the current | 941 // Detect that a block has been visited as part of the current |
1027 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 942 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
1028 // will be 'marked' by (1) having a preorder number in the range of the | 943 // will be 'marked' by (1) having a preorder number in the range of the |
1029 // preorder array and (2) being in the preorder array at that index. | 944 // preorder array and (2) being in the preorder array at that index. |
1030 intptr_t i = block->preorder_number(); | 945 intptr_t i = block->preorder_number(); |
1031 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); | 946 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); |
1032 } | 947 } |
1033 | 948 |
1034 | |
1035 // Base class implementation used for JoinEntry and TargetEntry. | 949 // Base class implementation used for JoinEntry and TargetEntry. |
1036 bool BlockEntryInstr::DiscoverBlock(BlockEntryInstr* predecessor, | 950 bool BlockEntryInstr::DiscoverBlock(BlockEntryInstr* predecessor, |
1037 GrowableArray<BlockEntryInstr*>* preorder, | 951 GrowableArray<BlockEntryInstr*>* preorder, |
1038 GrowableArray<intptr_t>* parent) { | 952 GrowableArray<intptr_t>* parent) { |
1039 // If this block has a predecessor (i.e., is not the graph entry) we can | 953 // If this block has a predecessor (i.e., is not the graph entry) we can |
1040 // assume the preorder array is non-empty. | 954 // assume the preorder array is non-empty. |
1041 ASSERT((predecessor == NULL) || !preorder->is_empty()); | 955 ASSERT((predecessor == NULL) || !preorder->is_empty()); |
1042 // Blocks with a single predecessor cannot have been reached before. | 956 // Blocks with a single predecessor cannot have been reached before. |
1043 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); | 957 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); |
1044 | 958 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 Instruction* last = this; | 990 Instruction* last = this; |
1077 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { | 991 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { |
1078 last = it.Current(); | 992 last = it.Current(); |
1079 } | 993 } |
1080 set_last_instruction(last); | 994 set_last_instruction(last); |
1081 if (last->IsGoto()) last->AsGoto()->set_block(this); | 995 if (last->IsGoto()) last->AsGoto()->set_block(this); |
1082 | 996 |
1083 return true; | 997 return true; |
1084 } | 998 } |
1085 | 999 |
1086 | |
1087 void GraphEntryInstr::RelinkToOsrEntry(Zone* zone, intptr_t max_block_id) { | 1000 void GraphEntryInstr::RelinkToOsrEntry(Zone* zone, intptr_t max_block_id) { |
1088 ASSERT(osr_id_ != Compiler::kNoOSRDeoptId); | 1001 ASSERT(osr_id_ != Compiler::kNoOSRDeoptId); |
1089 BitVector* block_marks = new (zone) BitVector(zone, max_block_id + 1); | 1002 BitVector* block_marks = new (zone) BitVector(zone, max_block_id + 1); |
1090 bool found = FindOsrEntryAndRelink(this, /*parent=*/NULL, block_marks); | 1003 bool found = FindOsrEntryAndRelink(this, /*parent=*/NULL, block_marks); |
1091 ASSERT(found); | 1004 ASSERT(found); |
1092 } | 1005 } |
1093 | 1006 |
1094 | |
1095 bool BlockEntryInstr::FindOsrEntryAndRelink(GraphEntryInstr* graph_entry, | 1007 bool BlockEntryInstr::FindOsrEntryAndRelink(GraphEntryInstr* graph_entry, |
1096 Instruction* parent, | 1008 Instruction* parent, |
1097 BitVector* block_marks) { | 1009 BitVector* block_marks) { |
1098 const intptr_t osr_id = graph_entry->osr_id(); | 1010 const intptr_t osr_id = graph_entry->osr_id(); |
1099 | 1011 |
1100 // Search for the instruction with the OSR id. Use a depth first search | 1012 // Search for the instruction with the OSR id. Use a depth first search |
1101 // because basic blocks have not been discovered yet. Prune unreachable | 1013 // because basic blocks have not been discovered yet. Prune unreachable |
1102 // blocks by replacing the normal entry with a jump to the block | 1014 // blocks by replacing the normal entry with a jump to the block |
1103 // containing the OSR entry point. | 1015 // containing the OSR entry point. |
1104 | 1016 |
(...skipping 26 matching lines...) Expand all Loading... |
1131 // Recursively search the successors. | 1043 // Recursively search the successors. |
1132 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { | 1044 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { |
1133 if (instr->SuccessorAt(i)->FindOsrEntryAndRelink(graph_entry, instr, | 1045 if (instr->SuccessorAt(i)->FindOsrEntryAndRelink(graph_entry, instr, |
1134 block_marks)) { | 1046 block_marks)) { |
1135 return true; | 1047 return true; |
1136 } | 1048 } |
1137 } | 1049 } |
1138 return false; | 1050 return false; |
1139 } | 1051 } |
1140 | 1052 |
1141 | |
1142 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { | 1053 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { |
1143 // TODO(fschneider): Make this faster by e.g. storing dominators for each | 1054 // TODO(fschneider): Make this faster by e.g. storing dominators for each |
1144 // block while computing the dominator tree. | 1055 // block while computing the dominator tree. |
1145 ASSERT(other != NULL); | 1056 ASSERT(other != NULL); |
1146 BlockEntryInstr* current = other; | 1057 BlockEntryInstr* current = other; |
1147 while (current != NULL && current != this) { | 1058 while (current != NULL && current != this) { |
1148 current = current->dominator(); | 1059 current = current->dominator(); |
1149 } | 1060 } |
1150 return current == this; | 1061 return current == this; |
1151 } | 1062 } |
1152 | 1063 |
1153 | |
1154 BlockEntryInstr* BlockEntryInstr::ImmediateDominator() const { | 1064 BlockEntryInstr* BlockEntryInstr::ImmediateDominator() const { |
1155 Instruction* last = dominator()->last_instruction(); | 1065 Instruction* last = dominator()->last_instruction(); |
1156 if ((last->SuccessorCount() == 1) && (last->SuccessorAt(0) == this)) { | 1066 if ((last->SuccessorCount() == 1) && (last->SuccessorAt(0) == this)) { |
1157 return dominator(); | 1067 return dominator(); |
1158 } | 1068 } |
1159 return NULL; | 1069 return NULL; |
1160 } | 1070 } |
1161 | 1071 |
1162 | |
1163 // Helper to mutate the graph during inlining. This block should be | 1072 // Helper to mutate the graph during inlining. This block should be |
1164 // replaced with new_block as a predecessor of all of this block's | 1073 // replaced with new_block as a predecessor of all of this block's |
1165 // successors. For each successor, the predecessors will be reordered | 1074 // successors. For each successor, the predecessors will be reordered |
1166 // to preserve block-order sorting of the predecessors as well as the | 1075 // to preserve block-order sorting of the predecessors as well as the |
1167 // phis if the successor is a join. | 1076 // phis if the successor is a join. |
1168 void BlockEntryInstr::ReplaceAsPredecessorWith(BlockEntryInstr* new_block) { | 1077 void BlockEntryInstr::ReplaceAsPredecessorWith(BlockEntryInstr* new_block) { |
1169 // Set the last instruction of the new block to that of the old block. | 1078 // Set the last instruction of the new block to that of the old block. |
1170 Instruction* last = last_instruction(); | 1079 Instruction* last = last_instruction(); |
1171 new_block->set_last_instruction(last); | 1080 new_block->set_last_instruction(last); |
1172 // For each successor, update the predecessors. | 1081 // For each successor, update the predecessors. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1216 for (intptr_t use_idx = old_index; use_idx != new_index; | 1125 for (intptr_t use_idx = old_index; use_idx != new_index; |
1217 use_idx += step) { | 1126 use_idx += step) { |
1218 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); | 1127 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); |
1219 } | 1128 } |
1220 // Write the predecessor use. | 1129 // Write the predecessor use. |
1221 phi->SetInputAt(new_index, pred_use); | 1130 phi->SetInputAt(new_index, pred_use); |
1222 } | 1131 } |
1223 } | 1132 } |
1224 } | 1133 } |
1225 | 1134 |
1226 | |
1227 void BlockEntryInstr::ClearAllInstructions() { | 1135 void BlockEntryInstr::ClearAllInstructions() { |
1228 JoinEntryInstr* join = this->AsJoinEntry(); | 1136 JoinEntryInstr* join = this->AsJoinEntry(); |
1229 if (join != NULL) { | 1137 if (join != NULL) { |
1230 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 1138 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
1231 it.Current()->UnuseAllInputs(); | 1139 it.Current()->UnuseAllInputs(); |
1232 } | 1140 } |
1233 } | 1141 } |
1234 UnuseAllInputs(); | 1142 UnuseAllInputs(); |
1235 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { | 1143 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { |
1236 it.Current()->UnuseAllInputs(); | 1144 it.Current()->UnuseAllInputs(); |
1237 } | 1145 } |
1238 } | 1146 } |
1239 | 1147 |
1240 | |
1241 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { | 1148 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { |
1242 // Lazily initialize the array of phis. | 1149 // Lazily initialize the array of phis. |
1243 // Currently, phis are stored in a sparse array that holds the phi | 1150 // Currently, phis are stored in a sparse array that holds the phi |
1244 // for variable with index i at position i. | 1151 // for variable with index i at position i. |
1245 // TODO(fschneider): Store phis in a more compact way. | 1152 // TODO(fschneider): Store phis in a more compact way. |
1246 if (phis_ == NULL) { | 1153 if (phis_ == NULL) { |
1247 phis_ = new ZoneGrowableArray<PhiInstr*>(var_count); | 1154 phis_ = new ZoneGrowableArray<PhiInstr*>(var_count); |
1248 for (intptr_t i = 0; i < var_count; i++) { | 1155 for (intptr_t i = 0; i < var_count; i++) { |
1249 phis_->Add(NULL); | 1156 phis_->Add(NULL); |
1250 } | 1157 } |
1251 } | 1158 } |
1252 ASSERT((*phis_)[var_index] == NULL); | 1159 ASSERT((*phis_)[var_index] == NULL); |
1253 return (*phis_)[var_index] = new PhiInstr(this, PredecessorCount()); | 1160 return (*phis_)[var_index] = new PhiInstr(this, PredecessorCount()); |
1254 } | 1161 } |
1255 | 1162 |
1256 | |
1257 void JoinEntryInstr::InsertPhi(PhiInstr* phi) { | 1163 void JoinEntryInstr::InsertPhi(PhiInstr* phi) { |
1258 // Lazily initialize the array of phis. | 1164 // Lazily initialize the array of phis. |
1259 if (phis_ == NULL) { | 1165 if (phis_ == NULL) { |
1260 phis_ = new ZoneGrowableArray<PhiInstr*>(1); | 1166 phis_ = new ZoneGrowableArray<PhiInstr*>(1); |
1261 } | 1167 } |
1262 phis_->Add(phi); | 1168 phis_->Add(phi); |
1263 } | 1169 } |
1264 | 1170 |
1265 void JoinEntryInstr::RemovePhi(PhiInstr* phi) { | 1171 void JoinEntryInstr::RemovePhi(PhiInstr* phi) { |
1266 ASSERT(phis_ != NULL); | 1172 ASSERT(phis_ != NULL); |
(...skipping 24 matching lines...) Expand all Loading... |
1291 } | 1197 } |
1292 } | 1198 } |
1293 } | 1199 } |
1294 if (to_index == 0) { | 1200 if (to_index == 0) { |
1295 phis_ = NULL; | 1201 phis_ = NULL; |
1296 } else { | 1202 } else { |
1297 phis_->TruncateTo(to_index); | 1203 phis_->TruncateTo(to_index); |
1298 } | 1204 } |
1299 } | 1205 } |
1300 | 1206 |
1301 | |
1302 intptr_t Instruction::SuccessorCount() const { | 1207 intptr_t Instruction::SuccessorCount() const { |
1303 return 0; | 1208 return 0; |
1304 } | 1209 } |
1305 | 1210 |
1306 | |
1307 BlockEntryInstr* Instruction::SuccessorAt(intptr_t index) const { | 1211 BlockEntryInstr* Instruction::SuccessorAt(intptr_t index) const { |
1308 // Called only if index is in range. Only control-transfer instructions | 1212 // Called only if index is in range. Only control-transfer instructions |
1309 // can have non-zero successor counts and they override this function. | 1213 // can have non-zero successor counts and they override this function. |
1310 UNREACHABLE(); | 1214 UNREACHABLE(); |
1311 return NULL; | 1215 return NULL; |
1312 } | 1216 } |
1313 | 1217 |
1314 | |
1315 intptr_t GraphEntryInstr::SuccessorCount() const { | 1218 intptr_t GraphEntryInstr::SuccessorCount() const { |
1316 return 1 + catch_entries_.length(); | 1219 return 1 + catch_entries_.length(); |
1317 } | 1220 } |
1318 | 1221 |
1319 | |
1320 BlockEntryInstr* GraphEntryInstr::SuccessorAt(intptr_t index) const { | 1222 BlockEntryInstr* GraphEntryInstr::SuccessorAt(intptr_t index) const { |
1321 if (index == 0) return normal_entry_; | 1223 if (index == 0) return normal_entry_; |
1322 return catch_entries_[index - 1]; | 1224 return catch_entries_[index - 1]; |
1323 } | 1225 } |
1324 | 1226 |
1325 | |
1326 intptr_t BranchInstr::SuccessorCount() const { | 1227 intptr_t BranchInstr::SuccessorCount() const { |
1327 return 2; | 1228 return 2; |
1328 } | 1229 } |
1329 | 1230 |
1330 | |
1331 BlockEntryInstr* BranchInstr::SuccessorAt(intptr_t index) const { | 1231 BlockEntryInstr* BranchInstr::SuccessorAt(intptr_t index) const { |
1332 if (index == 0) return true_successor_; | 1232 if (index == 0) return true_successor_; |
1333 if (index == 1) return false_successor_; | 1233 if (index == 1) return false_successor_; |
1334 UNREACHABLE(); | 1234 UNREACHABLE(); |
1335 return NULL; | 1235 return NULL; |
1336 } | 1236 } |
1337 | 1237 |
1338 | |
1339 intptr_t GotoInstr::SuccessorCount() const { | 1238 intptr_t GotoInstr::SuccessorCount() const { |
1340 return 1; | 1239 return 1; |
1341 } | 1240 } |
1342 | 1241 |
1343 | |
1344 BlockEntryInstr* GotoInstr::SuccessorAt(intptr_t index) const { | 1242 BlockEntryInstr* GotoInstr::SuccessorAt(intptr_t index) const { |
1345 ASSERT(index == 0); | 1243 ASSERT(index == 0); |
1346 return successor(); | 1244 return successor(); |
1347 } | 1245 } |
1348 | 1246 |
1349 | |
1350 void Instruction::Goto(JoinEntryInstr* entry) { | 1247 void Instruction::Goto(JoinEntryInstr* entry) { |
1351 LinkTo(new GotoInstr(entry, Thread::Current()->GetNextDeoptId())); | 1248 LinkTo(new GotoInstr(entry, Thread::Current()->GetNextDeoptId())); |
1352 } | 1249 } |
1353 | 1250 |
1354 | |
1355 bool UnboxedIntConverterInstr::ComputeCanDeoptimize() const { | 1251 bool UnboxedIntConverterInstr::ComputeCanDeoptimize() const { |
1356 return (to() == kUnboxedInt32) && !is_truncating() && | 1252 return (to() == kUnboxedInt32) && !is_truncating() && |
1357 !RangeUtils::Fits(value()->definition()->range(), | 1253 !RangeUtils::Fits(value()->definition()->range(), |
1358 RangeBoundary::kRangeBoundaryInt32); | 1254 RangeBoundary::kRangeBoundaryInt32); |
1359 } | 1255 } |
1360 | 1256 |
1361 | |
1362 bool UnboxInt32Instr::ComputeCanDeoptimize() const { | 1257 bool UnboxInt32Instr::ComputeCanDeoptimize() const { |
1363 const intptr_t value_cid = value()->Type()->ToCid(); | 1258 const intptr_t value_cid = value()->Type()->ToCid(); |
1364 if (value_cid == kSmiCid) { | 1259 if (value_cid == kSmiCid) { |
1365 return (kSmiBits > 32) && !is_truncating() && | 1260 return (kSmiBits > 32) && !is_truncating() && |
1366 !RangeUtils::Fits(value()->definition()->range(), | 1261 !RangeUtils::Fits(value()->definition()->range(), |
1367 RangeBoundary::kRangeBoundaryInt32); | 1262 RangeBoundary::kRangeBoundaryInt32); |
1368 } else if (value_cid == kMintCid) { | 1263 } else if (value_cid == kMintCid) { |
1369 return !is_truncating() && | 1264 return !is_truncating() && |
1370 !RangeUtils::Fits(value()->definition()->range(), | 1265 !RangeUtils::Fits(value()->definition()->range(), |
1371 RangeBoundary::kRangeBoundaryInt32); | 1266 RangeBoundary::kRangeBoundaryInt32); |
1372 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { | 1267 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { |
1373 return false; | 1268 return false; |
1374 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { | 1269 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { |
1375 // Note: we don't support truncation of Bigint values. | 1270 // Note: we don't support truncation of Bigint values. |
1376 return !RangeUtils::Fits(value()->definition()->range(), | 1271 return !RangeUtils::Fits(value()->definition()->range(), |
1377 RangeBoundary::kRangeBoundaryInt32); | 1272 RangeBoundary::kRangeBoundaryInt32); |
1378 } else { | 1273 } else { |
1379 return true; | 1274 return true; |
1380 } | 1275 } |
1381 } | 1276 } |
1382 | 1277 |
1383 | |
1384 bool UnboxUint32Instr::ComputeCanDeoptimize() const { | 1278 bool UnboxUint32Instr::ComputeCanDeoptimize() const { |
1385 ASSERT(is_truncating()); | 1279 ASSERT(is_truncating()); |
1386 if ((value()->Type()->ToCid() == kSmiCid) || | 1280 if ((value()->Type()->ToCid() == kSmiCid) || |
1387 (value()->Type()->ToCid() == kMintCid)) { | 1281 (value()->Type()->ToCid() == kMintCid)) { |
1388 return false; | 1282 return false; |
1389 } | 1283 } |
1390 // Check input value's range. | 1284 // Check input value's range. |
1391 Range* value_range = value()->definition()->range(); | 1285 Range* value_range = value()->definition()->range(); |
1392 return !RangeUtils::Fits(value_range, RangeBoundary::kRangeBoundaryInt64); | 1286 return !RangeUtils::Fits(value_range, RangeBoundary::kRangeBoundaryInt64); |
1393 } | 1287 } |
1394 | 1288 |
1395 | |
1396 bool BinaryInt32OpInstr::ComputeCanDeoptimize() const { | 1289 bool BinaryInt32OpInstr::ComputeCanDeoptimize() const { |
1397 switch (op_kind()) { | 1290 switch (op_kind()) { |
1398 case Token::kBIT_AND: | 1291 case Token::kBIT_AND: |
1399 case Token::kBIT_OR: | 1292 case Token::kBIT_OR: |
1400 case Token::kBIT_XOR: | 1293 case Token::kBIT_XOR: |
1401 return false; | 1294 return false; |
1402 | 1295 |
1403 case Token::kSHR: | 1296 case Token::kSHR: |
1404 return false; | 1297 return false; |
1405 | 1298 |
1406 case Token::kSHL: | 1299 case Token::kSHL: |
1407 // Currently only shifts by in range constant are supported, see | 1300 // Currently only shifts by in range constant are supported, see |
1408 // BinaryInt32OpInstr::IsSupported. | 1301 // BinaryInt32OpInstr::IsSupported. |
1409 return can_overflow(); | 1302 return can_overflow(); |
1410 | 1303 |
1411 case Token::kMOD: { | 1304 case Token::kMOD: { |
1412 UNREACHABLE(); | 1305 UNREACHABLE(); |
1413 } | 1306 } |
1414 | 1307 |
1415 default: | 1308 default: |
1416 return can_overflow(); | 1309 return can_overflow(); |
1417 } | 1310 } |
1418 } | 1311 } |
1419 | 1312 |
1420 | |
1421 bool BinarySmiOpInstr::ComputeCanDeoptimize() const { | 1313 bool BinarySmiOpInstr::ComputeCanDeoptimize() const { |
1422 switch (op_kind()) { | 1314 switch (op_kind()) { |
1423 case Token::kBIT_AND: | 1315 case Token::kBIT_AND: |
1424 case Token::kBIT_OR: | 1316 case Token::kBIT_OR: |
1425 case Token::kBIT_XOR: | 1317 case Token::kBIT_XOR: |
1426 return false; | 1318 return false; |
1427 | 1319 |
1428 case Token::kSHR: | 1320 case Token::kSHR: |
1429 return !RangeUtils::IsPositive(right_range()); | 1321 return !RangeUtils::IsPositive(right_range()); |
1430 | 1322 |
1431 case Token::kSHL: | 1323 case Token::kSHL: |
1432 return can_overflow() || !RangeUtils::IsPositive(right_range()); | 1324 return can_overflow() || !RangeUtils::IsPositive(right_range()); |
1433 | 1325 |
1434 case Token::kMOD: | 1326 case Token::kMOD: |
1435 return RangeUtils::CanBeZero(right_range()); | 1327 return RangeUtils::CanBeZero(right_range()); |
1436 | 1328 |
1437 default: | 1329 default: |
1438 return can_overflow(); | 1330 return can_overflow(); |
1439 } | 1331 } |
1440 } | 1332 } |
1441 | 1333 |
1442 | |
1443 bool ShiftMintOpInstr::IsShiftCountInRange() const { | 1334 bool ShiftMintOpInstr::IsShiftCountInRange() const { |
1444 return RangeUtils::IsWithin(shift_range(), 0, kMintShiftCountLimit); | 1335 return RangeUtils::IsWithin(shift_range(), 0, kMintShiftCountLimit); |
1445 } | 1336 } |
1446 | 1337 |
1447 | |
1448 bool BinaryIntegerOpInstr::RightIsPowerOfTwoConstant() const { | 1338 bool BinaryIntegerOpInstr::RightIsPowerOfTwoConstant() const { |
1449 if (!right()->definition()->IsConstant()) return false; | 1339 if (!right()->definition()->IsConstant()) return false; |
1450 const Object& constant = right()->definition()->AsConstant()->value(); | 1340 const Object& constant = right()->definition()->AsConstant()->value(); |
1451 if (!constant.IsSmi()) return false; | 1341 if (!constant.IsSmi()) return false; |
1452 const intptr_t int_value = Smi::Cast(constant).Value(); | 1342 const intptr_t int_value = Smi::Cast(constant).Value(); |
1453 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 1343 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
1454 } | 1344 } |
1455 | 1345 |
1456 | |
1457 static intptr_t RepresentationBits(Representation r) { | 1346 static intptr_t RepresentationBits(Representation r) { |
1458 switch (r) { | 1347 switch (r) { |
1459 case kTagged: | 1348 case kTagged: |
1460 return kBitsPerWord - 1; | 1349 return kBitsPerWord - 1; |
1461 case kUnboxedInt32: | 1350 case kUnboxedInt32: |
1462 case kUnboxedUint32: | 1351 case kUnboxedUint32: |
1463 return 32; | 1352 return 32; |
1464 case kUnboxedMint: | 1353 case kUnboxedMint: |
1465 return 64; | 1354 return 64; |
1466 default: | 1355 default: |
1467 UNREACHABLE(); | 1356 UNREACHABLE(); |
1468 return 0; | 1357 return 0; |
1469 } | 1358 } |
1470 } | 1359 } |
1471 | 1360 |
1472 | |
1473 static int64_t RepresentationMask(Representation r) { | 1361 static int64_t RepresentationMask(Representation r) { |
1474 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> | 1362 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> |
1475 (64 - RepresentationBits(r))); | 1363 (64 - RepresentationBits(r))); |
1476 } | 1364 } |
1477 | 1365 |
1478 | |
1479 static bool ToIntegerConstant(Value* value, int64_t* result) { | 1366 static bool ToIntegerConstant(Value* value, int64_t* result) { |
1480 if (!value->BindsToConstant()) { | 1367 if (!value->BindsToConstant()) { |
1481 UnboxInstr* unbox = value->definition()->AsUnbox(); | 1368 UnboxInstr* unbox = value->definition()->AsUnbox(); |
1482 if (unbox != NULL) { | 1369 if (unbox != NULL) { |
1483 switch (unbox->representation()) { | 1370 switch (unbox->representation()) { |
1484 case kUnboxedDouble: | 1371 case kUnboxedDouble: |
1485 case kUnboxedMint: | 1372 case kUnboxedMint: |
1486 return ToIntegerConstant(unbox->value(), result); | 1373 return ToIntegerConstant(unbox->value(), result); |
1487 | 1374 |
1488 case kUnboxedUint32: | 1375 case kUnboxedUint32: |
(...skipping 22 matching lines...) Expand all Loading... |
1511 *result = Smi::Cast(constant).Value(); | 1398 *result = Smi::Cast(constant).Value(); |
1512 return true; | 1399 return true; |
1513 } else if (constant.IsMint()) { | 1400 } else if (constant.IsMint()) { |
1514 *result = Mint::Cast(constant).value(); | 1401 *result = Mint::Cast(constant).value(); |
1515 return true; | 1402 return true; |
1516 } | 1403 } |
1517 | 1404 |
1518 return false; | 1405 return false; |
1519 } | 1406 } |
1520 | 1407 |
1521 | |
1522 static Definition* CanonicalizeCommutativeDoubleArithmetic(Token::Kind op, | 1408 static Definition* CanonicalizeCommutativeDoubleArithmetic(Token::Kind op, |
1523 Value* left, | 1409 Value* left, |
1524 Value* right) { | 1410 Value* right) { |
1525 int64_t left_value; | 1411 int64_t left_value; |
1526 if (!ToIntegerConstant(left, &left_value)) { | 1412 if (!ToIntegerConstant(left, &left_value)) { |
1527 return NULL; | 1413 return NULL; |
1528 } | 1414 } |
1529 | 1415 |
1530 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because | 1416 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because |
1531 // 0.0 * NaN is NaN not 0.0. | 1417 // 0.0 * NaN is NaN not 0.0. |
(...skipping 12 matching lines...) Expand all Loading... |
1544 } | 1430 } |
1545 } | 1431 } |
1546 break; | 1432 break; |
1547 default: | 1433 default: |
1548 break; | 1434 break; |
1549 } | 1435 } |
1550 | 1436 |
1551 return NULL; | 1437 return NULL; |
1552 } | 1438 } |
1553 | 1439 |
1554 | |
1555 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { | 1440 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { |
1556 #ifdef DEBUG | 1441 #ifdef DEBUG |
1557 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or | 1442 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or |
1558 // Phis introduce by load forwarding. | 1443 // Phis introduce by load forwarding. |
1559 ASSERT(env_use_list() == NULL); | 1444 ASSERT(env_use_list() == NULL); |
1560 for (Value* use = input_use_list(); use != NULL; use = use->next_use()) { | 1445 for (Value* use = input_use_list(); use != NULL; use = use->next_use()) { |
1561 ASSERT(use->instruction()->IsPhi() || | 1446 ASSERT(use->instruction()->IsPhi() || |
1562 use->instruction()->IsFloatToDouble() || | 1447 use->instruction()->IsFloatToDouble() || |
1563 (use->instruction()->IsStoreIndexed() && | 1448 (use->instruction()->IsStoreIndexed() && |
1564 (use->instruction()->AsStoreIndexed()->class_id() == | 1449 (use->instruction()->AsStoreIndexed()->class_id() == |
1565 kTypedDataFloat32ArrayCid))); | 1450 kTypedDataFloat32ArrayCid))); |
1566 } | 1451 } |
1567 #endif | 1452 #endif |
1568 if (!HasUses()) return NULL; | 1453 if (!HasUses()) return NULL; |
1569 if (value()->definition()->IsFloatToDouble()) { | 1454 if (value()->definition()->IsFloatToDouble()) { |
1570 // F2D(D2F(v)) == v. | 1455 // F2D(D2F(v)) == v. |
1571 return value()->definition()->AsFloatToDouble()->value()->definition(); | 1456 return value()->definition()->AsFloatToDouble()->value()->definition(); |
1572 } | 1457 } |
1573 return this; | 1458 return this; |
1574 } | 1459 } |
1575 | 1460 |
1576 | |
1577 Definition* FloatToDoubleInstr::Canonicalize(FlowGraph* flow_graph) { | 1461 Definition* FloatToDoubleInstr::Canonicalize(FlowGraph* flow_graph) { |
1578 return HasUses() ? this : NULL; | 1462 return HasUses() ? this : NULL; |
1579 } | 1463 } |
1580 | 1464 |
1581 | |
1582 Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1465 Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1583 if (!HasUses()) return NULL; | 1466 if (!HasUses()) return NULL; |
1584 | 1467 |
1585 Definition* result = NULL; | 1468 Definition* result = NULL; |
1586 | 1469 |
1587 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), left(), right()); | 1470 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), left(), right()); |
1588 if (result != NULL) { | 1471 if (result != NULL) { |
1589 return result; | 1472 return result; |
1590 } | 1473 } |
1591 | 1474 |
1592 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); | 1475 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); |
1593 if (result != NULL) { | 1476 if (result != NULL) { |
1594 return result; | 1477 return result; |
1595 } | 1478 } |
1596 | 1479 |
1597 if ((op_kind() == Token::kMUL) && | 1480 if ((op_kind() == Token::kMUL) && |
1598 (left()->definition() == right()->definition())) { | 1481 (left()->definition() == right()->definition())) { |
1599 MathUnaryInstr* math_unary = new MathUnaryInstr( | 1482 MathUnaryInstr* math_unary = new MathUnaryInstr( |
1600 MathUnaryInstr::kDoubleSquare, new Value(left()->definition()), | 1483 MathUnaryInstr::kDoubleSquare, new Value(left()->definition()), |
1601 DeoptimizationTarget()); | 1484 DeoptimizationTarget()); |
1602 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); | 1485 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); |
1603 return math_unary; | 1486 return math_unary; |
1604 } | 1487 } |
1605 | 1488 |
1606 return this; | 1489 return this; |
1607 } | 1490 } |
1608 | 1491 |
1609 | |
1610 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1492 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1611 return HasUses() ? this : NULL; | 1493 return HasUses() ? this : NULL; |
1612 } | 1494 } |
1613 | 1495 |
1614 | |
1615 static bool IsCommutative(Token::Kind op) { | 1496 static bool IsCommutative(Token::Kind op) { |
1616 switch (op) { | 1497 switch (op) { |
1617 case Token::kMUL: | 1498 case Token::kMUL: |
1618 case Token::kADD: | 1499 case Token::kADD: |
1619 case Token::kBIT_AND: | 1500 case Token::kBIT_AND: |
1620 case Token::kBIT_OR: | 1501 case Token::kBIT_OR: |
1621 case Token::kBIT_XOR: | 1502 case Token::kBIT_XOR: |
1622 return true; | 1503 return true; |
1623 default: | 1504 default: |
1624 return false; | 1505 return false; |
1625 } | 1506 } |
1626 } | 1507 } |
1627 | 1508 |
1628 | |
1629 UnaryIntegerOpInstr* UnaryIntegerOpInstr::Make(Representation representation, | 1509 UnaryIntegerOpInstr* UnaryIntegerOpInstr::Make(Representation representation, |
1630 Token::Kind op_kind, | 1510 Token::Kind op_kind, |
1631 Value* value, | 1511 Value* value, |
1632 intptr_t deopt_id, | 1512 intptr_t deopt_id, |
1633 Range* range) { | 1513 Range* range) { |
1634 UnaryIntegerOpInstr* op = NULL; | 1514 UnaryIntegerOpInstr* op = NULL; |
1635 switch (representation) { | 1515 switch (representation) { |
1636 case kTagged: | 1516 case kTagged: |
1637 op = new UnarySmiOpInstr(op_kind, value, deopt_id); | 1517 op = new UnarySmiOpInstr(op_kind, value, deopt_id); |
1638 break; | 1518 break; |
(...skipping 15 matching lines...) Expand all Loading... |
1654 } | 1534 } |
1655 | 1535 |
1656 if (!Range::IsUnknown(range)) { | 1536 if (!Range::IsUnknown(range)) { |
1657 op->set_range(*range); | 1537 op->set_range(*range); |
1658 } | 1538 } |
1659 | 1539 |
1660 ASSERT(op->representation() == representation); | 1540 ASSERT(op->representation() == representation); |
1661 return op; | 1541 return op; |
1662 } | 1542 } |
1663 | 1543 |
1664 | |
1665 BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(Representation representation, | 1544 BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(Representation representation, |
1666 Token::Kind op_kind, | 1545 Token::Kind op_kind, |
1667 Value* left, | 1546 Value* left, |
1668 Value* right, | 1547 Value* right, |
1669 intptr_t deopt_id, | 1548 intptr_t deopt_id, |
1670 bool can_overflow, | 1549 bool can_overflow, |
1671 bool is_truncating, | 1550 bool is_truncating, |
1672 Range* range) { | 1551 Range* range) { |
1673 BinaryIntegerOpInstr* op = NULL; | 1552 BinaryIntegerOpInstr* op = NULL; |
1674 switch (representation) { | 1553 switch (representation) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1706 | 1585 |
1707 op->set_can_overflow(can_overflow); | 1586 op->set_can_overflow(can_overflow); |
1708 if (is_truncating) { | 1587 if (is_truncating) { |
1709 op->mark_truncating(); | 1588 op->mark_truncating(); |
1710 } | 1589 } |
1711 | 1590 |
1712 ASSERT(op->representation() == representation); | 1591 ASSERT(op->representation() == representation); |
1713 return op; | 1592 return op; |
1714 } | 1593 } |
1715 | 1594 |
1716 | |
1717 static bool IsRepresentable(const Integer& value, Representation rep) { | 1595 static bool IsRepresentable(const Integer& value, Representation rep) { |
1718 switch (rep) { | 1596 switch (rep) { |
1719 case kTagged: // Smi case. | 1597 case kTagged: // Smi case. |
1720 return value.IsSmi(); | 1598 return value.IsSmi(); |
1721 | 1599 |
1722 case kUnboxedInt32: | 1600 case kUnboxedInt32: |
1723 if (value.IsSmi() || value.IsMint()) { | 1601 if (value.IsSmi() || value.IsMint()) { |
1724 return Utils::IsInt(32, value.AsInt64Value()); | 1602 return Utils::IsInt(32, value.AsInt64Value()); |
1725 } | 1603 } |
1726 return false; | 1604 return false; |
1727 | 1605 |
1728 case kUnboxedMint: | 1606 case kUnboxedMint: |
1729 return value.IsSmi() || value.IsMint(); | 1607 return value.IsSmi() || value.IsMint(); |
1730 | 1608 |
1731 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. | 1609 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. |
1732 default: | 1610 default: |
1733 UNREACHABLE(); | 1611 UNREACHABLE(); |
1734 } | 1612 } |
1735 | 1613 |
1736 return false; | 1614 return false; |
1737 } | 1615 } |
1738 | 1616 |
1739 | |
1740 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { | 1617 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { |
1741 Thread* thread = Thread::Current(); | 1618 Thread* thread = Thread::Current(); |
1742 Zone* zone = thread->zone(); | 1619 Zone* zone = thread->zone(); |
1743 Integer& result = Integer::Handle(zone); | 1620 Integer& result = Integer::Handle(zone); |
1744 | 1621 |
1745 switch (op_kind()) { | 1622 switch (op_kind()) { |
1746 case Token::kNEGATE: | 1623 case Token::kNEGATE: |
1747 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(zone, Smi::New(-1)), | 1624 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(zone, Smi::New(-1)), |
1748 Heap::kOld); | 1625 Heap::kOld); |
1749 break; | 1626 break; |
(...skipping 17 matching lines...) Expand all Loading... |
1767 // larger than something this operation can produce. We could have | 1644 // larger than something this operation can produce. We could have |
1768 // specialized instructions that use this value under this assumption. | 1645 // specialized instructions that use this value under this assumption. |
1769 return Integer::null(); | 1646 return Integer::null(); |
1770 } | 1647 } |
1771 result ^= result.CheckAndCanonicalize(thread, NULL); | 1648 result ^= result.CheckAndCanonicalize(thread, NULL); |
1772 } | 1649 } |
1773 | 1650 |
1774 return result.raw(); | 1651 return result.raw(); |
1775 } | 1652 } |
1776 | 1653 |
1777 | |
1778 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, | 1654 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, |
1779 const Integer& right) const { | 1655 const Integer& right) const { |
1780 Thread* thread = Thread::Current(); | 1656 Thread* thread = Thread::Current(); |
1781 Zone* zone = thread->zone(); | 1657 Zone* zone = thread->zone(); |
1782 Integer& result = Integer::Handle(zone); | 1658 Integer& result = Integer::Handle(zone); |
1783 | 1659 |
1784 switch (op_kind()) { | 1660 switch (op_kind()) { |
1785 case Token::kTRUNCDIV: | 1661 case Token::kTRUNCDIV: |
1786 case Token::kMOD: | 1662 case Token::kMOD: |
1787 // Check right value for zero. | 1663 // Check right value for zero. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1826 // larger than something this operation can produce. We could have | 1702 // larger than something this operation can produce. We could have |
1827 // specialized instructions that use this value under this assumption. | 1703 // specialized instructions that use this value under this assumption. |
1828 return Integer::null(); | 1704 return Integer::null(); |
1829 } | 1705 } |
1830 result ^= result.CheckAndCanonicalize(thread, NULL); | 1706 result ^= result.CheckAndCanonicalize(thread, NULL); |
1831 } | 1707 } |
1832 | 1708 |
1833 return result.raw(); | 1709 return result.raw(); |
1834 } | 1710 } |
1835 | 1711 |
1836 | |
1837 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, | 1712 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, |
1838 const Integer& result) { | 1713 const Integer& result) { |
1839 Definition* result_defn = flow_graph->GetConstant(result); | 1714 Definition* result_defn = flow_graph->GetConstant(result); |
1840 if (representation() != kTagged) { | 1715 if (representation() != kTagged) { |
1841 result_defn = UnboxInstr::Create(representation(), new Value(result_defn), | 1716 result_defn = UnboxInstr::Create(representation(), new Value(result_defn), |
1842 GetDeoptId()); | 1717 GetDeoptId()); |
1843 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); | 1718 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); |
1844 } | 1719 } |
1845 return result_defn; | 1720 return result_defn; |
1846 } | 1721 } |
1847 | 1722 |
1848 | |
1849 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1723 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1850 if ((left()->Type()->ToCid() == kSmiCid) && | 1724 if ((left()->Type()->ToCid() == kSmiCid) && |
1851 (right()->Type()->ToCid() == kSmiCid)) { | 1725 (right()->Type()->ToCid() == kSmiCid)) { |
1852 Definition* replacement = NULL; | 1726 Definition* replacement = NULL; |
1853 // Operations that can't deoptimize are specialized here: These include | 1727 // Operations that can't deoptimize are specialized here: These include |
1854 // bit-wise operators and comparisons. Other arithmetic operations can | 1728 // bit-wise operators and comparisons. Other arithmetic operations can |
1855 // overflow or divide by 0 and can't be specialized unless we have extra | 1729 // overflow or divide by 0 and can't be specialized unless we have extra |
1856 // range information. | 1730 // range information. |
1857 switch (op_kind()) { | 1731 switch (op_kind()) { |
1858 case Token::kBIT_AND: | 1732 case Token::kBIT_AND: |
1859 case Token::kBIT_OR: | 1733 case Token::kBIT_OR: |
1860 case Token::kBIT_XOR: | 1734 case Token::kBIT_XOR: |
1861 replacement = new BinarySmiOpInstr( | 1735 replacement = new BinarySmiOpInstr( |
1862 op_kind(), new Value(left()->definition()), | 1736 op_kind(), new Value(left()->definition()), |
1863 new Value(right()->definition()), Thread::kNoDeoptId); | 1737 new Value(right()->definition()), Thread::kNoDeoptId); |
1864 default: | 1738 default: |
1865 break; | 1739 break; |
1866 } | 1740 } |
1867 if (replacement != NULL) { | 1741 if (replacement != NULL) { |
1868 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1742 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
1869 return replacement; | 1743 return replacement; |
1870 } | 1744 } |
1871 } | 1745 } |
1872 return this; | 1746 return this; |
1873 } | 1747 } |
1874 | 1748 |
1875 | |
1876 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(Value* left, | 1749 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(Value* left, |
1877 Value* right) { | 1750 Value* right) { |
1878 UNREACHABLE(); | 1751 UNREACHABLE(); |
1879 return NULL; | 1752 return NULL; |
1880 } | 1753 } |
1881 | 1754 |
1882 | |
1883 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { | 1755 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { |
1884 if ((left()->Type()->ToCid() == kSmiCid) && | 1756 if ((left()->Type()->ToCid() == kSmiCid) && |
1885 (right()->Type()->ToCid() == kSmiCid)) { | 1757 (right()->Type()->ToCid() == kSmiCid)) { |
1886 Definition* replacement = NULL; | 1758 Definition* replacement = NULL; |
1887 if (Token::IsRelationalOperator(kind())) { | 1759 if (Token::IsRelationalOperator(kind())) { |
1888 replacement = new RelationalOpInstr( | 1760 replacement = new RelationalOpInstr( |
1889 token_pos(), kind(), new Value(left()->definition()), | 1761 token_pos(), kind(), new Value(left()->definition()), |
1890 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); | 1762 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
1891 } else if (Token::IsEqualityOperator(kind())) { | 1763 } else if (Token::IsEqualityOperator(kind())) { |
1892 replacement = new EqualityCompareInstr( | 1764 replacement = new EqualityCompareInstr( |
1893 token_pos(), kind(), new Value(left()->definition()), | 1765 token_pos(), kind(), new Value(left()->definition()), |
1894 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); | 1766 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
1895 } | 1767 } |
1896 if (replacement != NULL) { | 1768 if (replacement != NULL) { |
1897 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1769 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
1898 return replacement; | 1770 return replacement; |
1899 } | 1771 } |
1900 } | 1772 } |
1901 return this; | 1773 return this; |
1902 } | 1774 } |
1903 | 1775 |
1904 | |
1905 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1776 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1906 // If both operands are constants evaluate this expression. Might | 1777 // If both operands are constants evaluate this expression. Might |
1907 // occur due to load forwarding after constant propagation pass | 1778 // occur due to load forwarding after constant propagation pass |
1908 // have already been run. | 1779 // have already been run. |
1909 if (left()->BindsToConstant() && left()->BoundConstant().IsInteger() && | 1780 if (left()->BindsToConstant() && left()->BoundConstant().IsInteger() && |
1910 right()->BindsToConstant() && right()->BoundConstant().IsInteger()) { | 1781 right()->BindsToConstant() && right()->BoundConstant().IsInteger()) { |
1911 const Integer& result = | 1782 const Integer& result = |
1912 Integer::Handle(Evaluate(Integer::Cast(left()->BoundConstant()), | 1783 Integer::Handle(Evaluate(Integer::Cast(left()->BoundConstant()), |
1913 Integer::Cast(right()->BoundConstant()))); | 1784 Integer::Cast(right()->BoundConstant()))); |
1914 if (!result.IsNull()) { | 1785 if (!result.IsNull()) { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2044 break; | 1915 break; |
2045 } | 1916 } |
2046 | 1917 |
2047 default: | 1918 default: |
2048 break; | 1919 break; |
2049 } | 1920 } |
2050 | 1921 |
2051 return this; | 1922 return this; |
2052 } | 1923 } |
2053 | 1924 |
2054 | |
2055 // Optimizations that eliminate or simplify individual instructions. | 1925 // Optimizations that eliminate or simplify individual instructions. |
2056 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { | 1926 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { |
2057 return this; | 1927 return this; |
2058 } | 1928 } |
2059 | 1929 |
2060 | |
2061 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { | 1930 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { |
2062 return this; | 1931 return this; |
2063 } | 1932 } |
2064 | 1933 |
2065 | |
2066 Definition* RedefinitionInstr::Canonicalize(FlowGraph* flow_graph) { | 1934 Definition* RedefinitionInstr::Canonicalize(FlowGraph* flow_graph) { |
2067 if (!HasUses()) { | 1935 if (!HasUses()) { |
2068 return NULL; | 1936 return NULL; |
2069 } | 1937 } |
2070 if ((constrained_type() != NULL) && | 1938 if ((constrained_type() != NULL) && |
2071 Type()->IsEqualTo(value()->definition()->Type())) { | 1939 Type()->IsEqualTo(value()->definition()->Type())) { |
2072 return value()->definition(); | 1940 return value()->definition(); |
2073 } | 1941 } |
2074 return this; | 1942 return this; |
2075 } | 1943 } |
2076 | 1944 |
2077 | |
2078 Instruction* CheckStackOverflowInstr::Canonicalize(FlowGraph* flow_graph) { | 1945 Instruction* CheckStackOverflowInstr::Canonicalize(FlowGraph* flow_graph) { |
2079 switch (kind_) { | 1946 switch (kind_) { |
2080 case kOsrAndPreemption: | 1947 case kOsrAndPreemption: |
2081 return this; | 1948 return this; |
2082 case kOsrOnly: | 1949 case kOsrOnly: |
2083 // Don't need OSR entries in the optimized code. | 1950 // Don't need OSR entries in the optimized code. |
2084 return NULL; | 1951 return NULL; |
2085 } | 1952 } |
2086 | 1953 |
2087 // Switch above exhausts all possibilities but some compilers can't figure | 1954 // Switch above exhausts all possibilities but some compilers can't figure |
2088 // it out. | 1955 // it out. |
2089 UNREACHABLE(); | 1956 UNREACHABLE(); |
2090 return this; | 1957 return this; |
2091 } | 1958 } |
2092 | 1959 |
2093 | |
2094 bool LoadFieldInstr::IsImmutableLengthLoad() const { | 1960 bool LoadFieldInstr::IsImmutableLengthLoad() const { |
2095 switch (recognized_kind()) { | 1961 switch (recognized_kind()) { |
2096 case MethodRecognizer::kObjectArrayLength: | 1962 case MethodRecognizer::kObjectArrayLength: |
2097 case MethodRecognizer::kImmutableArrayLength: | 1963 case MethodRecognizer::kImmutableArrayLength: |
2098 case MethodRecognizer::kTypedDataLength: | 1964 case MethodRecognizer::kTypedDataLength: |
2099 case MethodRecognizer::kStringBaseLength: | 1965 case MethodRecognizer::kStringBaseLength: |
2100 return true; | 1966 return true; |
2101 default: | 1967 default: |
2102 return false; | 1968 return false; |
2103 } | 1969 } |
2104 } | 1970 } |
2105 | 1971 |
2106 | |
2107 MethodRecognizer::Kind LoadFieldInstr::RecognizedKindFromArrayCid( | 1972 MethodRecognizer::Kind LoadFieldInstr::RecognizedKindFromArrayCid( |
2108 intptr_t cid) { | 1973 intptr_t cid) { |
2109 if (RawObject::IsTypedDataClassId(cid) || | 1974 if (RawObject::IsTypedDataClassId(cid) || |
2110 RawObject::IsExternalTypedDataClassId(cid)) { | 1975 RawObject::IsExternalTypedDataClassId(cid)) { |
2111 return MethodRecognizer::kTypedDataLength; | 1976 return MethodRecognizer::kTypedDataLength; |
2112 } | 1977 } |
2113 switch (cid) { | 1978 switch (cid) { |
2114 case kArrayCid: | 1979 case kArrayCid: |
2115 return MethodRecognizer::kObjectArrayLength; | 1980 return MethodRecognizer::kObjectArrayLength; |
2116 case kImmutableArrayCid: | 1981 case kImmutableArrayCid: |
2117 return MethodRecognizer::kImmutableArrayLength; | 1982 return MethodRecognizer::kImmutableArrayLength; |
2118 case kGrowableObjectArrayCid: | 1983 case kGrowableObjectArrayCid: |
2119 return MethodRecognizer::kGrowableArrayLength; | 1984 return MethodRecognizer::kGrowableArrayLength; |
2120 default: | 1985 default: |
2121 UNREACHABLE(); | 1986 UNREACHABLE(); |
2122 return MethodRecognizer::kUnknown; | 1987 return MethodRecognizer::kUnknown; |
2123 } | 1988 } |
2124 } | 1989 } |
2125 | 1990 |
2126 | |
2127 bool LoadFieldInstr::IsFixedLengthArrayCid(intptr_t cid) { | 1991 bool LoadFieldInstr::IsFixedLengthArrayCid(intptr_t cid) { |
2128 if (RawObject::IsTypedDataClassId(cid) || | 1992 if (RawObject::IsTypedDataClassId(cid) || |
2129 RawObject::IsExternalTypedDataClassId(cid)) { | 1993 RawObject::IsExternalTypedDataClassId(cid)) { |
2130 return true; | 1994 return true; |
2131 } | 1995 } |
2132 | 1996 |
2133 switch (cid) { | 1997 switch (cid) { |
2134 case kArrayCid: | 1998 case kArrayCid: |
2135 case kImmutableArrayCid: | 1999 case kImmutableArrayCid: |
2136 return true; | 2000 return true; |
2137 default: | 2001 default: |
2138 return false; | 2002 return false; |
2139 } | 2003 } |
2140 } | 2004 } |
2141 | 2005 |
2142 | |
2143 Definition* ConstantInstr::Canonicalize(FlowGraph* flow_graph) { | 2006 Definition* ConstantInstr::Canonicalize(FlowGraph* flow_graph) { |
2144 return HasUses() ? this : NULL; | 2007 return HasUses() ? this : NULL; |
2145 } | 2008 } |
2146 | 2009 |
2147 | |
2148 // A math unary instruction has a side effect (exception | 2010 // A math unary instruction has a side effect (exception |
2149 // thrown) if the argument is not a number. | 2011 // thrown) if the argument is not a number. |
2150 // TODO(srdjan): eliminate if has no uses and input is guaranteed to be number. | 2012 // TODO(srdjan): eliminate if has no uses and input is guaranteed to be number. |
2151 Definition* MathUnaryInstr::Canonicalize(FlowGraph* flow_graph) { | 2013 Definition* MathUnaryInstr::Canonicalize(FlowGraph* flow_graph) { |
2152 return this; | 2014 return this; |
2153 } | 2015 } |
2154 | 2016 |
2155 | |
2156 bool LoadFieldInstr::Evaluate(const Object& instance, Object* result) { | 2017 bool LoadFieldInstr::Evaluate(const Object& instance, Object* result) { |
2157 if (field() == NULL || !field()->is_final() || !instance.IsInstance()) { | 2018 if (field() == NULL || !field()->is_final() || !instance.IsInstance()) { |
2158 return false; | 2019 return false; |
2159 } | 2020 } |
2160 | 2021 |
2161 // Check that instance really has the field which we | 2022 // Check that instance really has the field which we |
2162 // are trying to load from. | 2023 // are trying to load from. |
2163 Class& cls = Class::Handle(instance.clazz()); | 2024 Class& cls = Class::Handle(instance.clazz()); |
2164 while (cls.raw() != Class::null() && cls.raw() != field()->Owner()) { | 2025 while (cls.raw() != Class::null() && cls.raw() != field()->Owner()) { |
2165 cls = cls.SuperClass(); | 2026 cls = cls.SuperClass(); |
2166 } | 2027 } |
2167 if (cls.raw() != field()->Owner()) { | 2028 if (cls.raw() != field()->Owner()) { |
2168 // Failed to find the field in class or its superclasses. | 2029 // Failed to find the field in class or its superclasses. |
2169 return false; | 2030 return false; |
2170 } | 2031 } |
2171 | 2032 |
2172 // Object has the field: execute the load. | 2033 // Object has the field: execute the load. |
2173 *result = Instance::Cast(instance).GetField(*field()); | 2034 *result = Instance::Cast(instance).GetField(*field()); |
2174 return true; | 2035 return true; |
2175 } | 2036 } |
2176 | 2037 |
2177 | |
2178 Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) { | 2038 Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) { |
2179 if (!HasUses()) return NULL; | 2039 if (!HasUses()) return NULL; |
2180 | 2040 |
2181 if (IsImmutableLengthLoad()) { | 2041 if (IsImmutableLengthLoad()) { |
2182 // For fixed length arrays if the array is the result of a known constructor | 2042 // For fixed length arrays if the array is the result of a known constructor |
2183 // call we can replace the length load with the length argument passed to | 2043 // call we can replace the length load with the length argument passed to |
2184 // the constructor. | 2044 // the constructor. |
2185 StaticCallInstr* call = | 2045 StaticCallInstr* call = |
2186 instance()->definition()->OriginalDefinition()->AsStaticCall(); | 2046 instance()->definition()->OriginalDefinition()->AsStaticCall(); |
2187 if (call != NULL) { | 2047 if (call != NULL) { |
(...skipping 27 matching lines...) Expand all Loading... |
2215 if (instance()->BindsToConstant()) { | 2075 if (instance()->BindsToConstant()) { |
2216 Object& result = Object::Handle(); | 2076 Object& result = Object::Handle(); |
2217 if (Evaluate(instance()->BoundConstant(), &result)) { | 2077 if (Evaluate(instance()->BoundConstant(), &result)) { |
2218 return flow_graph->GetConstant(result); | 2078 return flow_graph->GetConstant(result); |
2219 } | 2079 } |
2220 } | 2080 } |
2221 | 2081 |
2222 return this; | 2082 return this; |
2223 } | 2083 } |
2224 | 2084 |
2225 | |
2226 Definition* AssertBooleanInstr::Canonicalize(FlowGraph* flow_graph) { | 2085 Definition* AssertBooleanInstr::Canonicalize(FlowGraph* flow_graph) { |
2227 if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) { | 2086 if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) { |
2228 return value()->definition(); | 2087 return value()->definition(); |
2229 } | 2088 } |
2230 | 2089 |
2231 return this; | 2090 return this; |
2232 } | 2091 } |
2233 | 2092 |
2234 | |
2235 Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) { | 2093 Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) { |
2236 if (FLAG_eliminate_type_checks && | 2094 if (FLAG_eliminate_type_checks && |
2237 value()->Type()->IsAssignableTo(dst_type())) { | 2095 value()->Type()->IsAssignableTo(dst_type())) { |
2238 return value()->definition(); | 2096 return value()->definition(); |
2239 } | 2097 } |
2240 if (dst_type().IsInstantiated()) { | 2098 if (dst_type().IsInstantiated()) { |
2241 return this; | 2099 return this; |
2242 } | 2100 } |
2243 // For uninstantiated target types: If the instantiator and function | 2101 // For uninstantiated target types: If the instantiator and function |
2244 // type arguments are constant, instantiate the target type here. | 2102 // type arguments are constant, instantiate the target type here. |
(...skipping 30 matching lines...) Expand all Loading... |
2275 return value()->definition(); | 2133 return value()->definition(); |
2276 } | 2134 } |
2277 | 2135 |
2278 ConstantInstr* null_constant = flow_graph->constant_null(); | 2136 ConstantInstr* null_constant = flow_graph->constant_null(); |
2279 instantiator_type_arguments()->BindTo(null_constant); | 2137 instantiator_type_arguments()->BindTo(null_constant); |
2280 function_type_arguments()->BindTo(null_constant); | 2138 function_type_arguments()->BindTo(null_constant); |
2281 } | 2139 } |
2282 return this; | 2140 return this; |
2283 } | 2141 } |
2284 | 2142 |
2285 | |
2286 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { | 2143 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { |
2287 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; | 2144 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; |
2288 } | 2145 } |
2289 | 2146 |
2290 | |
2291 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, | 2147 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, |
2292 bool opt) const { | 2148 bool opt) const { |
2293 const intptr_t kNumInputs = 0; | 2149 const intptr_t kNumInputs = 0; |
2294 const intptr_t kNumTemps = 0; | 2150 const intptr_t kNumTemps = 0; |
2295 LocationSummary* locs = new (zone) | 2151 LocationSummary* locs = new (zone) |
2296 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2152 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2297 return locs; | 2153 return locs; |
2298 } | 2154 } |
2299 | 2155 |
2300 | |
2301 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { | 2156 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { |
2302 return NULL; | 2157 return NULL; |
2303 } | 2158 } |
2304 | 2159 |
2305 | |
2306 static bool HasTryBlockUse(Value* use_list) { | 2160 static bool HasTryBlockUse(Value* use_list) { |
2307 for (Value::Iterator it(use_list); !it.Done(); it.Advance()) { | 2161 for (Value::Iterator it(use_list); !it.Done(); it.Advance()) { |
2308 Value* use = it.Current(); | 2162 Value* use = it.Current(); |
2309 if (use->instruction()->MayThrow() && | 2163 if (use->instruction()->MayThrow() && |
2310 use->instruction()->GetBlock()->InsideTryBlock()) { | 2164 use->instruction()->GetBlock()->InsideTryBlock()) { |
2311 return true; | 2165 return true; |
2312 } | 2166 } |
2313 } | 2167 } |
2314 return false; | 2168 return false; |
2315 } | 2169 } |
2316 | 2170 |
2317 | |
2318 Definition* BoxInstr::Canonicalize(FlowGraph* flow_graph) { | 2171 Definition* BoxInstr::Canonicalize(FlowGraph* flow_graph) { |
2319 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { | 2172 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { |
2320 // Environments can accommodate any representation. No need to box. | 2173 // Environments can accommodate any representation. No need to box. |
2321 return value()->definition(); | 2174 return value()->definition(); |
2322 } | 2175 } |
2323 | 2176 |
2324 // Fold away Box<rep>(Unbox<rep>(v)) if value is known to be of the | 2177 // Fold away Box<rep>(Unbox<rep>(v)) if value is known to be of the |
2325 // right class. | 2178 // right class. |
2326 UnboxInstr* unbox_defn = value()->definition()->AsUnbox(); | 2179 UnboxInstr* unbox_defn = value()->definition()->AsUnbox(); |
2327 if ((unbox_defn != NULL) && | 2180 if ((unbox_defn != NULL) && |
2328 (unbox_defn->representation() == from_representation()) && | 2181 (unbox_defn->representation() == from_representation()) && |
2329 (unbox_defn->value()->Type()->ToCid() == Type()->ToCid())) { | 2182 (unbox_defn->value()->Type()->ToCid() == Type()->ToCid())) { |
2330 return unbox_defn->value()->definition(); | 2183 return unbox_defn->value()->definition(); |
2331 } | 2184 } |
2332 | 2185 |
2333 return this; | 2186 return this; |
2334 } | 2187 } |
2335 | 2188 |
2336 | |
2337 bool BoxIntegerInstr::ValueFitsSmi() const { | 2189 bool BoxIntegerInstr::ValueFitsSmi() const { |
2338 Range* range = value()->definition()->range(); | 2190 Range* range = value()->definition()->range(); |
2339 return RangeUtils::Fits(range, RangeBoundary::kRangeBoundarySmi); | 2191 return RangeUtils::Fits(range, RangeBoundary::kRangeBoundarySmi); |
2340 } | 2192 } |
2341 | 2193 |
2342 | |
2343 Definition* BoxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { | 2194 Definition* BoxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
2344 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { | 2195 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { |
2345 // Environments can accommodate any representation. No need to box. | 2196 // Environments can accommodate any representation. No need to box. |
2346 return value()->definition(); | 2197 return value()->definition(); |
2347 } | 2198 } |
2348 | 2199 |
2349 return this; | 2200 return this; |
2350 } | 2201 } |
2351 | 2202 |
2352 | |
2353 Definition* BoxInt64Instr::Canonicalize(FlowGraph* flow_graph) { | 2203 Definition* BoxInt64Instr::Canonicalize(FlowGraph* flow_graph) { |
2354 Definition* replacement = BoxIntegerInstr::Canonicalize(flow_graph); | 2204 Definition* replacement = BoxIntegerInstr::Canonicalize(flow_graph); |
2355 if (replacement != this) { | 2205 if (replacement != this) { |
2356 return replacement; | 2206 return replacement; |
2357 } | 2207 } |
2358 | 2208 |
2359 UnboxedIntConverterInstr* conv = | 2209 UnboxedIntConverterInstr* conv = |
2360 value()->definition()->AsUnboxedIntConverter(); | 2210 value()->definition()->AsUnboxedIntConverter(); |
2361 if (conv != NULL) { | 2211 if (conv != NULL) { |
2362 Definition* replacement = this; | 2212 Definition* replacement = this; |
(...skipping 13 matching lines...) Expand all Loading... |
2376 if (replacement != this) { | 2226 if (replacement != this) { |
2377 flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue); | 2227 flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue); |
2378 } | 2228 } |
2379 | 2229 |
2380 return replacement; | 2230 return replacement; |
2381 } | 2231 } |
2382 | 2232 |
2383 return this; | 2233 return this; |
2384 } | 2234 } |
2385 | 2235 |
2386 | |
2387 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { | 2236 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { |
2388 if (!HasUses() && !CanDeoptimize()) return NULL; | 2237 if (!HasUses() && !CanDeoptimize()) return NULL; |
2389 | 2238 |
2390 // Fold away Unbox<rep>(Box<rep>(v)). | 2239 // Fold away Unbox<rep>(Box<rep>(v)). |
2391 BoxInstr* box_defn = value()->definition()->AsBox(); | 2240 BoxInstr* box_defn = value()->definition()->AsBox(); |
2392 if ((box_defn != NULL) && | 2241 if ((box_defn != NULL) && |
2393 (box_defn->from_representation() == representation())) { | 2242 (box_defn->from_representation() == representation())) { |
2394 return box_defn->value()->definition(); | 2243 return box_defn->value()->definition(); |
2395 } | 2244 } |
2396 | 2245 |
(...skipping 12 matching lines...) Expand all Loading... |
2409 | 2258 |
2410 if (uc != NULL) { | 2259 if (uc != NULL) { |
2411 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2260 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
2412 return uc; | 2261 return uc; |
2413 } | 2262 } |
2414 } | 2263 } |
2415 | 2264 |
2416 return this; | 2265 return this; |
2417 } | 2266 } |
2418 | 2267 |
2419 | |
2420 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { | 2268 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
2421 if (!HasUses() && !CanDeoptimize()) return NULL; | 2269 if (!HasUses() && !CanDeoptimize()) return NULL; |
2422 | 2270 |
2423 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). | 2271 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). |
2424 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); | 2272 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); |
2425 if (box_defn != NULL) { | 2273 if (box_defn != NULL) { |
2426 Representation from_representation = | 2274 Representation from_representation = |
2427 box_defn->value()->definition()->representation(); | 2275 box_defn->value()->definition()->representation(); |
2428 if (from_representation == representation()) { | 2276 if (from_representation == representation()) { |
2429 return box_defn->value()->definition(); | 2277 return box_defn->value()->definition(); |
(...skipping 13 matching lines...) Expand all Loading... |
2443 converter->mark_truncating(); | 2291 converter->mark_truncating(); |
2444 } | 2292 } |
2445 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2293 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
2446 return converter; | 2294 return converter; |
2447 } | 2295 } |
2448 } | 2296 } |
2449 | 2297 |
2450 return this; | 2298 return this; |
2451 } | 2299 } |
2452 | 2300 |
2453 | |
2454 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { | 2301 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { |
2455 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); | 2302 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); |
2456 if (replacement != this) { | 2303 if (replacement != this) { |
2457 return replacement; | 2304 return replacement; |
2458 } | 2305 } |
2459 | 2306 |
2460 ConstantInstr* c = value()->definition()->AsConstant(); | 2307 ConstantInstr* c = value()->definition()->AsConstant(); |
2461 if ((c != NULL) && c->value().IsSmi()) { | 2308 if ((c != NULL) && c->value().IsSmi()) { |
2462 if (!is_truncating() && (kSmiBits > 32)) { | 2309 if (!is_truncating() && (kSmiBits > 32)) { |
2463 // Check that constant fits into 32-bit integer. | 2310 // Check that constant fits into 32-bit integer. |
2464 const int64_t value = static_cast<int64_t>(Smi::Cast(c->value()).Value()); | 2311 const int64_t value = static_cast<int64_t>(Smi::Cast(c->value()).Value()); |
2465 if (!Utils::IsInt(32, value)) { | 2312 if (!Utils::IsInt(32, value)) { |
2466 return this; | 2313 return this; |
2467 } | 2314 } |
2468 } | 2315 } |
2469 | 2316 |
2470 UnboxedConstantInstr* uc = | 2317 UnboxedConstantInstr* uc = |
2471 new UnboxedConstantInstr(c->value(), kUnboxedInt32); | 2318 new UnboxedConstantInstr(c->value(), kUnboxedInt32); |
2472 if (c->range() != NULL) { | 2319 if (c->range() != NULL) { |
2473 uc->set_range(*c->range()); | 2320 uc->set_range(*c->range()); |
2474 } | 2321 } |
2475 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2322 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
2476 return uc; | 2323 return uc; |
2477 } | 2324 } |
2478 | 2325 |
2479 return this; | 2326 return this; |
2480 } | 2327 } |
2481 | 2328 |
2482 | |
2483 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { | 2329 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { |
2484 if (!HasUses()) return NULL; | 2330 if (!HasUses()) return NULL; |
2485 | 2331 |
2486 UnboxedIntConverterInstr* box_defn = | 2332 UnboxedIntConverterInstr* box_defn = |
2487 value()->definition()->AsUnboxedIntConverter(); | 2333 value()->definition()->AsUnboxedIntConverter(); |
2488 if ((box_defn != NULL) && (box_defn->representation() == from())) { | 2334 if ((box_defn != NULL) && (box_defn->representation() == from())) { |
2489 if (box_defn->from() == to()) { | 2335 if (box_defn->from() == to()) { |
2490 // Do not erase truncating conversions from 64-bit value to 32-bit values | 2336 // Do not erase truncating conversions from 64-bit value to 32-bit values |
2491 // because such conversions erase upper 32 bits. | 2337 // because such conversions erase upper 32 bits. |
2492 if ((box_defn->from() == kUnboxedMint) && box_defn->is_truncating()) { | 2338 if ((box_defn->from() == kUnboxedMint) && box_defn->is_truncating()) { |
(...skipping 22 matching lines...) Expand all Loading... |
2515 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate | 2361 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate |
2516 : UnboxInt32Instr::kNoTruncation, | 2362 : UnboxInt32Instr::kNoTruncation, |
2517 unbox_defn->value()->CopyWithType(), GetDeoptId()); | 2363 unbox_defn->value()->CopyWithType(), GetDeoptId()); |
2518 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 2364 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
2519 return replacement; | 2365 return replacement; |
2520 } | 2366 } |
2521 | 2367 |
2522 return this; | 2368 return this; |
2523 } | 2369 } |
2524 | 2370 |
2525 | |
2526 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { | 2371 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { |
2527 Definition* defn = value()->definition(); | 2372 Definition* defn = value()->definition(); |
2528 if (defn->IsComparison() && defn->HasOnlyUse(value()) && | 2373 if (defn->IsComparison() && defn->HasOnlyUse(value()) && |
2529 defn->Type()->ToCid() == kBoolCid) { | 2374 defn->Type()->ToCid() == kBoolCid) { |
2530 defn->AsComparison()->NegateComparison(); | 2375 defn->AsComparison()->NegateComparison(); |
2531 return defn; | 2376 return defn; |
2532 } | 2377 } |
2533 return this; | 2378 return this; |
2534 } | 2379 } |
2535 | 2380 |
2536 | |
2537 static bool MayBeBoxableNumber(intptr_t cid) { | 2381 static bool MayBeBoxableNumber(intptr_t cid) { |
2538 return (cid == kDynamicCid) || (cid == kMintCid) || (cid == kBigintCid) || | 2382 return (cid == kDynamicCid) || (cid == kMintCid) || (cid == kBigintCid) || |
2539 (cid == kDoubleCid); | 2383 (cid == kDoubleCid); |
2540 } | 2384 } |
2541 | 2385 |
2542 | |
2543 static bool MaybeNumber(CompileType* type) { | 2386 static bool MaybeNumber(CompileType* type) { |
2544 ASSERT(Type::Handle(Type::Number()) | 2387 ASSERT(Type::Handle(Type::Number()) |
2545 .IsMoreSpecificThan(Type::Handle(Type::Number()), NULL, NULL, | 2388 .IsMoreSpecificThan(Type::Handle(Type::Number()), NULL, NULL, |
2546 Heap::kOld)); | 2389 Heap::kOld)); |
2547 return type->ToAbstractType()->IsDynamicType() || | 2390 return type->ToAbstractType()->IsDynamicType() || |
2548 type->ToAbstractType()->IsObjectType() || | 2391 type->ToAbstractType()->IsObjectType() || |
2549 type->ToAbstractType()->IsTypeParameter() || | 2392 type->ToAbstractType()->IsTypeParameter() || |
2550 type->IsMoreSpecificThan(Type::Handle(Type::Number())); | 2393 type->IsMoreSpecificThan(Type::Handle(Type::Number())); |
2551 } | 2394 } |
2552 | 2395 |
2553 | |
2554 // Returns a replacement for a strict comparison and signals if the result has | 2396 // Returns a replacement for a strict comparison and signals if the result has |
2555 // to be negated. | 2397 // to be negated. |
2556 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, | 2398 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, |
2557 bool* negated, | 2399 bool* negated, |
2558 bool is_branch) { | 2400 bool is_branch) { |
2559 // Use propagated cid and type information to eliminate number checks. | 2401 // Use propagated cid and type information to eliminate number checks. |
2560 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or | 2402 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or |
2561 // is not a subtype of num, no need for number checks. | 2403 // is not a subtype of num, no need for number checks. |
2562 if (compare->needs_number_check()) { | 2404 if (compare->needs_number_check()) { |
2563 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || | 2405 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2604 // Handle e === false. | 2446 // Handle e === false. |
2605 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::False().raw()) && | 2447 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::False().raw()) && |
2606 other_defn->IsComparison() && can_merge && | 2448 other_defn->IsComparison() && can_merge && |
2607 other_defn->HasOnlyUse(other)) { | 2449 other_defn->HasOnlyUse(other)) { |
2608 *negated = true; | 2450 *negated = true; |
2609 return other_defn; | 2451 return other_defn; |
2610 } | 2452 } |
2611 return compare; | 2453 return compare; |
2612 } | 2454 } |
2613 | 2455 |
2614 | |
2615 static bool BindsToGivenConstant(Value* v, intptr_t expected) { | 2456 static bool BindsToGivenConstant(Value* v, intptr_t expected) { |
2616 return v->BindsToConstant() && v->BoundConstant().IsSmi() && | 2457 return v->BindsToConstant() && v->BoundConstant().IsSmi() && |
2617 (Smi::Cast(v->BoundConstant()).Value() == expected); | 2458 (Smi::Cast(v->BoundConstant()).Value() == expected); |
2618 } | 2459 } |
2619 | 2460 |
2620 | |
2621 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. | 2461 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. |
2622 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { | 2462 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { |
2623 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { | 2463 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { |
2624 return false; | 2464 return false; |
2625 } | 2465 } |
2626 | 2466 |
2627 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); | 2467 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); |
2628 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { | 2468 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { |
2629 return false; | 2469 return false; |
2630 } | 2470 } |
2631 | 2471 |
2632 | |
2633 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); | 2472 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); |
2634 if ((mask_op == NULL) || (mask_op->op_kind() != Token::kBIT_AND) || | 2473 if ((mask_op == NULL) || (mask_op->op_kind() != Token::kBIT_AND) || |
2635 !mask_op->HasOnlyUse(left)) { | 2474 !mask_op->HasOnlyUse(left)) { |
2636 return false; | 2475 return false; |
2637 } | 2476 } |
2638 | 2477 |
2639 if (value == 0) { | 2478 if (value == 0) { |
2640 // Recognized (a & b) == 0 pattern. | 2479 // Recognized (a & b) == 0 pattern. |
2641 *negate = false; | 2480 *negate = false; |
2642 return true; | 2481 return true; |
2643 } | 2482 } |
2644 | 2483 |
2645 // Recognize | 2484 // Recognize |
2646 if (BindsToGivenConstant(mask_op->left(), value) || | 2485 if (BindsToGivenConstant(mask_op->left(), value) || |
2647 BindsToGivenConstant(mask_op->right(), value)) { | 2486 BindsToGivenConstant(mask_op->right(), value)) { |
2648 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 | 2487 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 |
2649 // so we need to negate original comparison. | 2488 // so we need to negate original comparison. |
2650 *negate = true; | 2489 *negate = true; |
2651 return true; | 2490 return true; |
2652 } | 2491 } |
2653 | 2492 |
2654 return false; | 2493 return false; |
2655 } | 2494 } |
2656 | 2495 |
2657 | |
2658 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { | 2496 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { |
2659 Zone* zone = flow_graph->zone(); | 2497 Zone* zone = flow_graph->zone(); |
2660 // Only handle strict-compares. | 2498 // Only handle strict-compares. |
2661 if (comparison()->IsStrictCompare()) { | 2499 if (comparison()->IsStrictCompare()) { |
2662 bool negated = false; | 2500 bool negated = false; |
2663 Definition* replacement = CanonicalizeStrictCompare( | 2501 Definition* replacement = CanonicalizeStrictCompare( |
2664 comparison()->AsStrictCompare(), &negated, /* is_branch = */ true); | 2502 comparison()->AsStrictCompare(), &negated, /* is_branch = */ true); |
2665 if (replacement == comparison()) { | 2503 if (replacement == comparison()) { |
2666 return this; | 2504 return this; |
2667 } | 2505 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2718 ASSERT(!CanDeoptimize()); | 2556 ASSERT(!CanDeoptimize()); |
2719 RemoveEnvironment(); | 2557 RemoveEnvironment(); |
2720 flow_graph->CopyDeoptTarget(this, bit_and); | 2558 flow_graph->CopyDeoptTarget(this, bit_and); |
2721 SetComparison(test); | 2559 SetComparison(test); |
2722 bit_and->RemoveFromGraph(); | 2560 bit_and->RemoveFromGraph(); |
2723 } | 2561 } |
2724 } | 2562 } |
2725 return this; | 2563 return this; |
2726 } | 2564 } |
2727 | 2565 |
2728 | |
2729 Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) { | 2566 Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) { |
2730 if (!HasUses()) return NULL; | 2567 if (!HasUses()) return NULL; |
2731 bool negated = false; | 2568 bool negated = false; |
2732 Definition* replacement = CanonicalizeStrictCompare(this, &negated, | 2569 Definition* replacement = CanonicalizeStrictCompare(this, &negated, |
2733 /* is_branch = */ false); | 2570 /* is_branch = */ false); |
2734 if (negated && replacement->IsComparison()) { | 2571 if (negated && replacement->IsComparison()) { |
2735 ASSERT(replacement != this); | 2572 ASSERT(replacement != this); |
2736 replacement->AsComparison()->NegateComparison(); | 2573 replacement->AsComparison()->NegateComparison(); |
2737 } | 2574 } |
2738 return replacement; | 2575 return replacement; |
2739 } | 2576 } |
2740 | 2577 |
2741 | |
2742 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { | 2578 Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) { |
2743 const intptr_t value_cid = value()->Type()->ToCid(); | 2579 const intptr_t value_cid = value()->Type()->ToCid(); |
2744 if (value_cid == kDynamicCid) { | 2580 if (value_cid == kDynamicCid) { |
2745 return this; | 2581 return this; |
2746 } | 2582 } |
2747 | 2583 |
2748 return cids().HasClassId(value_cid) ? NULL : this; | 2584 return cids().HasClassId(value_cid) ? NULL : this; |
2749 } | 2585 } |
2750 | 2586 |
2751 | |
2752 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { | 2587 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { |
2753 if (value()->BindsToConstant()) { | 2588 if (value()->BindsToConstant()) { |
2754 const Object& constant_value = value()->BoundConstant(); | 2589 const Object& constant_value = value()->BoundConstant(); |
2755 if (constant_value.IsSmi() && | 2590 if (constant_value.IsSmi() && |
2756 cids_.Contains(Smi::Cast(constant_value).Value())) { | 2591 cids_.Contains(Smi::Cast(constant_value).Value())) { |
2757 return NULL; | 2592 return NULL; |
2758 } | 2593 } |
2759 } | 2594 } |
2760 return this; | 2595 return this; |
2761 } | 2596 } |
2762 | 2597 |
2763 | |
2764 TestCidsInstr::TestCidsInstr(TokenPosition token_pos, | 2598 TestCidsInstr::TestCidsInstr(TokenPosition token_pos, |
2765 Token::Kind kind, | 2599 Token::Kind kind, |
2766 Value* value, | 2600 Value* value, |
2767 const ZoneGrowableArray<intptr_t>& cid_results, | 2601 const ZoneGrowableArray<intptr_t>& cid_results, |
2768 intptr_t deopt_id) | 2602 intptr_t deopt_id) |
2769 : TemplateComparison(token_pos, kind, deopt_id), | 2603 : TemplateComparison(token_pos, kind, deopt_id), |
2770 cid_results_(cid_results), | 2604 cid_results_(cid_results), |
2771 licm_hoisted_(false) { | 2605 licm_hoisted_(false) { |
2772 ASSERT((kind == Token::kIS) || (kind == Token::kISNOT)); | 2606 ASSERT((kind == Token::kIS) || (kind == Token::kISNOT)); |
2773 SetInputAt(0, value); | 2607 SetInputAt(0, value); |
2774 set_operation_cid(kObjectCid); | 2608 set_operation_cid(kObjectCid); |
2775 #ifdef DEBUG | 2609 #ifdef DEBUG |
2776 ASSERT(cid_results[0] == kSmiCid); | 2610 ASSERT(cid_results[0] == kSmiCid); |
2777 if (deopt_id == Thread::kNoDeoptId) { | 2611 if (deopt_id == Thread::kNoDeoptId) { |
2778 // The entry for Smi can be special, but all other entries have | 2612 // The entry for Smi can be special, but all other entries have |
2779 // to match in the no-deopt case. | 2613 // to match in the no-deopt case. |
2780 for (intptr_t i = 4; i < cid_results.length(); i += 2) { | 2614 for (intptr_t i = 4; i < cid_results.length(); i += 2) { |
2781 ASSERT(cid_results[i + 1] == cid_results[3]); | 2615 ASSERT(cid_results[i + 1] == cid_results[3]); |
2782 } | 2616 } |
2783 } | 2617 } |
2784 #endif | 2618 #endif |
2785 } | 2619 } |
2786 | 2620 |
2787 | |
2788 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { | 2621 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { |
2789 CompileType* in_type = left()->Type(); | 2622 CompileType* in_type = left()->Type(); |
2790 intptr_t cid = in_type->ToCid(); | 2623 intptr_t cid = in_type->ToCid(); |
2791 if (cid == kDynamicCid) return this; | 2624 if (cid == kDynamicCid) return this; |
2792 | 2625 |
2793 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 2626 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
2794 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 2627 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
2795 for (intptr_t i = 0; i < data.length(); i += 2) { | 2628 for (intptr_t i = 0; i < data.length(); i += 2) { |
2796 if (data[i] == cid) { | 2629 if (data[i] == cid) { |
2797 return (data[i + 1] == true_result) | 2630 return (data[i + 1] == true_result) |
2798 ? flow_graph->GetConstant(Bool::True()) | 2631 ? flow_graph->GetConstant(Bool::True()) |
2799 : flow_graph->GetConstant(Bool::False()); | 2632 : flow_graph->GetConstant(Bool::False()); |
2800 } | 2633 } |
2801 } | 2634 } |
2802 | 2635 |
2803 if (!CanDeoptimize()) { | 2636 if (!CanDeoptimize()) { |
2804 ASSERT(deopt_id() == Thread::kNoDeoptId); | 2637 ASSERT(deopt_id() == Thread::kNoDeoptId); |
2805 return (data[data.length() - 1] == true_result) | 2638 return (data[data.length() - 1] == true_result) |
2806 ? flow_graph->GetConstant(Bool::False()) | 2639 ? flow_graph->GetConstant(Bool::False()) |
2807 : flow_graph->GetConstant(Bool::True()); | 2640 : flow_graph->GetConstant(Bool::True()); |
2808 } | 2641 } |
2809 | 2642 |
2810 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare | 2643 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare |
2811 // against `null`. | 2644 // against `null`. |
2812 return this; | 2645 return this; |
2813 } | 2646 } |
2814 | 2647 |
2815 | |
2816 Instruction* GuardFieldClassInstr::Canonicalize(FlowGraph* flow_graph) { | 2648 Instruction* GuardFieldClassInstr::Canonicalize(FlowGraph* flow_graph) { |
2817 if (field().guarded_cid() == kDynamicCid) { | 2649 if (field().guarded_cid() == kDynamicCid) { |
2818 return NULL; // Nothing to guard. | 2650 return NULL; // Nothing to guard. |
2819 } | 2651 } |
2820 | 2652 |
2821 if (field().is_nullable() && value()->Type()->IsNull()) { | 2653 if (field().is_nullable() && value()->Type()->IsNull()) { |
2822 return NULL; | 2654 return NULL; |
2823 } | 2655 } |
2824 | 2656 |
2825 const intptr_t cid = field().is_nullable() ? value()->Type()->ToNullableCid() | 2657 const intptr_t cid = field().is_nullable() ? value()->Type()->ToNullableCid() |
2826 : value()->Type()->ToCid(); | 2658 : value()->Type()->ToCid(); |
2827 if (field().guarded_cid() == cid) { | 2659 if (field().guarded_cid() == cid) { |
2828 return NULL; // Value is guaranteed to have this cid. | 2660 return NULL; // Value is guaranteed to have this cid. |
2829 } | 2661 } |
2830 | 2662 |
2831 return this; | 2663 return this; |
2832 } | 2664 } |
2833 | 2665 |
2834 | |
2835 Instruction* GuardFieldLengthInstr::Canonicalize(FlowGraph* flow_graph) { | 2666 Instruction* GuardFieldLengthInstr::Canonicalize(FlowGraph* flow_graph) { |
2836 if (!field().needs_length_check()) { | 2667 if (!field().needs_length_check()) { |
2837 return NULL; // Nothing to guard. | 2668 return NULL; // Nothing to guard. |
2838 } | 2669 } |
2839 | 2670 |
2840 const intptr_t expected_length = field().guarded_list_length(); | 2671 const intptr_t expected_length = field().guarded_list_length(); |
2841 if (expected_length == Field::kUnknownFixedLength) { | 2672 if (expected_length == Field::kUnknownFixedLength) { |
2842 return this; | 2673 return this; |
2843 } | 2674 } |
2844 | 2675 |
2845 // Check if length is statically known. | 2676 // Check if length is statically known. |
2846 StaticCallInstr* call = value()->definition()->AsStaticCall(); | 2677 StaticCallInstr* call = value()->definition()->AsStaticCall(); |
2847 if (call == NULL) { | 2678 if (call == NULL) { |
2848 return this; | 2679 return this; |
2849 } | 2680 } |
2850 | 2681 |
2851 ConstantInstr* length = NULL; | 2682 ConstantInstr* length = NULL; |
2852 if (call->is_known_list_constructor() && | 2683 if (call->is_known_list_constructor() && |
2853 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { | 2684 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { |
2854 length = call->ArgumentAt(1)->AsConstant(); | 2685 length = call->ArgumentAt(1)->AsConstant(); |
2855 } | 2686 } |
2856 if ((length != NULL) && length->value().IsSmi() && | 2687 if ((length != NULL) && length->value().IsSmi() && |
2857 Smi::Cast(length->value()).Value() == expected_length) { | 2688 Smi::Cast(length->value()).Value() == expected_length) { |
2858 return NULL; // Expected length matched. | 2689 return NULL; // Expected length matched. |
2859 } | 2690 } |
2860 | 2691 |
2861 return this; | 2692 return this; |
2862 } | 2693 } |
2863 | 2694 |
2864 | |
2865 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2695 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
2866 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; | 2696 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; |
2867 } | 2697 } |
2868 | 2698 |
2869 | |
2870 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2699 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
2871 if ((left()->Type()->ToCid() == kDoubleCid) || | 2700 if ((left()->Type()->ToCid() == kDoubleCid) || |
2872 (right()->Type()->ToCid() == kDoubleCid)) { | 2701 (right()->Type()->ToCid() == kDoubleCid)) { |
2873 return NULL; // Remove from the graph. | 2702 return NULL; // Remove from the graph. |
2874 } | 2703 } |
2875 return this; | 2704 return this; |
2876 } | 2705 } |
2877 | 2706 |
2878 | |
2879 BoxInstr* BoxInstr::Create(Representation from, Value* value) { | 2707 BoxInstr* BoxInstr::Create(Representation from, Value* value) { |
2880 switch (from) { | 2708 switch (from) { |
2881 case kUnboxedInt32: | 2709 case kUnboxedInt32: |
2882 return new BoxInt32Instr(value); | 2710 return new BoxInt32Instr(value); |
2883 | 2711 |
2884 case kUnboxedUint32: | 2712 case kUnboxedUint32: |
2885 return new BoxUint32Instr(value); | 2713 return new BoxUint32Instr(value); |
2886 | 2714 |
2887 case kUnboxedMint: | 2715 case kUnboxedMint: |
2888 return new BoxInt64Instr(value); | 2716 return new BoxInt64Instr(value); |
2889 | 2717 |
2890 case kUnboxedDouble: | 2718 case kUnboxedDouble: |
2891 case kUnboxedFloat32x4: | 2719 case kUnboxedFloat32x4: |
2892 case kUnboxedFloat64x2: | 2720 case kUnboxedFloat64x2: |
2893 case kUnboxedInt32x4: | 2721 case kUnboxedInt32x4: |
2894 return new BoxInstr(from, value); | 2722 return new BoxInstr(from, value); |
2895 | 2723 |
2896 default: | 2724 default: |
2897 UNREACHABLE(); | 2725 UNREACHABLE(); |
2898 return NULL; | 2726 return NULL; |
2899 } | 2727 } |
2900 } | 2728 } |
2901 | 2729 |
2902 | |
2903 UnboxInstr* UnboxInstr::Create(Representation to, | 2730 UnboxInstr* UnboxInstr::Create(Representation to, |
2904 Value* value, | 2731 Value* value, |
2905 intptr_t deopt_id) { | 2732 intptr_t deopt_id) { |
2906 switch (to) { | 2733 switch (to) { |
2907 case kUnboxedInt32: | 2734 case kUnboxedInt32: |
2908 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, | 2735 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, |
2909 deopt_id); | 2736 deopt_id); |
2910 | 2737 |
2911 case kUnboxedUint32: | 2738 case kUnboxedUint32: |
2912 return new UnboxUint32Instr(value, deopt_id); | 2739 return new UnboxUint32Instr(value, deopt_id); |
2913 | 2740 |
2914 case kUnboxedMint: | 2741 case kUnboxedMint: |
2915 return new UnboxInt64Instr(value, deopt_id); | 2742 return new UnboxInt64Instr(value, deopt_id); |
2916 | 2743 |
2917 case kUnboxedDouble: | 2744 case kUnboxedDouble: |
2918 case kUnboxedFloat32x4: | 2745 case kUnboxedFloat32x4: |
2919 case kUnboxedFloat64x2: | 2746 case kUnboxedFloat64x2: |
2920 case kUnboxedInt32x4: | 2747 case kUnboxedInt32x4: |
2921 return new UnboxInstr(to, value, deopt_id); | 2748 return new UnboxInstr(to, value, deopt_id); |
2922 | 2749 |
2923 default: | 2750 default: |
2924 UNREACHABLE(); | 2751 UNREACHABLE(); |
2925 return NULL; | 2752 return NULL; |
2926 } | 2753 } |
2927 } | 2754 } |
2928 | 2755 |
2929 | |
2930 bool UnboxInstr::CanConvertSmi() const { | 2756 bool UnboxInstr::CanConvertSmi() const { |
2931 switch (representation()) { | 2757 switch (representation()) { |
2932 case kUnboxedDouble: | 2758 case kUnboxedDouble: |
2933 case kUnboxedMint: | 2759 case kUnboxedMint: |
2934 return true; | 2760 return true; |
2935 | 2761 |
2936 case kUnboxedFloat32x4: | 2762 case kUnboxedFloat32x4: |
2937 case kUnboxedFloat64x2: | 2763 case kUnboxedFloat64x2: |
2938 case kUnboxedInt32x4: | 2764 case kUnboxedInt32x4: |
2939 return false; | 2765 return false; |
2940 | 2766 |
2941 default: | 2767 default: |
2942 UNREACHABLE(); | 2768 UNREACHABLE(); |
2943 return false; | 2769 return false; |
2944 } | 2770 } |
2945 } | 2771 } |
2946 | 2772 |
2947 | |
2948 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { | 2773 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { |
2949 CallTargets* targets = new (zone) CallTargets(zone); | 2774 CallTargets* targets = new (zone) CallTargets(zone); |
2950 targets->CreateHelper(zone, ic_data, /* argument_number = */ 0, | 2775 targets->CreateHelper(zone, ic_data, /* argument_number = */ 0, |
2951 /* include_targets = */ true); | 2776 /* include_targets = */ true); |
2952 targets->Sort(OrderById); | 2777 targets->Sort(OrderById); |
2953 targets->MergeIntoRanges(); | 2778 targets->MergeIntoRanges(); |
2954 return targets; | 2779 return targets; |
2955 } | 2780 } |
2956 | 2781 |
2957 | |
2958 CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) { | 2782 CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) { |
2959 CallTargets& targets = *new (zone) CallTargets(zone); | 2783 CallTargets& targets = *new (zone) CallTargets(zone); |
2960 targets.CreateHelper(zone, ic_data, /* argument_number = */ 0, | 2784 targets.CreateHelper(zone, ic_data, /* argument_number = */ 0, |
2961 /* include_targets = */ true); | 2785 /* include_targets = */ true); |
2962 targets.Sort(OrderById); | 2786 targets.Sort(OrderById); |
2963 | 2787 |
2964 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); | 2788 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); |
2965 ArgumentsDescriptor args_desc(args_desc_array); | 2789 ArgumentsDescriptor args_desc(args_desc_array); |
2966 String& name = String::Handle(zone, ic_data.target_name()); | 2790 String& name = String::Handle(zone, ic_data.target_name()); |
2967 | 2791 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3007 } | 2831 } |
3008 } else { | 2832 } else { |
3009 break; | 2833 break; |
3010 } | 2834 } |
3011 } | 2835 } |
3012 } | 2836 } |
3013 targets.MergeIntoRanges(); | 2837 targets.MergeIntoRanges(); |
3014 return &targets; | 2838 return &targets; |
3015 } | 2839 } |
3016 | 2840 |
3017 | |
3018 void CallTargets::MergeIntoRanges() { | 2841 void CallTargets::MergeIntoRanges() { |
3019 // Merge adjacent class id ranges. | 2842 // Merge adjacent class id ranges. |
3020 int dest = 0; | 2843 int dest = 0; |
3021 // We merge entries that dispatch to the same target, but polymorphic targets | 2844 // We merge entries that dispatch to the same target, but polymorphic targets |
3022 // are not really the same target since they depend on the class-id, so we | 2845 // are not really the same target since they depend on the class-id, so we |
3023 // don't merge them. | 2846 // don't merge them. |
3024 for (int src = 1; src < length(); src++) { | 2847 for (int src = 1; src < length(); src++) { |
3025 const Function& target = *TargetAt(dest)->target; | 2848 const Function& target = *TargetAt(dest)->target; |
3026 if (TargetAt(dest)->cid_end + 1 >= TargetAt(src)->cid_start && | 2849 if (TargetAt(dest)->cid_end + 1 >= TargetAt(src)->cid_start && |
3027 target.raw() == TargetAt(src)->target->raw() && | 2850 target.raw() == TargetAt(src)->target->raw() && |
3028 !MethodRecognizer::PolymorphicTarget(target)) { | 2851 !MethodRecognizer::PolymorphicTarget(target)) { |
3029 TargetAt(dest)->cid_end = TargetAt(src)->cid_end; | 2852 TargetAt(dest)->cid_end = TargetAt(src)->cid_end; |
3030 TargetAt(dest)->count += TargetAt(src)->count; | 2853 TargetAt(dest)->count += TargetAt(src)->count; |
3031 } else { | 2854 } else { |
3032 dest++; | 2855 dest++; |
3033 if (src != dest) { | 2856 if (src != dest) { |
3034 // Use cid_ranges_ instead of TargetAt when updating the pointer. | 2857 // Use cid_ranges_ instead of TargetAt when updating the pointer. |
3035 cid_ranges_[dest] = TargetAt(src); | 2858 cid_ranges_[dest] = TargetAt(src); |
3036 } | 2859 } |
3037 } | 2860 } |
3038 } | 2861 } |
3039 SetLength(dest + 1); | 2862 SetLength(dest + 1); |
3040 Sort(OrderByFrequency); | 2863 Sort(OrderByFrequency); |
3041 } | 2864 } |
3042 | 2865 |
3043 | |
3044 // Shared code generation methods (EmitNativeCode and | 2866 // Shared code generation methods (EmitNativeCode and |
3045 // MakeLocationSummary). Only assembly code that can be shared across all | 2867 // MakeLocationSummary). Only assembly code that can be shared across all |
3046 // architectures can be used. Machine specific register allocation and code | 2868 // architectures can be used. Machine specific register allocation and code |
3047 // generation is located in intermediate_language_<arch>.cc | 2869 // generation is located in intermediate_language_<arch>.cc |
3048 | 2870 |
3049 #define __ compiler->assembler()-> | 2871 #define __ compiler->assembler()-> |
3050 | 2872 |
3051 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, | 2873 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, |
3052 bool optimizing) const { | 2874 bool optimizing) const { |
3053 UNREACHABLE(); | 2875 UNREACHABLE(); |
3054 return NULL; | 2876 return NULL; |
3055 } | 2877 } |
3056 | 2878 |
3057 | |
3058 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, | 2879 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, |
3059 bool optimizing) const { | 2880 bool optimizing) const { |
3060 UNREACHABLE(); | 2881 UNREACHABLE(); |
3061 return NULL; | 2882 return NULL; |
3062 } | 2883 } |
3063 | 2884 |
3064 | |
3065 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2885 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3066 __ Bind(compiler->GetJumpLabel(this)); | 2886 __ Bind(compiler->GetJumpLabel(this)); |
3067 if (!compiler->is_optimizing()) { | 2887 if (!compiler->is_optimizing()) { |
3068 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), | 2888 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
3069 TokenPosition::kNoSource); | 2889 TokenPosition::kNoSource); |
3070 } | 2890 } |
3071 if (HasParallelMove()) { | 2891 if (HasParallelMove()) { |
3072 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2892 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
3073 } | 2893 } |
3074 } | 2894 } |
3075 | 2895 |
3076 | |
3077 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, | 2896 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, |
3078 bool optimizing) const { | 2897 bool optimizing) const { |
3079 UNREACHABLE(); | 2898 UNREACHABLE(); |
3080 return NULL; | 2899 return NULL; |
3081 } | 2900 } |
3082 | 2901 |
3083 | |
3084 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2902 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3085 __ Bind(compiler->GetJumpLabel(this)); | 2903 __ Bind(compiler->GetJumpLabel(this)); |
3086 if (!compiler->is_optimizing()) { | 2904 if (!compiler->is_optimizing()) { |
3087 #if !defined(TARGET_ARCH_DBC) | 2905 #if !defined(TARGET_ARCH_DBC) |
3088 // TODO(vegorov) re-enable edge counters on DBC if we consider them | 2906 // TODO(vegorov) re-enable edge counters on DBC if we consider them |
3089 // beneficial for the quality of the optimized bytecode. | 2907 // beneficial for the quality of the optimized bytecode. |
3090 if (compiler->NeedsEdgeCounter(this)) { | 2908 if (compiler->NeedsEdgeCounter(this)) { |
3091 compiler->EmitEdgeCounter(preorder_number()); | 2909 compiler->EmitEdgeCounter(preorder_number()); |
3092 } | 2910 } |
3093 #endif | 2911 #endif |
3094 | 2912 |
3095 // The deoptimization descriptor points after the edge counter code for | 2913 // The deoptimization descriptor points after the edge counter code for |
3096 // uniformity with ARM, where we can reuse pattern matching code that | 2914 // uniformity with ARM, where we can reuse pattern matching code that |
3097 // matches backwards from the end of the pattern. | 2915 // matches backwards from the end of the pattern. |
3098 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), | 2916 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
3099 TokenPosition::kNoSource); | 2917 TokenPosition::kNoSource); |
3100 } | 2918 } |
3101 if (HasParallelMove()) { | 2919 if (HasParallelMove()) { |
3102 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2920 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
3103 } | 2921 } |
3104 } | 2922 } |
3105 | 2923 |
3106 | |
3107 void IndirectGotoInstr::ComputeOffsetTable() { | 2924 void IndirectGotoInstr::ComputeOffsetTable() { |
3108 if (GetBlock()->offset() < 0) { | 2925 if (GetBlock()->offset() < 0) { |
3109 // Don't generate a table when contained in an unreachable block. | 2926 // Don't generate a table when contained in an unreachable block. |
3110 return; | 2927 return; |
3111 } | 2928 } |
3112 ASSERT(SuccessorCount() == offsets_.Length()); | 2929 ASSERT(SuccessorCount() == offsets_.Length()); |
3113 intptr_t element_size = offsets_.ElementSizeInBytes(); | 2930 intptr_t element_size = offsets_.ElementSizeInBytes(); |
3114 for (intptr_t i = 0; i < SuccessorCount(); i++) { | 2931 for (intptr_t i = 0; i < SuccessorCount(); i++) { |
3115 TargetEntryInstr* target = SuccessorAt(i); | 2932 TargetEntryInstr* target = SuccessorAt(i); |
3116 intptr_t offset = target->offset(); | 2933 intptr_t offset = target->offset(); |
(...skipping 13 matching lines...) Expand all Loading... |
3130 ASSERT(ientry != NULL); | 2947 ASSERT(ientry != NULL); |
3131 ASSERT(ientry->indirect_id() == i); | 2948 ASSERT(ientry->indirect_id() == i); |
3132 offset = ientry->offset(); | 2949 offset = ientry->offset(); |
3133 } | 2950 } |
3134 | 2951 |
3135 ASSERT(offset > 0); | 2952 ASSERT(offset > 0); |
3136 offsets_.SetInt32(i * element_size, offset); | 2953 offsets_.SetInt32(i * element_size, offset); |
3137 } | 2954 } |
3138 } | 2955 } |
3139 | 2956 |
3140 | |
3141 LocationSummary* IndirectEntryInstr::MakeLocationSummary( | 2957 LocationSummary* IndirectEntryInstr::MakeLocationSummary( |
3142 Zone* zone, | 2958 Zone* zone, |
3143 bool optimizing) const { | 2959 bool optimizing) const { |
3144 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); | 2960 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); |
3145 } | 2961 } |
3146 | 2962 |
3147 | |
3148 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2963 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3149 JoinEntryInstr::EmitNativeCode(compiler); | 2964 JoinEntryInstr::EmitNativeCode(compiler); |
3150 } | 2965 } |
3151 | 2966 |
3152 | |
3153 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, | 2967 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, |
3154 bool optimizing) const { | 2968 bool optimizing) const { |
3155 UNREACHABLE(); | 2969 UNREACHABLE(); |
3156 return NULL; | 2970 return NULL; |
3157 } | 2971 } |
3158 | 2972 |
3159 | |
3160 void PhiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2973 void PhiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3161 UNREACHABLE(); | 2974 UNREACHABLE(); |
3162 } | 2975 } |
3163 | 2976 |
3164 | |
3165 LocationSummary* RedefinitionInstr::MakeLocationSummary(Zone* zone, | 2977 LocationSummary* RedefinitionInstr::MakeLocationSummary(Zone* zone, |
3166 bool optimizing) const { | 2978 bool optimizing) const { |
3167 UNREACHABLE(); | 2979 UNREACHABLE(); |
3168 return NULL; | 2980 return NULL; |
3169 } | 2981 } |
3170 | 2982 |
3171 | |
3172 void RedefinitionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2983 void RedefinitionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3173 UNREACHABLE(); | 2984 UNREACHABLE(); |
3174 } | 2985 } |
3175 | 2986 |
3176 | |
3177 LocationSummary* ParameterInstr::MakeLocationSummary(Zone* zone, | 2987 LocationSummary* ParameterInstr::MakeLocationSummary(Zone* zone, |
3178 bool optimizing) const { | 2988 bool optimizing) const { |
3179 UNREACHABLE(); | 2989 UNREACHABLE(); |
3180 return NULL; | 2990 return NULL; |
3181 } | 2991 } |
3182 | 2992 |
3183 | |
3184 void ParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2993 void ParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3185 UNREACHABLE(); | 2994 UNREACHABLE(); |
3186 } | 2995 } |
3187 | 2996 |
3188 | |
3189 bool ParallelMoveInstr::IsRedundant() const { | 2997 bool ParallelMoveInstr::IsRedundant() const { |
3190 for (intptr_t i = 0; i < moves_.length(); i++) { | 2998 for (intptr_t i = 0; i < moves_.length(); i++) { |
3191 if (!moves_[i]->IsRedundant()) { | 2999 if (!moves_[i]->IsRedundant()) { |
3192 return false; | 3000 return false; |
3193 } | 3001 } |
3194 } | 3002 } |
3195 return true; | 3003 return true; |
3196 } | 3004 } |
3197 | 3005 |
3198 | |
3199 LocationSummary* ParallelMoveInstr::MakeLocationSummary(Zone* zone, | 3006 LocationSummary* ParallelMoveInstr::MakeLocationSummary(Zone* zone, |
3200 bool optimizing) const { | 3007 bool optimizing) const { |
3201 return NULL; | 3008 return NULL; |
3202 } | 3009 } |
3203 | 3010 |
3204 | |
3205 void ParallelMoveInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3011 void ParallelMoveInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3206 UNREACHABLE(); | 3012 UNREACHABLE(); |
3207 } | 3013 } |
3208 | 3014 |
3209 | |
3210 LocationSummary* ConstraintInstr::MakeLocationSummary(Zone* zone, | 3015 LocationSummary* ConstraintInstr::MakeLocationSummary(Zone* zone, |
3211 bool optimizing) const { | 3016 bool optimizing) const { |
3212 UNREACHABLE(); | 3017 UNREACHABLE(); |
3213 return NULL; | 3018 return NULL; |
3214 } | 3019 } |
3215 | 3020 |
3216 | |
3217 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3021 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3218 UNREACHABLE(); | 3022 UNREACHABLE(); |
3219 } | 3023 } |
3220 | 3024 |
3221 | |
3222 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( | 3025 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( |
3223 Zone* zone, | 3026 Zone* zone, |
3224 bool optimizing) const { | 3027 bool optimizing) const { |
3225 UNREACHABLE(); | 3028 UNREACHABLE(); |
3226 return NULL; | 3029 return NULL; |
3227 } | 3030 } |
3228 | 3031 |
3229 | |
3230 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3032 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3231 UNREACHABLE(); | 3033 UNREACHABLE(); |
3232 } | 3034 } |
3233 | 3035 |
3234 | |
3235 // This function should be kept in sync with | 3036 // This function should be kept in sync with |
3236 // FlowGraphCompiler::SlowPathEnvironmentFor(). | 3037 // FlowGraphCompiler::SlowPathEnvironmentFor(). |
3237 void MaterializeObjectInstr::RemapRegisters(intptr_t* cpu_reg_slots, | 3038 void MaterializeObjectInstr::RemapRegisters(intptr_t* cpu_reg_slots, |
3238 intptr_t* fpu_reg_slots) { | 3039 intptr_t* fpu_reg_slots) { |
3239 if (registers_remapped_) { | 3040 if (registers_remapped_) { |
3240 return; | 3041 return; |
3241 } | 3042 } |
3242 registers_remapped_ = true; | 3043 registers_remapped_ = true; |
3243 | 3044 |
3244 for (intptr_t i = 0; i < InputCount(); i++) { | 3045 for (intptr_t i = 0; i < InputCount(); i++) { |
3245 locations_[i] = LocationAt(i).RemapForSlowPath( | 3046 locations_[i] = LocationAt(i).RemapForSlowPath( |
3246 InputAt(i)->definition(), cpu_reg_slots, fpu_reg_slots); | 3047 InputAt(i)->definition(), cpu_reg_slots, fpu_reg_slots); |
3247 } | 3048 } |
3248 } | 3049 } |
3249 | 3050 |
3250 | |
3251 LocationSummary* SpecialParameterInstr::MakeLocationSummary(Zone* zone, | 3051 LocationSummary* SpecialParameterInstr::MakeLocationSummary(Zone* zone, |
3252 bool opt) const { | 3052 bool opt) const { |
3253 // Only appears in initial definitions, never in normal code. | 3053 // Only appears in initial definitions, never in normal code. |
3254 UNREACHABLE(); | 3054 UNREACHABLE(); |
3255 return NULL; | 3055 return NULL; |
3256 } | 3056 } |
3257 | 3057 |
3258 | |
3259 void SpecialParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3058 void SpecialParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3260 // Only appears in initial definitions, never in normal code. | 3059 // Only appears in initial definitions, never in normal code. |
3261 UNREACHABLE(); | 3060 UNREACHABLE(); |
3262 } | 3061 } |
3263 | 3062 |
3264 | |
3265 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, | 3063 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, |
3266 bool optimizing) const { | 3064 bool optimizing) const { |
3267 return (InputCount() == 1) | 3065 return (InputCount() == 1) |
3268 ? LocationSummary::Make(zone, 1, Location::SameAsFirstInput(), | 3066 ? LocationSummary::Make(zone, 1, Location::SameAsFirstInput(), |
3269 LocationSummary::kNoCall) | 3067 LocationSummary::kNoCall) |
3270 : LocationSummary::Make(zone, 0, Location::NoLocation(), | 3068 : LocationSummary::Make(zone, 0, Location::NoLocation(), |
3271 LocationSummary::kNoCall); | 3069 LocationSummary::kNoCall); |
3272 } | 3070 } |
3273 | 3071 |
3274 | |
3275 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3072 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3276 #if defined(TARGET_ARCH_DBC) | 3073 #if defined(TARGET_ARCH_DBC) |
3277 // On DBC the action of poping the TOS value and then pushing it | 3074 // On DBC the action of poping the TOS value and then pushing it |
3278 // after all intermediates are poped is folded into a special | 3075 // after all intermediates are poped is folded into a special |
3279 // bytecode (DropR). On other architectures this is handled by | 3076 // bytecode (DropR). On other architectures this is handled by |
3280 // instruction prologue/epilogues. | 3077 // instruction prologue/epilogues. |
3281 ASSERT(!compiler->is_optimizing()); | 3078 ASSERT(!compiler->is_optimizing()); |
3282 if ((InputCount() != 0) && HasTemp()) { | 3079 if ((InputCount() != 0) && HasTemp()) { |
3283 __ DropR(num_temps()); | 3080 __ DropR(num_temps()); |
3284 } else { | 3081 } else { |
3285 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); | 3082 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); |
3286 } | 3083 } |
3287 #else | 3084 #else |
3288 ASSERT(!compiler->is_optimizing()); | 3085 ASSERT(!compiler->is_optimizing()); |
3289 // Assert that register assignment is correct. | 3086 // Assert that register assignment is correct. |
3290 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); | 3087 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); |
3291 __ Drop(num_temps()); | 3088 __ Drop(num_temps()); |
3292 #endif // defined(TARGET_ARCH_DBC) | 3089 #endif // defined(TARGET_ARCH_DBC) |
3293 } | 3090 } |
3294 | 3091 |
3295 | |
3296 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, | 3092 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, |
3297 Token::Kind kind, | 3093 Token::Kind kind, |
3298 Value* left, | 3094 Value* left, |
3299 Value* right, | 3095 Value* right, |
3300 bool needs_number_check, | 3096 bool needs_number_check, |
3301 intptr_t deopt_id) | 3097 intptr_t deopt_id) |
3302 : TemplateComparison(token_pos, kind, deopt_id), | 3098 : TemplateComparison(token_pos, kind, deopt_id), |
3303 needs_number_check_(needs_number_check) { | 3099 needs_number_check_(needs_number_check) { |
3304 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); | 3100 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); |
3305 SetInputAt(0, left); | 3101 SetInputAt(0, left); |
3306 SetInputAt(1, right); | 3102 SetInputAt(1, right); |
3307 } | 3103 } |
3308 | 3104 |
3309 | |
3310 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, | 3105 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, |
3311 bool optimizing) const { | 3106 bool optimizing) const { |
3312 return MakeCallSummary(zone); | 3107 return MakeCallSummary(zone); |
3313 } | 3108 } |
3314 | 3109 |
3315 | |
3316 // DBC does not use specialized inline cache stubs for smi operations. | 3110 // DBC does not use specialized inline cache stubs for smi operations. |
3317 #if !defined(TARGET_ARCH_DBC) | 3111 #if !defined(TARGET_ARCH_DBC) |
3318 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { | 3112 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { |
3319 if (!FLAG_two_args_smi_icd) { | 3113 if (!FLAG_two_args_smi_icd) { |
3320 return 0; | 3114 return 0; |
3321 } | 3115 } |
3322 switch (kind) { | 3116 switch (kind) { |
3323 case Token::kADD: | 3117 case Token::kADD: |
3324 return StubCode::SmiAddInlineCache_entry(); | 3118 return StubCode::SmiAddInlineCache_entry(); |
3325 case Token::kSUB: | 3119 case Token::kSUB: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3366 __ BitOrTOS(); | 3160 __ BitOrTOS(); |
3367 } | 3161 } |
3368 } else if (name.raw() == Symbols::Star().raw()) { | 3162 } else if (name.raw() == Symbols::Star().raw()) { |
3369 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3163 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3370 __ MulTOS(); | 3164 __ MulTOS(); |
3371 } | 3165 } |
3372 } | 3166 } |
3373 } | 3167 } |
3374 #endif | 3168 #endif |
3375 | 3169 |
3376 | |
3377 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3170 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3378 Zone* zone = compiler->zone(); | 3171 Zone* zone = compiler->zone(); |
3379 const ICData* call_ic_data = NULL; | 3172 const ICData* call_ic_data = NULL; |
3380 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3173 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
3381 (ic_data() == NULL)) { | 3174 (ic_data() == NULL)) { |
3382 const Array& arguments_descriptor = | 3175 const Array& arguments_descriptor = |
3383 Array::Handle(zone, GetArgumentsDescriptor()); | 3176 Array::Handle(zone, GetArgumentsDescriptor()); |
3384 call_ic_data = compiler->GetOrAddInstanceCallICData( | 3177 call_ic_data = compiler->GetOrAddInstanceCallICData( |
3385 deopt_id(), function_name(), arguments_descriptor, | 3178 deopt_id(), function_name(), arguments_descriptor, |
3386 checked_argument_count()); | 3179 checked_argument_count()); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3457 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, deopt_id(), | 3250 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, deopt_id(), |
3458 token_pos()); | 3251 token_pos()); |
3459 compiler->RecordAfterCall(this, FlowGraphCompiler::kHasResult); | 3252 compiler->RecordAfterCall(this, FlowGraphCompiler::kHasResult); |
3460 | 3253 |
3461 if (compiler->is_optimizing()) { | 3254 if (compiler->is_optimizing()) { |
3462 __ PopLocal(locs()->out(0).reg()); | 3255 __ PopLocal(locs()->out(0).reg()); |
3463 } | 3256 } |
3464 #endif // !defined(TARGET_ARCH_DBC) | 3257 #endif // !defined(TARGET_ARCH_DBC) |
3465 } | 3258 } |
3466 | 3259 |
3467 | |
3468 bool InstanceCallInstr::MatchesCoreName(const String& name) { | 3260 bool InstanceCallInstr::MatchesCoreName(const String& name) { |
3469 return function_name().raw() == Library::PrivateCoreLibName(name).raw(); | 3261 return function_name().raw() == Library::PrivateCoreLibName(name).raw(); |
3470 } | 3262 } |
3471 | 3263 |
3472 | |
3473 RawFunction* InstanceCallInstr::ResolveForReceiverClass(const Class& cls) { | 3264 RawFunction* InstanceCallInstr::ResolveForReceiverClass(const Class& cls) { |
3474 const Array& args_desc_array = Array::Handle(GetArgumentsDescriptor()); | 3265 const Array& args_desc_array = Array::Handle(GetArgumentsDescriptor()); |
3475 ArgumentsDescriptor args_desc(args_desc_array); | 3266 ArgumentsDescriptor args_desc(args_desc_array); |
3476 return Resolver::ResolveDynamicForReceiverClass(cls, function_name(), | 3267 return Resolver::ResolveDynamicForReceiverClass(cls, function_name(), |
3477 args_desc); | 3268 args_desc); |
3478 } | 3269 } |
3479 | 3270 |
3480 | |
3481 bool CallTargets::HasSingleRecognizedTarget() const { | 3271 bool CallTargets::HasSingleRecognizedTarget() const { |
3482 if (!HasSingleTarget()) return false; | 3272 if (!HasSingleTarget()) return false; |
3483 return MethodRecognizer::RecognizeKind(FirstTarget()) != | 3273 return MethodRecognizer::RecognizeKind(FirstTarget()) != |
3484 MethodRecognizer::kUnknown; | 3274 MethodRecognizer::kUnknown; |
3485 } | 3275 } |
3486 | 3276 |
3487 | |
3488 bool CallTargets::HasSingleTarget() const { | 3277 bool CallTargets::HasSingleTarget() const { |
3489 ASSERT(length() != 0); | 3278 ASSERT(length() != 0); |
3490 for (int i = 0; i < length(); i++) { | 3279 for (int i = 0; i < length(); i++) { |
3491 if (TargetAt(i)->target->raw() != TargetAt(0)->target->raw()) return false; | 3280 if (TargetAt(i)->target->raw() != TargetAt(0)->target->raw()) return false; |
3492 } | 3281 } |
3493 return true; | 3282 return true; |
3494 } | 3283 } |
3495 | 3284 |
3496 | |
3497 const Function& CallTargets::FirstTarget() const { | 3285 const Function& CallTargets::FirstTarget() const { |
3498 ASSERT(length() != 0); | 3286 ASSERT(length() != 0); |
3499 ASSERT(TargetAt(0)->target->IsZoneHandle()); | 3287 ASSERT(TargetAt(0)->target->IsZoneHandle()); |
3500 return *TargetAt(0)->target; | 3288 return *TargetAt(0)->target; |
3501 } | 3289 } |
3502 | 3290 |
3503 | |
3504 const Function& CallTargets::MostPopularTarget() const { | 3291 const Function& CallTargets::MostPopularTarget() const { |
3505 ASSERT(length() != 0); | 3292 ASSERT(length() != 0); |
3506 ASSERT(TargetAt(0)->target->IsZoneHandle()); | 3293 ASSERT(TargetAt(0)->target->IsZoneHandle()); |
3507 for (int i = 1; i < length(); i++) { | 3294 for (int i = 1; i < length(); i++) { |
3508 ASSERT(TargetAt(i)->count <= TargetAt(0)->count); | 3295 ASSERT(TargetAt(i)->count <= TargetAt(0)->count); |
3509 } | 3296 } |
3510 return *TargetAt(0)->target; | 3297 return *TargetAt(0)->target; |
3511 } | 3298 } |
3512 | 3299 |
3513 | |
3514 intptr_t CallTargets::AggregateCallCount() const { | 3300 intptr_t CallTargets::AggregateCallCount() const { |
3515 intptr_t sum = 0; | 3301 intptr_t sum = 0; |
3516 for (int i = 0; i < length(); i++) { | 3302 for (int i = 0; i < length(); i++) { |
3517 sum += TargetAt(i)->count; | 3303 sum += TargetAt(i)->count; |
3518 } | 3304 } |
3519 return sum; | 3305 return sum; |
3520 } | 3306 } |
3521 | 3307 |
3522 | |
3523 bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() | 3308 bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() |
3524 const { | 3309 const { |
3525 const intptr_t len = targets_.length(); | 3310 const intptr_t len = targets_.length(); |
3526 Function& target = Function::Handle(); | 3311 Function& target = Function::Handle(); |
3527 for (intptr_t i = 0; i < len; i++) { | 3312 for (intptr_t i = 0; i < len; i++) { |
3528 target ^= targets_.TargetAt(i)->target->raw(); | 3313 target ^= targets_.TargetAt(i)->target->raw(); |
3529 if (!target.IsDispatcherOrImplicitAccessor()) { | 3314 if (!target.IsDispatcherOrImplicitAccessor()) { |
3530 return false; | 3315 return false; |
3531 } | 3316 } |
3532 } | 3317 } |
3533 return true; | 3318 return true; |
3534 } | 3319 } |
3535 | 3320 |
3536 | |
3537 intptr_t PolymorphicInstanceCallInstr::CallCount() const { | 3321 intptr_t PolymorphicInstanceCallInstr::CallCount() const { |
3538 return targets().AggregateCallCount(); | 3322 return targets().AggregateCallCount(); |
3539 } | 3323 } |
3540 | 3324 |
3541 | |
3542 // DBC does not support optimizing compiler and thus doesn't emit | 3325 // DBC does not support optimizing compiler and thus doesn't emit |
3543 // PolymorphicInstanceCallInstr. | 3326 // PolymorphicInstanceCallInstr. |
3544 #if !defined(TARGET_ARCH_DBC) | 3327 #if !defined(TARGET_ARCH_DBC) |
3545 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3328 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3546 ArgumentsInfo args_info(instance_call()->type_args_len(), | 3329 ArgumentsInfo args_info(instance_call()->type_args_len(), |
3547 instance_call()->ArgumentCount(), | 3330 instance_call()->ArgumentCount(), |
3548 instance_call()->argument_names()); | 3331 instance_call()->argument_names()); |
3549 compiler->EmitPolymorphicInstanceCall( | 3332 compiler->EmitPolymorphicInstanceCall( |
3550 targets_, *instance_call(), args_info, deopt_id(), | 3333 targets_, *instance_call(), args_info, deopt_id(), |
3551 instance_call()->token_pos(), locs(), complete(), total_call_count()); | 3334 instance_call()->token_pos(), locs(), complete(), total_call_count()); |
3552 } | 3335 } |
3553 #endif | 3336 #endif |
3554 | 3337 |
3555 | |
3556 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( | 3338 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
3557 const CallTargets& targets) { | 3339 const CallTargets& targets) { |
3558 bool is_string = true; | 3340 bool is_string = true; |
3559 bool is_integer = true; | 3341 bool is_integer = true; |
3560 bool is_double = true; | 3342 bool is_double = true; |
3561 | 3343 |
3562 const intptr_t num_checks = targets.length(); | 3344 const intptr_t num_checks = targets.length(); |
3563 for (intptr_t i = 0; i < num_checks; i++) { | 3345 for (intptr_t i = 0; i < num_checks; i++) { |
3564 ASSERT(targets.TargetAt(i)->target->raw() == | 3346 ASSERT(targets.TargetAt(i)->target->raw() == |
3565 targets.TargetAt(0)->target->raw()); | 3347 targets.TargetAt(0)->target->raw()); |
(...skipping 13 matching lines...) Expand all Loading... |
3579 } else if (is_integer) { | 3361 } else if (is_integer) { |
3580 ASSERT(!is_double); | 3362 ASSERT(!is_double); |
3581 return Type::IntType(); | 3363 return Type::IntType(); |
3582 } else if (is_double) { | 3364 } else if (is_double) { |
3583 return Type::Double(); | 3365 return Type::Double(); |
3584 } | 3366 } |
3585 | 3367 |
3586 return Type::null(); | 3368 return Type::null(); |
3587 } | 3369 } |
3588 | 3370 |
3589 | |
3590 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3371 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
3591 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); | 3372 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); |
3592 | 3373 |
3593 // TODO(erikcorry): Even for cold call sites we could still try to look up | 3374 // TODO(erikcorry): Even for cold call sites we could still try to look up |
3594 // methods when we know the receiver cid. We don't currently do this because | 3375 // methods when we know the receiver cid. We don't currently do this because |
3595 // it turns the InstanceCall into a PolymorphicInstanceCall which doesn't get | 3376 // it turns the InstanceCall into a PolymorphicInstanceCall which doesn't get |
3596 // recognized or inlined when it is cold. | 3377 // recognized or inlined when it is cold. |
3597 if (ic_data()->NumberOfUsedChecks() == 0) return this; | 3378 if (ic_data()->NumberOfUsedChecks() == 0) return this; |
3598 | 3379 |
3599 const CallTargets* new_target = | 3380 const CallTargets* new_target = |
3600 FlowGraphCompiler::ResolveCallTargetsForReceiverCid( | 3381 FlowGraphCompiler::ResolveCallTargetsForReceiverCid( |
3601 receiver_cid, | 3382 receiver_cid, |
3602 String::Handle(flow_graph->zone(), ic_data()->target_name()), | 3383 String::Handle(flow_graph->zone(), ic_data()->target_name()), |
3603 Array::Handle(flow_graph->zone(), ic_data()->arguments_descriptor())); | 3384 Array::Handle(flow_graph->zone(), ic_data()->arguments_descriptor())); |
3604 if (new_target == NULL) { | 3385 if (new_target == NULL) { |
3605 // No specialization. | 3386 // No specialization. |
3606 return this; | 3387 return this; |
3607 } | 3388 } |
3608 | 3389 |
3609 ASSERT(new_target->HasSingleTarget()); | 3390 ASSERT(new_target->HasSingleTarget()); |
3610 const Function& target = new_target->FirstTarget(); | 3391 const Function& target = new_target->FirstTarget(); |
3611 StaticCallInstr* specialized = | 3392 StaticCallInstr* specialized = |
3612 StaticCallInstr::FromCall(flow_graph->zone(), this, target); | 3393 StaticCallInstr::FromCall(flow_graph->zone(), this, target); |
3613 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); | 3394 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); |
3614 return specialized; | 3395 return specialized; |
3615 } | 3396 } |
3616 | 3397 |
3617 | |
3618 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3398 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
3619 if (!IsSureToCallSingleRecognizedTarget()) { | 3399 if (!IsSureToCallSingleRecognizedTarget()) { |
3620 return this; | 3400 return this; |
3621 } | 3401 } |
3622 | 3402 |
3623 const Function& target = targets().FirstTarget(); | 3403 const Function& target = targets().FirstTarget(); |
3624 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { | 3404 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
3625 const AbstractType& type = | 3405 const AbstractType& type = |
3626 AbstractType::Handle(ComputeRuntimeType(targets_)); | 3406 AbstractType::Handle(ComputeRuntimeType(targets_)); |
3627 if (!type.IsNull()) { | 3407 if (!type.IsNull()) { |
3628 return flow_graph->GetConstant(type); | 3408 return flow_graph->GetConstant(type); |
3629 } | 3409 } |
3630 } | 3410 } |
3631 | 3411 |
3632 return this; | 3412 return this; |
3633 } | 3413 } |
3634 | 3414 |
3635 | |
3636 bool PolymorphicInstanceCallInstr::IsSureToCallSingleRecognizedTarget() const { | 3415 bool PolymorphicInstanceCallInstr::IsSureToCallSingleRecognizedTarget() const { |
3637 if (FLAG_precompiled_mode && !complete()) return false; | 3416 if (FLAG_precompiled_mode && !complete()) return false; |
3638 return targets_.HasSingleRecognizedTarget(); | 3417 return targets_.HasSingleRecognizedTarget(); |
3639 } | 3418 } |
3640 | 3419 |
3641 | |
3642 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3420 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) { |
3643 if (!FLAG_precompiled_mode) { | 3421 if (!FLAG_precompiled_mode) { |
3644 return this; | 3422 return this; |
3645 } | 3423 } |
3646 | 3424 |
3647 if (function().recognized_kind() == MethodRecognizer::kObjectRuntimeType) { | 3425 if (function().recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
3648 if (input_use_list() == NULL) { | 3426 if (input_use_list() == NULL) { |
3649 // This function has only environment uses. In precompiled mode it is | 3427 // This function has only environment uses. In precompiled mode it is |
3650 // fine to remove it - because we will never deoptimize. | 3428 // fine to remove it - because we will never deoptimize. |
3651 return flow_graph->constant_dead(); | 3429 return flow_graph->constant_dead(); |
3652 } | 3430 } |
3653 } | 3431 } |
3654 | 3432 |
3655 return this; | 3433 return this; |
3656 } | 3434 } |
3657 | 3435 |
3658 | |
3659 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, | 3436 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, |
3660 bool optimizing) const { | 3437 bool optimizing) const { |
3661 return MakeCallSummary(zone); | 3438 return MakeCallSummary(zone); |
3662 } | 3439 } |
3663 | 3440 |
3664 | |
3665 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3441 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3666 Zone* zone = compiler->zone(); | 3442 Zone* zone = compiler->zone(); |
3667 const ICData* call_ic_data = NULL; | 3443 const ICData* call_ic_data = NULL; |
3668 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3444 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
3669 (ic_data() == NULL)) { | 3445 (ic_data() == NULL)) { |
3670 const Array& arguments_descriptor = | 3446 const Array& arguments_descriptor = |
3671 Array::Handle(zone, GetArgumentsDescriptor()); | 3447 Array::Handle(zone, GetArgumentsDescriptor()); |
3672 MethodRecognizer::Kind recognized_kind = | 3448 MethodRecognizer::Kind recognized_kind = |
3673 MethodRecognizer::RecognizeKind(function()); | 3449 MethodRecognizer::RecognizeKind(function()); |
3674 int num_args_checked = 0; | 3450 int num_args_checked = 0; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3710 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); | 3486 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); |
3711 __ PushConstant(ic_data_kidx); | 3487 __ PushConstant(ic_data_kidx); |
3712 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); | 3488 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); |
3713 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, | 3489 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, |
3714 deopt_id(), token_pos()); | 3490 deopt_id(), token_pos()); |
3715 compiler->RecordAfterCall(this, FlowGraphCompiler::kHasResult); | 3491 compiler->RecordAfterCall(this, FlowGraphCompiler::kHasResult); |
3716 } | 3492 } |
3717 #endif // !defined(TARGET_ARCH_DBC) | 3493 #endif // !defined(TARGET_ARCH_DBC) |
3718 } | 3494 } |
3719 | 3495 |
3720 | |
3721 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3496 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3722 compiler->GenerateAssertAssignable(token_pos(), deopt_id(), dst_type(), | 3497 compiler->GenerateAssertAssignable(token_pos(), deopt_id(), dst_type(), |
3723 dst_name(), locs()); | 3498 dst_name(), locs()); |
3724 | 3499 |
3725 // DBC does not use LocationSummaries in the same way as other architectures. | 3500 // DBC does not use LocationSummaries in the same way as other architectures. |
3726 #if !defined(TARGET_ARCH_DBC) | 3501 #if !defined(TARGET_ARCH_DBC) |
3727 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); | 3502 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); |
3728 #endif // !defined(TARGET_ARCH_DBC) | 3503 #endif // !defined(TARGET_ARCH_DBC) |
3729 } | 3504 } |
3730 | 3505 |
3731 | |
3732 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, | 3506 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, |
3733 bool opt) const { | 3507 bool opt) const { |
3734 return new (zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); | 3508 return new (zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); |
3735 } | 3509 } |
3736 | 3510 |
3737 | |
3738 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3511 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3739 #if !defined(TARGET_ARCH_DBC) | 3512 #if !defined(TARGET_ARCH_DBC) |
3740 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | 3513 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); |
3741 #else | 3514 #else |
3742 compiler->EmitDeopt(deopt_id(), deopt_reason_); | 3515 compiler->EmitDeopt(deopt_id(), deopt_reason_); |
3743 #endif | 3516 #endif |
3744 } | 3517 } |
3745 | 3518 |
3746 | |
3747 #if !defined(TARGET_ARCH_DBC) | 3519 #if !defined(TARGET_ARCH_DBC) |
3748 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3520 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3749 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass, | 3521 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass, |
3750 licm_hoisted_ ? ICData::kHoisted : 0); | 3522 licm_hoisted_ ? ICData::kHoisted : 0); |
3751 if (IsNullCheck()) { | 3523 if (IsNullCheck()) { |
3752 EmitNullCheck(compiler, deopt); | 3524 EmitNullCheck(compiler, deopt); |
3753 return; | 3525 return; |
3754 } | 3526 } |
3755 | 3527 |
3756 ASSERT(!cids_.IsMonomorphic() || !cids_.HasClassId(kSmiCid)); | 3528 ASSERT(!cids_.IsMonomorphic() || !cids_.HasClassId(kSmiCid)); |
(...skipping 26 matching lines...) Expand all Loading... |
3783 (i == num_checks - 2 && cids_[i + 1].cid_start == kSmiCid && | 3555 (i == num_checks - 2 && cids_[i + 1].cid_start == kSmiCid && |
3784 cids_[i + 1].cid_end == kSmiCid); | 3556 cids_[i + 1].cid_end == kSmiCid); |
3785 bias = EmitCheckCid(compiler, bias, cid_start, cid_end, is_last, &is_ok, | 3557 bias = EmitCheckCid(compiler, bias, cid_start, cid_end, is_last, &is_ok, |
3786 deopt, use_near_jump); | 3558 deopt, use_near_jump); |
3787 } | 3559 } |
3788 } | 3560 } |
3789 __ Bind(&is_ok); | 3561 __ Bind(&is_ok); |
3790 } | 3562 } |
3791 #endif | 3563 #endif |
3792 | 3564 |
3793 | |
3794 Environment* Environment::From(Zone* zone, | 3565 Environment* Environment::From(Zone* zone, |
3795 const GrowableArray<Definition*>& definitions, | 3566 const GrowableArray<Definition*>& definitions, |
3796 intptr_t fixed_parameter_count, | 3567 intptr_t fixed_parameter_count, |
3797 const ParsedFunction& parsed_function) { | 3568 const ParsedFunction& parsed_function) { |
3798 Environment* env = | 3569 Environment* env = |
3799 new (zone) Environment(definitions.length(), fixed_parameter_count, | 3570 new (zone) Environment(definitions.length(), fixed_parameter_count, |
3800 Thread::kNoDeoptId, parsed_function, NULL); | 3571 Thread::kNoDeoptId, parsed_function, NULL); |
3801 for (intptr_t i = 0; i < definitions.length(); ++i) { | 3572 for (intptr_t i = 0; i < definitions.length(); ++i) { |
3802 env->values_.Add(new (zone) Value(definitions[i])); | 3573 env->values_.Add(new (zone) Value(definitions[i])); |
3803 } | 3574 } |
3804 return env; | 3575 return env; |
3805 } | 3576 } |
3806 | 3577 |
3807 | |
3808 void Environment::PushValue(Value* value) { | 3578 void Environment::PushValue(Value* value) { |
3809 values_.Add(value); | 3579 values_.Add(value); |
3810 } | 3580 } |
3811 | 3581 |
3812 | |
3813 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { | 3582 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { |
3814 ASSERT(length <= values_.length()); | 3583 ASSERT(length <= values_.length()); |
3815 Environment* copy = new (zone) | 3584 Environment* copy = new (zone) |
3816 Environment(length, fixed_parameter_count_, deopt_id_, parsed_function_, | 3585 Environment(length, fixed_parameter_count_, deopt_id_, parsed_function_, |
3817 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); | 3586 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); |
3818 if (locations_ != NULL) { | 3587 if (locations_ != NULL) { |
3819 Location* new_locations = zone->Alloc<Location>(length); | 3588 Location* new_locations = zone->Alloc<Location>(length); |
3820 copy->set_locations(new_locations); | 3589 copy->set_locations(new_locations); |
3821 } | 3590 } |
3822 for (intptr_t i = 0; i < length; ++i) { | 3591 for (intptr_t i = 0; i < length; ++i) { |
3823 copy->values_.Add(values_[i]->Copy(zone)); | 3592 copy->values_.Add(values_[i]->Copy(zone)); |
3824 if (locations_ != NULL) { | 3593 if (locations_ != NULL) { |
3825 copy->locations_[i] = locations_[i].Copy(); | 3594 copy->locations_[i] = locations_[i].Copy(); |
3826 } | 3595 } |
3827 } | 3596 } |
3828 return copy; | 3597 return copy; |
3829 } | 3598 } |
3830 | 3599 |
3831 | |
3832 // Copies the environment and updates the environment use lists. | 3600 // Copies the environment and updates the environment use lists. |
3833 void Environment::DeepCopyTo(Zone* zone, Instruction* instr) const { | 3601 void Environment::DeepCopyTo(Zone* zone, Instruction* instr) const { |
3834 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | 3602 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
3835 it.CurrentValue()->RemoveFromUseList(); | 3603 it.CurrentValue()->RemoveFromUseList(); |
3836 } | 3604 } |
3837 | 3605 |
3838 Environment* copy = DeepCopy(zone); | 3606 Environment* copy = DeepCopy(zone); |
3839 instr->SetEnvironment(copy); | 3607 instr->SetEnvironment(copy); |
3840 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 3608 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
3841 Value* value = it.CurrentValue(); | 3609 Value* value = it.CurrentValue(); |
3842 value->definition()->AddEnvUse(value); | 3610 value->definition()->AddEnvUse(value); |
3843 } | 3611 } |
3844 } | 3612 } |
3845 | 3613 |
3846 | |
3847 void Environment::DeepCopyAfterTo(Zone* zone, | 3614 void Environment::DeepCopyAfterTo(Zone* zone, |
3848 Instruction* instr, | 3615 Instruction* instr, |
3849 intptr_t argc, | 3616 intptr_t argc, |
3850 Definition* dead, | 3617 Definition* dead, |
3851 Definition* result) const { | 3618 Definition* result) const { |
3852 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | 3619 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
3853 it.CurrentValue()->RemoveFromUseList(); | 3620 it.CurrentValue()->RemoveFromUseList(); |
3854 } | 3621 } |
3855 | 3622 |
3856 Environment* copy = DeepCopy(zone, values_.length() - argc); | 3623 Environment* copy = DeepCopy(zone, values_.length() - argc); |
3857 for (intptr_t i = 0; i < argc; i++) { | 3624 for (intptr_t i = 0; i < argc; i++) { |
3858 copy->values_.Add(new (zone) Value(dead)); | 3625 copy->values_.Add(new (zone) Value(dead)); |
3859 } | 3626 } |
3860 copy->values_.Add(new (zone) Value(result)); | 3627 copy->values_.Add(new (zone) Value(result)); |
3861 | 3628 |
3862 instr->SetEnvironment(copy); | 3629 instr->SetEnvironment(copy); |
3863 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 3630 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
3864 Value* value = it.CurrentValue(); | 3631 Value* value = it.CurrentValue(); |
3865 value->definition()->AddEnvUse(value); | 3632 value->definition()->AddEnvUse(value); |
3866 } | 3633 } |
3867 } | 3634 } |
3868 | 3635 |
3869 | |
3870 // Copies the environment as outer on an inlined instruction and updates the | 3636 // Copies the environment as outer on an inlined instruction and updates the |
3871 // environment use lists. | 3637 // environment use lists. |
3872 void Environment::DeepCopyToOuter(Zone* zone, Instruction* instr) const { | 3638 void Environment::DeepCopyToOuter(Zone* zone, Instruction* instr) const { |
3873 // Create a deep copy removing caller arguments from the environment. | 3639 // Create a deep copy removing caller arguments from the environment. |
3874 ASSERT(this != NULL); | 3640 ASSERT(this != NULL); |
3875 ASSERT(instr->env()->outer() == NULL); | 3641 ASSERT(instr->env()->outer() == NULL); |
3876 intptr_t argument_count = instr->env()->fixed_parameter_count(); | 3642 intptr_t argument_count = instr->env()->fixed_parameter_count(); |
3877 Environment* copy = DeepCopy(zone, values_.length() - argument_count); | 3643 Environment* copy = DeepCopy(zone, values_.length() - argument_count); |
3878 instr->env()->outer_ = copy; | 3644 instr->env()->outer_ = copy; |
3879 intptr_t use_index = instr->env()->Length(); // Start index after inner. | 3645 intptr_t use_index = instr->env()->Length(); // Start index after inner. |
3880 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 3646 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
3881 Value* value = it.CurrentValue(); | 3647 Value* value = it.CurrentValue(); |
3882 value->set_instruction(instr); | 3648 value->set_instruction(instr); |
3883 value->set_use_index(use_index++); | 3649 value->set_use_index(use_index++); |
3884 value->definition()->AddEnvUse(value); | 3650 value->definition()->AddEnvUse(value); |
3885 } | 3651 } |
3886 } | 3652 } |
3887 | 3653 |
3888 | |
3889 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, | 3654 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, |
3890 Value* new_right) { | 3655 Value* new_right) { |
3891 UNREACHABLE(); | 3656 UNREACHABLE(); |
3892 return NULL; | 3657 return NULL; |
3893 } | 3658 } |
3894 | 3659 |
3895 | |
3896 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, | 3660 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, |
3897 Value* new_right) { | 3661 Value* new_right) { |
3898 return new EqualityCompareInstr(token_pos(), kind(), new_left, new_right, | 3662 return new EqualityCompareInstr(token_pos(), kind(), new_left, new_right, |
3899 operation_cid(), deopt_id()); | 3663 operation_cid(), deopt_id()); |
3900 } | 3664 } |
3901 | 3665 |
3902 | |
3903 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, | 3666 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, |
3904 Value* new_right) { | 3667 Value* new_right) { |
3905 return new RelationalOpInstr(token_pos(), kind(), new_left, new_right, | 3668 return new RelationalOpInstr(token_pos(), kind(), new_left, new_right, |
3906 operation_cid(), deopt_id()); | 3669 operation_cid(), deopt_id()); |
3907 } | 3670 } |
3908 | 3671 |
3909 | |
3910 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, | 3672 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, |
3911 Value* new_right) { | 3673 Value* new_right) { |
3912 return new StrictCompareInstr(token_pos(), kind(), new_left, new_right, | 3674 return new StrictCompareInstr(token_pos(), kind(), new_left, new_right, |
3913 needs_number_check(), Thread::kNoDeoptId); | 3675 needs_number_check(), Thread::kNoDeoptId); |
3914 } | 3676 } |
3915 | 3677 |
3916 | |
3917 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, | 3678 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, |
3918 Value* new_right) { | 3679 Value* new_right) { |
3919 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); | 3680 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); |
3920 } | 3681 } |
3921 | 3682 |
3922 | |
3923 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, | 3683 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, |
3924 Value* new_right) { | 3684 Value* new_right) { |
3925 return new TestCidsInstr(token_pos(), kind(), new_left, cid_results(), | 3685 return new TestCidsInstr(token_pos(), kind(), new_left, cid_results(), |
3926 deopt_id()); | 3686 deopt_id()); |
3927 } | 3687 } |
3928 | 3688 |
3929 | |
3930 bool TestCidsInstr::AttributesEqual(Instruction* other) const { | 3689 bool TestCidsInstr::AttributesEqual(Instruction* other) const { |
3931 TestCidsInstr* other_instr = other->AsTestCids(); | 3690 TestCidsInstr* other_instr = other->AsTestCids(); |
3932 if (!ComparisonInstr::AttributesEqual(other)) { | 3691 if (!ComparisonInstr::AttributesEqual(other)) { |
3933 return false; | 3692 return false; |
3934 } | 3693 } |
3935 if (cid_results().length() != other_instr->cid_results().length()) { | 3694 if (cid_results().length() != other_instr->cid_results().length()) { |
3936 return false; | 3695 return false; |
3937 } | 3696 } |
3938 for (intptr_t i = 0; i < cid_results().length(); i++) { | 3697 for (intptr_t i = 0; i < cid_results().length(); i++) { |
3939 if (cid_results()[i] != other_instr->cid_results()[i]) { | 3698 if (cid_results()[i] != other_instr->cid_results()[i]) { |
3940 return false; | 3699 return false; |
3941 } | 3700 } |
3942 } | 3701 } |
3943 return true; | 3702 return true; |
3944 } | 3703 } |
3945 | 3704 |
3946 | |
3947 #if !defined(TARGET_ARCH_DBC) | 3705 #if !defined(TARGET_ARCH_DBC) |
3948 static bool BindsToSmiConstant(Value* value) { | 3706 static bool BindsToSmiConstant(Value* value) { |
3949 return value->BindsToConstant() && value->BoundConstant().IsSmi(); | 3707 return value->BindsToConstant() && value->BoundConstant().IsSmi(); |
3950 } | 3708 } |
3951 #endif | 3709 #endif |
3952 | 3710 |
3953 | |
3954 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | 3711 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
3955 Value* v1, | 3712 Value* v1, |
3956 Value* v2) { | 3713 Value* v2) { |
3957 #if !defined(TARGET_ARCH_DBC) | 3714 #if !defined(TARGET_ARCH_DBC) |
3958 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); | 3715 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); |
3959 if (comparison->IsStrictCompare()) { | 3716 if (comparison->IsStrictCompare()) { |
3960 // Strict comparison with number checks calls a stub and is not supported | 3717 // Strict comparison with number checks calls a stub and is not supported |
3961 // by if-conversion. | 3718 // by if-conversion. |
3962 return is_smi_result && | 3719 return is_smi_result && |
3963 !comparison->AsStrictCompare()->needs_number_check(); | 3720 !comparison->AsStrictCompare()->needs_number_check(); |
3964 } | 3721 } |
3965 if (comparison->operation_cid() != kSmiCid) { | 3722 if (comparison->operation_cid() != kSmiCid) { |
3966 // Non-smi comparisons are not supported by if-conversion. | 3723 // Non-smi comparisons are not supported by if-conversion. |
3967 return false; | 3724 return false; |
3968 } | 3725 } |
3969 return is_smi_result; | 3726 return is_smi_result; |
3970 #else | 3727 #else |
3971 return false; | 3728 return false; |
3972 #endif // !defined(TARGET_ARCH_DBC) | 3729 #endif // !defined(TARGET_ARCH_DBC) |
3973 } | 3730 } |
3974 | 3731 |
3975 | |
3976 bool PhiInstr::IsRedundant() const { | 3732 bool PhiInstr::IsRedundant() const { |
3977 ASSERT(InputCount() > 1); | 3733 ASSERT(InputCount() > 1); |
3978 Definition* first = InputAt(0)->definition(); | 3734 Definition* first = InputAt(0)->definition(); |
3979 for (intptr_t i = 1; i < InputCount(); ++i) { | 3735 for (intptr_t i = 1; i < InputCount(); ++i) { |
3980 Definition* def = InputAt(i)->definition(); | 3736 Definition* def = InputAt(i)->definition(); |
3981 if (def != first) return false; | 3737 if (def != first) return false; |
3982 } | 3738 } |
3983 return true; | 3739 return true; |
3984 } | 3740 } |
3985 | 3741 |
3986 | |
3987 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3742 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
3988 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3743 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
3989 } | 3744 } |
3990 | 3745 |
3991 | |
3992 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { | 3746 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { |
3993 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) | 3747 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) |
3994 ? NULL | 3748 ? NULL |
3995 : this; | 3749 : this; |
3996 } | 3750 } |
3997 | 3751 |
3998 | |
3999 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { | 3752 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { |
4000 if (RawObject::IsExternalTypedDataClassId(class_id)) { | 3753 if (RawObject::IsExternalTypedDataClassId(class_id)) { |
4001 return ExternalTypedData::length_offset(); | 3754 return ExternalTypedData::length_offset(); |
4002 } | 3755 } |
4003 if (RawObject::IsTypedDataClassId(class_id)) { | 3756 if (RawObject::IsTypedDataClassId(class_id)) { |
4004 return TypedData::length_offset(); | 3757 return TypedData::length_offset(); |
4005 } | 3758 } |
4006 switch (class_id) { | 3759 switch (class_id) { |
4007 case kGrowableObjectArrayCid: | 3760 case kGrowableObjectArrayCid: |
4008 return GrowableObjectArray::length_offset(); | 3761 return GrowableObjectArray::length_offset(); |
4009 case kOneByteStringCid: | 3762 case kOneByteStringCid: |
4010 case kTwoByteStringCid: | 3763 case kTwoByteStringCid: |
4011 return String::length_offset(); | 3764 return String::length_offset(); |
4012 case kArrayCid: | 3765 case kArrayCid: |
4013 case kImmutableArrayCid: | 3766 case kImmutableArrayCid: |
4014 return Array::length_offset(); | 3767 return Array::length_offset(); |
4015 default: | 3768 default: |
4016 UNREACHABLE(); | 3769 UNREACHABLE(); |
4017 return -1; | 3770 return -1; |
4018 } | 3771 } |
4019 } | 3772 } |
4020 | 3773 |
4021 | |
4022 const Function& StringInterpolateInstr::CallFunction() const { | 3774 const Function& StringInterpolateInstr::CallFunction() const { |
4023 if (function_.IsNull()) { | 3775 if (function_.IsNull()) { |
4024 const int kTypeArgsLen = 0; | 3776 const int kTypeArgsLen = 0; |
4025 const int kNumberOfArguments = 1; | 3777 const int kNumberOfArguments = 1; |
4026 const Array& kNoArgumentNames = Object::null_array(); | 3778 const Array& kNoArgumentNames = Object::null_array(); |
4027 const Class& cls = | 3779 const Class& cls = |
4028 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); | 3780 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); |
4029 ASSERT(!cls.IsNull()); | 3781 ASSERT(!cls.IsNull()); |
4030 function_ = Resolver::ResolveStatic( | 3782 function_ = Resolver::ResolveStatic( |
4031 cls, Library::PrivateCoreLibName(Symbols::Interpolate()), kTypeArgsLen, | 3783 cls, Library::PrivateCoreLibName(Symbols::Interpolate()), kTypeArgsLen, |
4032 kNumberOfArguments, kNoArgumentNames); | 3784 kNumberOfArguments, kNoArgumentNames); |
4033 } | 3785 } |
4034 ASSERT(!function_.IsNull()); | 3786 ASSERT(!function_.IsNull()); |
4035 return function_; | 3787 return function_; |
4036 } | 3788 } |
4037 | 3789 |
4038 | |
4039 // Replace StringInterpolateInstr with a constant string if all inputs are | 3790 // Replace StringInterpolateInstr with a constant string if all inputs are |
4040 // constant of [string, number, boolean, null]. | 3791 // constant of [string, number, boolean, null]. |
4041 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case | 3792 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case |
4042 // deoptimization occurs. | 3793 // deoptimization occurs. |
4043 Definition* StringInterpolateInstr::Canonicalize(FlowGraph* flow_graph) { | 3794 Definition* StringInterpolateInstr::Canonicalize(FlowGraph* flow_graph) { |
4044 // The following graph structure is generated by the graph builder: | 3795 // The following graph structure is generated by the graph builder: |
4045 // v2 <- CreateArray(v0) | 3796 // v2 <- CreateArray(v0) |
4046 // StoreIndexed(v2, v3, v4) -- v3:constant index, v4: value. | 3797 // StoreIndexed(v2, v3, v4) -- v3:constant index, v4: value. |
4047 // .. | 3798 // .. |
4048 // v8 <- StringInterpolate(v2) | 3799 // v8 <- StringInterpolate(v2) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4102 } else { | 3853 } else { |
4103 return this; | 3854 return this; |
4104 } | 3855 } |
4105 } | 3856 } |
4106 | 3857 |
4107 const String& concatenated = | 3858 const String& concatenated = |
4108 String::ZoneHandle(zone, Symbols::FromConcatAll(thread, pieces)); | 3859 String::ZoneHandle(zone, Symbols::FromConcatAll(thread, pieces)); |
4109 return flow_graph->GetConstant(concatenated); | 3860 return flow_graph->GetConstant(concatenated); |
4110 } | 3861 } |
4111 | 3862 |
4112 | |
4113 static AlignmentType StrengthenAlignment(intptr_t cid, | 3863 static AlignmentType StrengthenAlignment(intptr_t cid, |
4114 AlignmentType alignment) { | 3864 AlignmentType alignment) { |
4115 switch (cid) { | 3865 switch (cid) { |
4116 case kTypedDataInt8ArrayCid: | 3866 case kTypedDataInt8ArrayCid: |
4117 case kTypedDataUint8ArrayCid: | 3867 case kTypedDataUint8ArrayCid: |
4118 case kTypedDataUint8ClampedArrayCid: | 3868 case kTypedDataUint8ClampedArrayCid: |
4119 case kExternalTypedDataUint8ArrayCid: | 3869 case kExternalTypedDataUint8ArrayCid: |
4120 case kExternalTypedDataUint8ClampedArrayCid: | 3870 case kExternalTypedDataUint8ClampedArrayCid: |
4121 case kOneByteStringCid: | 3871 case kOneByteStringCid: |
4122 case kExternalOneByteStringCid: | 3872 case kExternalOneByteStringCid: |
4123 // Don't need to worry about alignment for accessing bytes. | 3873 // Don't need to worry about alignment for accessing bytes. |
4124 return kAlignedAccess; | 3874 return kAlignedAccess; |
4125 case kTypedDataFloat64x2ArrayCid: | 3875 case kTypedDataFloat64x2ArrayCid: |
4126 case kTypedDataInt32x4ArrayCid: | 3876 case kTypedDataInt32x4ArrayCid: |
4127 case kTypedDataFloat32x4ArrayCid: | 3877 case kTypedDataFloat32x4ArrayCid: |
4128 // TODO(rmacnak): Investigate alignment requirements of floating point | 3878 // TODO(rmacnak): Investigate alignment requirements of floating point |
4129 // loads. | 3879 // loads. |
4130 return kAlignedAccess; | 3880 return kAlignedAccess; |
4131 } | 3881 } |
4132 | 3882 |
4133 return alignment; | 3883 return alignment; |
4134 } | 3884 } |
4135 | 3885 |
4136 | |
4137 LoadIndexedInstr::LoadIndexedInstr(Value* array, | 3886 LoadIndexedInstr::LoadIndexedInstr(Value* array, |
4138 Value* index, | 3887 Value* index, |
4139 intptr_t index_scale, | 3888 intptr_t index_scale, |
4140 intptr_t class_id, | 3889 intptr_t class_id, |
4141 AlignmentType alignment, | 3890 AlignmentType alignment, |
4142 intptr_t deopt_id, | 3891 intptr_t deopt_id, |
4143 TokenPosition token_pos) | 3892 TokenPosition token_pos) |
4144 : TemplateDefinition(deopt_id), | 3893 : TemplateDefinition(deopt_id), |
4145 index_scale_(index_scale), | 3894 index_scale_(index_scale), |
4146 class_id_(class_id), | 3895 class_id_(class_id), |
4147 alignment_(StrengthenAlignment(class_id, alignment)), | 3896 alignment_(StrengthenAlignment(class_id, alignment)), |
4148 token_pos_(token_pos) { | 3897 token_pos_(token_pos) { |
4149 SetInputAt(0, array); | 3898 SetInputAt(0, array); |
4150 SetInputAt(1, index); | 3899 SetInputAt(1, index); |
4151 } | 3900 } |
4152 | 3901 |
4153 | |
4154 StoreIndexedInstr::StoreIndexedInstr(Value* array, | 3902 StoreIndexedInstr::StoreIndexedInstr(Value* array, |
4155 Value* index, | 3903 Value* index, |
4156 Value* value, | 3904 Value* value, |
4157 StoreBarrierType emit_store_barrier, | 3905 StoreBarrierType emit_store_barrier, |
4158 intptr_t index_scale, | 3906 intptr_t index_scale, |
4159 intptr_t class_id, | 3907 intptr_t class_id, |
4160 AlignmentType alignment, | 3908 AlignmentType alignment, |
4161 intptr_t deopt_id, | 3909 intptr_t deopt_id, |
4162 TokenPosition token_pos) | 3910 TokenPosition token_pos) |
4163 : TemplateDefinition(deopt_id), | 3911 : TemplateDefinition(deopt_id), |
4164 emit_store_barrier_(emit_store_barrier), | 3912 emit_store_barrier_(emit_store_barrier), |
4165 index_scale_(index_scale), | 3913 index_scale_(index_scale), |
4166 class_id_(class_id), | 3914 class_id_(class_id), |
4167 alignment_(StrengthenAlignment(class_id, alignment)), | 3915 alignment_(StrengthenAlignment(class_id, alignment)), |
4168 token_pos_(token_pos) { | 3916 token_pos_(token_pos) { |
4169 SetInputAt(kArrayPos, array); | 3917 SetInputAt(kArrayPos, array); |
4170 SetInputAt(kIndexPos, index); | 3918 SetInputAt(kIndexPos, index); |
4171 SetInputAt(kValuePos, value); | 3919 SetInputAt(kValuePos, value); |
4172 } | 3920 } |
4173 | 3921 |
4174 | |
4175 InvokeMathCFunctionInstr::InvokeMathCFunctionInstr( | 3922 InvokeMathCFunctionInstr::InvokeMathCFunctionInstr( |
4176 ZoneGrowableArray<Value*>* inputs, | 3923 ZoneGrowableArray<Value*>* inputs, |
4177 intptr_t deopt_id, | 3924 intptr_t deopt_id, |
4178 MethodRecognizer::Kind recognized_kind, | 3925 MethodRecognizer::Kind recognized_kind, |
4179 TokenPosition token_pos) | 3926 TokenPosition token_pos) |
4180 : PureDefinition(deopt_id), | 3927 : PureDefinition(deopt_id), |
4181 inputs_(inputs), | 3928 inputs_(inputs), |
4182 recognized_kind_(recognized_kind), | 3929 recognized_kind_(recognized_kind), |
4183 token_pos_(token_pos) { | 3930 token_pos_(token_pos) { |
4184 ASSERT(inputs_->length() == ArgumentCountFor(recognized_kind_)); | 3931 ASSERT(inputs_->length() == ArgumentCountFor(recognized_kind_)); |
4185 for (intptr_t i = 0; i < inputs_->length(); ++i) { | 3932 for (intptr_t i = 0; i < inputs_->length(); ++i) { |
4186 ASSERT((*inputs)[i] != NULL); | 3933 ASSERT((*inputs)[i] != NULL); |
4187 (*inputs)[i]->set_instruction(this); | 3934 (*inputs)[i]->set_instruction(this); |
4188 (*inputs)[i]->set_use_index(i); | 3935 (*inputs)[i]->set_use_index(i); |
4189 } | 3936 } |
4190 } | 3937 } |
4191 | 3938 |
4192 | |
4193 intptr_t InvokeMathCFunctionInstr::ArgumentCountFor( | 3939 intptr_t InvokeMathCFunctionInstr::ArgumentCountFor( |
4194 MethodRecognizer::Kind kind) { | 3940 MethodRecognizer::Kind kind) { |
4195 switch (kind) { | 3941 switch (kind) { |
4196 case MethodRecognizer::kDoubleTruncate: | 3942 case MethodRecognizer::kDoubleTruncate: |
4197 case MethodRecognizer::kDoubleFloor: | 3943 case MethodRecognizer::kDoubleFloor: |
4198 case MethodRecognizer::kDoubleCeil: { | 3944 case MethodRecognizer::kDoubleCeil: { |
4199 ASSERT(!TargetCPUFeatures::double_truncate_round_supported()); | 3945 ASSERT(!TargetCPUFeatures::double_truncate_round_supported()); |
4200 return 1; | 3946 return 1; |
4201 } | 3947 } |
4202 case MethodRecognizer::kDoubleRound: | 3948 case MethodRecognizer::kDoubleRound: |
4203 case MethodRecognizer::kMathAtan: | 3949 case MethodRecognizer::kMathAtan: |
4204 case MethodRecognizer::kMathTan: | 3950 case MethodRecognizer::kMathTan: |
4205 case MethodRecognizer::kMathAcos: | 3951 case MethodRecognizer::kMathAcos: |
4206 case MethodRecognizer::kMathAsin: | 3952 case MethodRecognizer::kMathAsin: |
4207 case MethodRecognizer::kMathSin: | 3953 case MethodRecognizer::kMathSin: |
4208 case MethodRecognizer::kMathCos: | 3954 case MethodRecognizer::kMathCos: |
4209 return 1; | 3955 return 1; |
4210 case MethodRecognizer::kDoubleMod: | 3956 case MethodRecognizer::kDoubleMod: |
4211 case MethodRecognizer::kMathDoublePow: | 3957 case MethodRecognizer::kMathDoublePow: |
4212 case MethodRecognizer::kMathAtan2: | 3958 case MethodRecognizer::kMathAtan2: |
4213 return 2; | 3959 return 2; |
4214 default: | 3960 default: |
4215 UNREACHABLE(); | 3961 UNREACHABLE(); |
4216 } | 3962 } |
4217 return 0; | 3963 return 0; |
4218 } | 3964 } |
4219 | 3965 |
4220 | |
4221 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { | 3966 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { |
4222 switch (recognized_kind_) { | 3967 switch (recognized_kind_) { |
4223 case MethodRecognizer::kDoubleTruncate: | 3968 case MethodRecognizer::kDoubleTruncate: |
4224 return kLibcTruncRuntimeEntry; | 3969 return kLibcTruncRuntimeEntry; |
4225 case MethodRecognizer::kDoubleRound: | 3970 case MethodRecognizer::kDoubleRound: |
4226 return kLibcRoundRuntimeEntry; | 3971 return kLibcRoundRuntimeEntry; |
4227 case MethodRecognizer::kDoubleFloor: | 3972 case MethodRecognizer::kDoubleFloor: |
4228 return kLibcFloorRuntimeEntry; | 3973 return kLibcFloorRuntimeEntry; |
4229 case MethodRecognizer::kDoubleCeil: | 3974 case MethodRecognizer::kDoubleCeil: |
4230 return kLibcCeilRuntimeEntry; | 3975 return kLibcCeilRuntimeEntry; |
(...skipping 14 matching lines...) Expand all Loading... |
4245 case MethodRecognizer::kMathAtan: | 3990 case MethodRecognizer::kMathAtan: |
4246 return kLibcAtanRuntimeEntry; | 3991 return kLibcAtanRuntimeEntry; |
4247 case MethodRecognizer::kMathAtan2: | 3992 case MethodRecognizer::kMathAtan2: |
4248 return kLibcAtan2RuntimeEntry; | 3993 return kLibcAtan2RuntimeEntry; |
4249 default: | 3994 default: |
4250 UNREACHABLE(); | 3995 UNREACHABLE(); |
4251 } | 3996 } |
4252 return kLibcPowRuntimeEntry; | 3997 return kLibcPowRuntimeEntry; |
4253 } | 3998 } |
4254 | 3999 |
4255 | |
4256 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { | 4000 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { |
4257 switch (kind) { | 4001 switch (kind) { |
4258 case kIllegal: | 4002 case kIllegal: |
4259 return "illegal"; | 4003 return "illegal"; |
4260 case kSqrt: | 4004 case kSqrt: |
4261 return "sqrt"; | 4005 return "sqrt"; |
4262 case kDoubleSquare: | 4006 case kDoubleSquare: |
4263 return "double-square"; | 4007 return "double-square"; |
4264 } | 4008 } |
4265 UNREACHABLE(); | 4009 UNREACHABLE(); |
4266 return ""; | 4010 return ""; |
4267 } | 4011 } |
4268 | 4012 |
4269 | |
4270 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { | 4013 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { |
4271 return kCaseInsensitiveCompareUC16RuntimeEntry; | 4014 return kCaseInsensitiveCompareUC16RuntimeEntry; |
4272 } | 4015 } |
4273 | 4016 |
4274 | |
4275 TruncDivModInstr::TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id) | 4017 TruncDivModInstr::TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id) |
4276 : TemplateDefinition(deopt_id) { | 4018 : TemplateDefinition(deopt_id) { |
4277 SetInputAt(0, lhs); | 4019 SetInputAt(0, lhs); |
4278 SetInputAt(1, rhs); | 4020 SetInputAt(1, rhs); |
4279 } | 4021 } |
4280 | 4022 |
4281 | |
4282 intptr_t TruncDivModInstr::OutputIndexOf(Token::Kind token) { | 4023 intptr_t TruncDivModInstr::OutputIndexOf(Token::Kind token) { |
4283 switch (token) { | 4024 switch (token) { |
4284 case Token::kTRUNCDIV: | 4025 case Token::kTRUNCDIV: |
4285 return 0; | 4026 return 0; |
4286 case Token::kMOD: | 4027 case Token::kMOD: |
4287 return 1; | 4028 return 1; |
4288 default: | 4029 default: |
4289 UNIMPLEMENTED(); | 4030 UNIMPLEMENTED(); |
4290 return -1; | 4031 return -1; |
4291 } | 4032 } |
4292 } | 4033 } |
4293 | 4034 |
4294 | |
4295 void NativeCallInstr::SetupNative() { | 4035 void NativeCallInstr::SetupNative() { |
4296 if (link_lazily()) { | 4036 if (link_lazily()) { |
4297 // Resolution will happen during NativeEntry::LinkNativeCall. | 4037 // Resolution will happen during NativeEntry::LinkNativeCall. |
4298 return; | 4038 return; |
4299 } | 4039 } |
4300 | 4040 |
4301 Zone* zone = Thread::Current()->zone(); | 4041 Zone* zone = Thread::Current()->zone(); |
4302 const Class& cls = Class::Handle(zone, function().Owner()); | 4042 const Class& cls = Class::Handle(zone, function().Owner()); |
4303 const Library& library = Library::Handle(zone, cls.library()); | 4043 const Library& library = Library::Handle(zone, cls.library()); |
4304 | 4044 |
(...skipping 12 matching lines...) Expand all Loading... |
4317 "native function '%s' (%" Pd " arguments) cannot be found", | 4057 "native function '%s' (%" Pd " arguments) cannot be found", |
4318 native_name().ToCString(), function().NumParameters()); | 4058 native_name().ToCString(), function().NumParameters()); |
4319 } | 4059 } |
4320 set_is_auto_scope(auto_setup_scope); | 4060 set_is_auto_scope(auto_setup_scope); |
4321 set_native_c_function(native_function); | 4061 set_native_c_function(native_function); |
4322 } | 4062 } |
4323 | 4063 |
4324 #undef __ | 4064 #undef __ |
4325 | 4065 |
4326 } // namespace dart | 4066 } // namespace dart |
OLD | NEW |