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