| 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 11 matching lines...) Expand all Loading... |
| 22 #include "vm/regexp_assembler_ir.h" | 22 #include "vm/regexp_assembler_ir.h" |
| 23 #include "vm/resolver.h" | 23 #include "vm/resolver.h" |
| 24 #include "vm/scopes.h" | 24 #include "vm/scopes.h" |
| 25 #include "vm/stub_code.h" | 25 #include "vm/stub_code.h" |
| 26 #include "vm/symbols.h" | 26 #include "vm/symbols.h" |
| 27 | 27 |
| 28 #include "vm/il_printer.h" | 28 #include "vm/il_printer.h" |
| 29 | 29 |
| 30 namespace dart { | 30 namespace dart { |
| 31 | 31 |
| 32 DEFINE_FLAG(bool, propagate_ic_data, true, | 32 DEFINE_FLAG(bool, |
| 33 "Propagate IC data from unoptimized to optimized IC calls."); | 33 propagate_ic_data, |
| 34 DEFINE_FLAG(bool, two_args_smi_icd, true, | 34 true, |
| 35 "Generate special IC stubs for two args Smi operations"); | 35 "Propagate IC data from unoptimized to optimized IC calls."); |
| 36 DEFINE_FLAG(bool, unbox_numeric_fields, !USING_DBC, | 36 DEFINE_FLAG(bool, |
| 37 "Support unboxed double and float32x4 fields."); | 37 two_args_smi_icd, |
| 38 true, |
| 39 "Generate special IC stubs for two args Smi operations"); |
| 40 DEFINE_FLAG(bool, |
| 41 unbox_numeric_fields, |
| 42 !USING_DBC, |
| 43 "Support unboxed double and float32x4 fields."); |
| 38 DECLARE_FLAG(bool, eliminate_type_checks); | 44 DECLARE_FLAG(bool, eliminate_type_checks); |
| 39 DECLARE_FLAG(bool, support_externalizable_strings); | 45 DECLARE_FLAG(bool, support_externalizable_strings); |
| 40 | 46 |
| 41 | 47 |
| 42 #if defined(DEBUG) | 48 #if defined(DEBUG) |
| 43 void Instruction::CheckField(const Field& field) const { | 49 void Instruction::CheckField(const Field& field) const { |
| 44 ASSERT(field.IsZoneHandle()); | 50 ASSERT(field.IsZoneHandle()); |
| 45 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); | 51 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); |
| 46 } | 52 } |
| 47 #endif // DEBUG | 53 #endif // DEBUG |
| 48 | 54 |
| 49 | 55 |
| 50 Definition::Definition(intptr_t deopt_id) | 56 Definition::Definition(intptr_t deopt_id) |
| 51 : Instruction(deopt_id), | 57 : Instruction(deopt_id), |
| 52 range_(NULL), | 58 range_(NULL), |
| 53 type_(NULL), | 59 type_(NULL), |
| 54 temp_index_(-1), | 60 temp_index_(-1), |
| 55 ssa_temp_index_(-1), | 61 ssa_temp_index_(-1), |
| 56 input_use_list_(NULL), | 62 input_use_list_(NULL), |
| 57 env_use_list_(NULL), | 63 env_use_list_(NULL), |
| 58 constant_value_(NULL) { | 64 constant_value_(NULL) {} |
| 59 } | |
| 60 | 65 |
| 61 | 66 |
| 62 // A value in the constant propagation lattice. | 67 // A value in the constant propagation lattice. |
| 63 // - non-constant sentinel | 68 // - non-constant sentinel |
| 64 // - a constant (any non-sentinel value) | 69 // - a constant (any non-sentinel value) |
| 65 // - unknown sentinel | 70 // - unknown sentinel |
| 66 Object& Definition::constant_value() { | 71 Object& Definition::constant_value() { |
| 67 if (constant_value_ == NULL) { | 72 if (constant_value_ == NULL) { |
| 68 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); | 73 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); |
| 69 } | 74 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 } | 188 } |
| 184 } | 189 } |
| 185 return true; | 190 return true; |
| 186 } | 191 } |
| 187 | 192 |
| 188 | 193 |
| 189 static bool AreAllChecksImmutable(const ICData& checks) { | 194 static bool AreAllChecksImmutable(const ICData& checks) { |
| 190 const intptr_t len = checks.NumberOfChecks(); | 195 const intptr_t len = checks.NumberOfChecks(); |
| 191 for (intptr_t i = 0; i < len; i++) { | 196 for (intptr_t i = 0; i < len; i++) { |
| 192 if (checks.IsUsedAt(i)) { | 197 if (checks.IsUsedAt(i)) { |
| 193 if (Field::IsExternalizableCid( | 198 if (Field::IsExternalizableCid(checks.GetReceiverClassIdAt(i))) { |
| 194 checks.GetReceiverClassIdAt(i))) { | |
| 195 return false; | 199 return false; |
| 196 } | 200 } |
| 197 } | 201 } |
| 198 } | 202 } |
| 199 return true; | 203 return true; |
| 200 } | 204 } |
| 201 | 205 |
| 202 | 206 |
| 203 EffectSet CheckClassInstr::Dependencies() const { | 207 EffectSet CheckClassInstr::Dependencies() const { |
| 204 // Externalization of strings via the API can change the class-id. | 208 // Externalization of strings via the API can change the class-id. |
| 205 return !AreAllChecksImmutable(unary_checks()) ? | 209 return !AreAllChecksImmutable(unary_checks()) ? EffectSet::Externalization() |
| 206 EffectSet::Externalization() : EffectSet::None(); | 210 : EffectSet::None(); |
| 207 } | 211 } |
| 208 | 212 |
| 209 | 213 |
| 210 EffectSet CheckClassIdInstr::Dependencies() const { | 214 EffectSet CheckClassIdInstr::Dependencies() const { |
| 211 // Externalization of strings via the API can change the class-id. | 215 // Externalization of strings via the API can change the class-id. |
| 212 return Field::IsExternalizableCid(cid_) ? | 216 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() |
| 213 EffectSet::Externalization() : EffectSet::None(); | 217 : EffectSet::None(); |
| 214 } | 218 } |
| 215 | 219 |
| 216 | 220 |
| 217 bool CheckClassInstr::DeoptIfNull() const { | 221 bool CheckClassInstr::DeoptIfNull() const { |
| 218 if (unary_checks().NumberOfChecks() != 1) { | 222 if (unary_checks().NumberOfChecks() != 1) { |
| 219 return false; | 223 return false; |
| 220 } | 224 } |
| 221 CompileType* in_type = value()->Type(); | 225 CompileType* in_type = value()->Type(); |
| 222 const intptr_t cid = unary_checks().GetCidAt(0); | 226 const intptr_t cid = unary_checks().GetCidAt(0); |
| 223 // Performance check: use CheckSmiInstr instead. | 227 // Performance check: use CheckSmiInstr instead. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 | 274 |
| 271 | 275 |
| 272 bool CheckClassInstr::IsDenseMask(intptr_t mask) { | 276 bool CheckClassInstr::IsDenseMask(intptr_t mask) { |
| 273 // Returns true if the mask is a continuos sequence of ones in its binary | 277 // Returns true if the mask is a continuos sequence of ones in its binary |
| 274 // representation (i.e. no holes) | 278 // representation (i.e. no holes) |
| 275 return mask == -1 || Utils::IsPowerOfTwo(mask + 1); | 279 return mask == -1 || Utils::IsPowerOfTwo(mask + 1); |
| 276 } | 280 } |
| 277 | 281 |
| 278 | 282 |
| 279 bool LoadFieldInstr::IsUnboxedLoad() const { | 283 bool LoadFieldInstr::IsUnboxedLoad() const { |
| 280 return FLAG_unbox_numeric_fields | 284 return FLAG_unbox_numeric_fields && (field() != NULL) && |
| 281 && (field() != NULL) | 285 FlowGraphCompiler::IsUnboxedField(*field()); |
| 282 && FlowGraphCompiler::IsUnboxedField(*field()); | |
| 283 } | 286 } |
| 284 | 287 |
| 285 | 288 |
| 286 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { | 289 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { |
| 287 return FLAG_unbox_numeric_fields | 290 return FLAG_unbox_numeric_fields && (field() != NULL) && |
| 288 && (field() != NULL) | 291 FlowGraphCompiler::IsPotentialUnboxedField(*field()); |
| 289 && FlowGraphCompiler::IsPotentialUnboxedField(*field()); | |
| 290 } | 292 } |
| 291 | 293 |
| 292 | 294 |
| 293 Representation LoadFieldInstr::representation() const { | 295 Representation LoadFieldInstr::representation() const { |
| 294 if (IsUnboxedLoad()) { | 296 if (IsUnboxedLoad()) { |
| 295 const intptr_t cid = field()->UnboxedFieldCid(); | 297 const intptr_t cid = field()->UnboxedFieldCid(); |
| 296 switch (cid) { | 298 switch (cid) { |
| 297 case kDoubleCid: | 299 case kDoubleCid: |
| 298 return kUnboxedDouble; | 300 return kUnboxedDouble; |
| 299 case kFloat32x4Cid: | 301 case kFloat32x4Cid: |
| 300 return kUnboxedFloat32x4; | 302 return kUnboxedFloat32x4; |
| 301 case kFloat64x2Cid: | 303 case kFloat64x2Cid: |
| 302 return kUnboxedFloat64x2; | 304 return kUnboxedFloat64x2; |
| 303 default: | 305 default: |
| 304 UNREACHABLE(); | 306 UNREACHABLE(); |
| 305 } | 307 } |
| 306 } | 308 } |
| 307 return kTagged; | 309 return kTagged; |
| 308 } | 310 } |
| 309 | 311 |
| 310 | 312 |
| 311 bool StoreInstanceFieldInstr::IsUnboxedStore() const { | 313 bool StoreInstanceFieldInstr::IsUnboxedStore() const { |
| 312 return FLAG_unbox_numeric_fields | 314 return FLAG_unbox_numeric_fields && !field().IsNull() && |
| 313 && !field().IsNull() | 315 FlowGraphCompiler::IsUnboxedField(field()); |
| 314 && FlowGraphCompiler::IsUnboxedField(field()); | |
| 315 } | 316 } |
| 316 | 317 |
| 317 | 318 |
| 318 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { | 319 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { |
| 319 return FLAG_unbox_numeric_fields | 320 return FLAG_unbox_numeric_fields && !field().IsNull() && |
| 320 && !field().IsNull() | 321 FlowGraphCompiler::IsPotentialUnboxedField(field()); |
| 321 && FlowGraphCompiler::IsPotentialUnboxedField(field()); | |
| 322 } | 322 } |
| 323 | 323 |
| 324 | 324 |
| 325 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( | 325 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( |
| 326 intptr_t index) const { | 326 intptr_t index) const { |
| 327 ASSERT((index == 0) || (index == 1)); | 327 ASSERT((index == 0) || (index == 1)); |
| 328 if ((index == 1) && IsUnboxedStore()) { | 328 if ((index == 1) && IsUnboxedStore()) { |
| 329 const intptr_t cid = field().UnboxedFieldCid(); | 329 const intptr_t cid = field().UnboxedFieldCid(); |
| 330 switch (cid) { | 330 switch (cid) { |
| 331 case kDoubleCid: | 331 case kDoubleCid: |
| 332 return kUnboxedDouble; | 332 return kUnboxedDouble; |
| 333 case kFloat32x4Cid: | 333 case kFloat32x4Cid: |
| 334 return kUnboxedFloat32x4; | 334 return kUnboxedFloat32x4; |
| 335 case kFloat64x2Cid: | 335 case kFloat64x2Cid: |
| 336 return kUnboxedFloat64x2; | 336 return kUnboxedFloat64x2; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 358 // This predicate has to be commutative for DominatorBasedCSE to work. | 358 // This predicate has to be commutative for DominatorBasedCSE to work. |
| 359 // TODO(fschneider): Eliminate more asserts with subtype relation. | 359 // TODO(fschneider): Eliminate more asserts with subtype relation. |
| 360 return dst_type().raw() == other_assert->dst_type().raw(); | 360 return dst_type().raw() == other_assert->dst_type().raw(); |
| 361 } | 361 } |
| 362 | 362 |
| 363 | 363 |
| 364 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { | 364 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { |
| 365 StrictCompareInstr* other_op = other->AsStrictCompare(); | 365 StrictCompareInstr* other_op = other->AsStrictCompare(); |
| 366 ASSERT(other_op != NULL); | 366 ASSERT(other_op != NULL); |
| 367 return ComparisonInstr::AttributesEqual(other) && | 367 return ComparisonInstr::AttributesEqual(other) && |
| 368 (needs_number_check() == other_op->needs_number_check()); | 368 (needs_number_check() == other_op->needs_number_check()); |
| 369 } | 369 } |
| 370 | 370 |
| 371 | 371 |
| 372 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { | 372 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { |
| 373 MathMinMaxInstr* other_op = other->AsMathMinMax(); | 373 MathMinMaxInstr* other_op = other->AsMathMinMax(); |
| 374 ASSERT(other_op != NULL); | 374 ASSERT(other_op != NULL); |
| 375 return (op_kind() == other_op->op_kind()) && | 375 return (op_kind() == other_op->op_kind()) && |
| 376 (result_cid() == other_op->result_cid()); | 376 (result_cid() == other_op->result_cid()); |
| 377 } | 377 } |
| 378 | 378 |
| 379 | 379 |
| 380 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { | 380 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { |
| 381 ASSERT(other->tag() == tag()); | 381 ASSERT(other->tag() == tag()); |
| 382 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); | 382 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); |
| 383 return (op_kind() == other_op->op_kind()) && | 383 return (op_kind() == other_op->op_kind()) && |
| 384 (can_overflow() == other_op->can_overflow()) && | 384 (can_overflow() == other_op->can_overflow()) && |
| 385 (is_truncating() == other_op->is_truncating()); | 385 (is_truncating() == other_op->is_truncating()); |
| 386 } | 386 } |
| 387 | 387 |
| 388 | 388 |
| 389 EffectSet LoadFieldInstr::Dependencies() const { | 389 EffectSet LoadFieldInstr::Dependencies() const { |
| 390 return immutable_ ? EffectSet::None() : EffectSet::All(); | 390 return immutable_ ? EffectSet::None() : EffectSet::All(); |
| 391 } | 391 } |
| 392 | 392 |
| 393 | 393 |
| 394 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 394 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
| 395 LoadFieldInstr* other_load = other->AsLoadField(); | 395 LoadFieldInstr* other_load = other->AsLoadField(); |
| 396 ASSERT(other_load != NULL); | 396 ASSERT(other_load != NULL); |
| 397 if (field() != NULL) { | 397 if (field() != NULL) { |
| 398 return (other_load->field() != NULL) && | 398 return (other_load->field() != NULL) && |
| 399 (field()->raw() == other_load->field()->raw()); | 399 (field()->raw() == other_load->field()->raw()); |
| 400 } | 400 } |
| 401 return (other_load->field() == NULL) && | 401 return (other_load->field() == NULL) && |
| 402 (offset_in_bytes() == other_load->offset_in_bytes()); | 402 (offset_in_bytes() == other_load->offset_in_bytes()); |
| 403 } | 403 } |
| 404 | 404 |
| 405 | 405 |
| 406 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { | 406 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { |
| 407 const bool is_initialized = | 407 const bool is_initialized = |
| 408 (field_.StaticValue() != Object::sentinel().raw()) && | 408 (field_.StaticValue() != Object::sentinel().raw()) && |
| 409 (field_.StaticValue() != Object::transition_sentinel().raw()); | 409 (field_.StaticValue() != Object::transition_sentinel().raw()); |
| 410 // When precompiling, the fact that a field is currently initialized does not | 410 // When precompiling, the fact that a field is currently initialized does not |
| 411 // make it safe to omit code that checks if the field needs initialization | 411 // make it safe to omit code that checks if the field needs initialization |
| 412 // because the field will be reset so it starts uninitialized in the process | 412 // because the field will be reset so it starts uninitialized in the process |
| 413 // running the precompiled code. We must be prepared to reinitialize fields. | 413 // running the precompiled code. We must be prepared to reinitialize fields. |
| 414 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; | 414 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; |
| 415 } | 415 } |
| 416 | 416 |
| 417 | 417 |
| 418 EffectSet LoadStaticFieldInstr::Dependencies() const { | 418 EffectSet LoadStaticFieldInstr::Dependencies() const { |
| 419 return (StaticField().is_final() && !FLAG_fields_may_be_reset) | 419 return (StaticField().is_final() && !FLAG_fields_may_be_reset) |
| 420 ? EffectSet::None() : EffectSet::All(); | 420 ? EffectSet::None() |
| 421 : EffectSet::All(); |
| 421 } | 422 } |
| 422 | 423 |
| 423 | 424 |
| 424 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { | 425 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
| 425 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 426 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
| 426 ASSERT(other_load != NULL); | 427 ASSERT(other_load != NULL); |
| 427 // Assert that the field is initialized. | 428 // Assert that the field is initialized. |
| 428 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); | 429 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); |
| 429 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); | 430 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); |
| 430 return StaticField().raw() == other_load->StaticField().raw(); | 431 return StaticField().raw() == other_load->StaticField().raw(); |
| 431 } | 432 } |
| 432 | 433 |
| 433 | 434 |
| 434 const Field& LoadStaticFieldInstr::StaticField() const { | 435 const Field& LoadStaticFieldInstr::StaticField() const { |
| 435 Field& field = Field::ZoneHandle(); | 436 Field& field = Field::ZoneHandle(); |
| 436 field ^= field_value()->BoundConstant().raw(); | 437 field ^= field_value()->BoundConstant().raw(); |
| 437 return field; | 438 return field; |
| 438 } | 439 } |
| 439 | 440 |
| 440 | 441 |
| 441 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) | 442 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) |
| 442 : value_(value), | 443 : value_(value), token_pos_(token_pos) { |
| 443 token_pos_(token_pos) { | |
| 444 // Check that the value is not an incorrect Integer representation. | 444 // Check that the value is not an incorrect Integer representation. |
| 445 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); | 445 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); |
| 446 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); | 446 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); |
| 447 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); | 447 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); |
| 448 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 448 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
| 449 } | 449 } |
| 450 | 450 |
| 451 | 451 |
| 452 bool ConstantInstr::AttributesEqual(Instruction* other) const { | 452 bool ConstantInstr::AttributesEqual(Instruction* other) const { |
| 453 ConstantInstr* other_constant = other->AsConstant(); | 453 ConstantInstr* other_constant = other->AsConstant(); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 intptr_t osr_id) | 495 intptr_t osr_id) |
| 496 : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex), | 496 : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex), |
| 497 parsed_function_(parsed_function), | 497 parsed_function_(parsed_function), |
| 498 normal_entry_(normal_entry), | 498 normal_entry_(normal_entry), |
| 499 catch_entries_(), | 499 catch_entries_(), |
| 500 indirect_entries_(), | 500 indirect_entries_(), |
| 501 initial_definitions_(), | 501 initial_definitions_(), |
| 502 osr_id_(osr_id), | 502 osr_id_(osr_id), |
| 503 entry_count_(0), | 503 entry_count_(0), |
| 504 spill_slot_count_(0), | 504 spill_slot_count_(0), |
| 505 fixed_slot_count_(0) { | 505 fixed_slot_count_(0) {} |
| 506 } | |
| 507 | 506 |
| 508 | 507 |
| 509 ConstantInstr* GraphEntryInstr::constant_null() { | 508 ConstantInstr* GraphEntryInstr::constant_null() { |
| 510 ASSERT(initial_definitions_.length() > 0); | 509 ASSERT(initial_definitions_.length() > 0); |
| 511 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { | 510 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { |
| 512 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); | 511 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); |
| 513 if (defn != NULL && defn->value().IsNull()) return defn; | 512 if (defn != NULL && defn->value().IsNull()) return defn; |
| 514 } | 513 } |
| 515 UNREACHABLE(); | 514 UNREACHABLE(); |
| 516 return NULL; | 515 return NULL; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 528 | 527 |
| 529 | 528 |
| 530 bool GraphEntryInstr::IsCompiledForOsr() const { | 529 bool GraphEntryInstr::IsCompiledForOsr() const { |
| 531 return osr_id_ != Compiler::kNoOSRDeoptId; | 530 return osr_id_ != Compiler::kNoOSRDeoptId; |
| 532 } | 531 } |
| 533 | 532 |
| 534 | 533 |
| 535 // ==== Support for visiting flow graphs. | 534 // ==== Support for visiting flow graphs. |
| 536 | 535 |
| 537 #define DEFINE_ACCEPT(ShortName) \ | 536 #define DEFINE_ACCEPT(ShortName) \ |
| 538 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ | 537 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ |
| 539 visitor->Visit##ShortName(this); \ | 538 visitor->Visit##ShortName(this); \ |
| 540 } | 539 } |
| 541 | 540 |
| 542 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) | 541 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) |
| 543 | 542 |
| 544 #undef DEFINE_ACCEPT | 543 #undef DEFINE_ACCEPT |
| 545 | 544 |
| 546 | 545 |
| 547 void Instruction::SetEnvironment(Environment* deopt_env) { | 546 void Instruction::SetEnvironment(Environment* deopt_env) { |
| 548 intptr_t use_index = 0; | 547 intptr_t use_index = 0; |
| 549 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | 548 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { |
| 550 Value* use = it.CurrentValue(); | 549 Value* use = it.CurrentValue(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 } | 614 } |
| 616 return tail; | 615 return tail; |
| 617 } | 616 } |
| 618 | 617 |
| 619 | 618 |
| 620 BlockEntryInstr* Instruction::GetBlock() { | 619 BlockEntryInstr* Instruction::GetBlock() { |
| 621 // TODO(fschneider): Implement a faster way to get the block of an | 620 // TODO(fschneider): Implement a faster way to get the block of an |
| 622 // instruction. | 621 // instruction. |
| 623 ASSERT(previous() != NULL); | 622 ASSERT(previous() != NULL); |
| 624 Instruction* result = previous(); | 623 Instruction* result = previous(); |
| 625 while (!result->IsBlockEntry()) result = result->previous(); | 624 while (!result->IsBlockEntry()) |
| 625 result = result->previous(); |
| 626 return result->AsBlockEntry(); | 626 return result->AsBlockEntry(); |
| 627 } | 627 } |
| 628 | 628 |
| 629 | 629 |
| 630 void ForwardInstructionIterator::RemoveCurrentFromGraph() { | 630 void ForwardInstructionIterator::RemoveCurrentFromGraph() { |
| 631 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. | 631 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. |
| 632 } | 632 } |
| 633 | 633 |
| 634 | 634 |
| 635 void BackwardInstructionIterator::RemoveCurrentFromGraph() { | 635 void BackwardInstructionIterator::RemoveCurrentFromGraph() { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 647 current_iterator_ = ⁢ | 647 current_iterator_ = ⁢ |
| 648 for (; !it.Done(); it.Advance()) { | 648 for (; !it.Done(); it.Advance()) { |
| 649 it.Current()->Accept(this); | 649 it.Current()->Accept(this); |
| 650 } | 650 } |
| 651 current_iterator_ = NULL; | 651 current_iterator_ = NULL; |
| 652 } | 652 } |
| 653 } | 653 } |
| 654 | 654 |
| 655 | 655 |
| 656 bool Value::NeedsStoreBuffer() { | 656 bool Value::NeedsStoreBuffer() { |
| 657 if (Type()->IsNull() || | 657 if (Type()->IsNull() || (Type()->ToNullableCid() == kSmiCid) || |
| 658 (Type()->ToNullableCid() == kSmiCid) || | |
| 659 (Type()->ToNullableCid() == kBoolCid)) { | 658 (Type()->ToNullableCid() == kBoolCid)) { |
| 660 return false; | 659 return false; |
| 661 } | 660 } |
| 662 | 661 |
| 663 return !BindsToConstant(); | 662 return !BindsToConstant(); |
| 664 } | 663 } |
| 665 | 664 |
| 666 | 665 |
| 667 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { | 666 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { |
| 668 // Require the predecessors to be sorted by block_id to make managing | 667 // Require the predecessors to be sorted by block_id to make managing |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 it.CurrentValue()->RemoveFromUseList(); | 786 it.CurrentValue()->RemoveFromUseList(); |
| 788 } | 787 } |
| 789 } | 788 } |
| 790 | 789 |
| 791 | 790 |
| 792 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, | 791 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, |
| 793 Definition* call, | 792 Definition* call, |
| 794 Definition* result) { | 793 Definition* result) { |
| 795 ASSERT(call->env() != NULL); | 794 ASSERT(call->env() != NULL); |
| 796 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); | 795 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); |
| 797 call->env()->DeepCopyAfterTo(flow_graph->zone(), | 796 call->env()->DeepCopyAfterTo( |
| 798 this, | 797 flow_graph->zone(), this, call->ArgumentCount(), |
| 799 call->ArgumentCount(), | 798 flow_graph->constant_dead(), |
| 800 flow_graph->constant_dead(), | 799 result != NULL ? result : flow_graph->constant_dead()); |
| 801 result != NULL ? result | |
| 802 : flow_graph->constant_dead()); | |
| 803 env()->set_deopt_id(deopt_id_); | 800 env()->set_deopt_id(deopt_id_); |
| 804 } | 801 } |
| 805 | 802 |
| 806 | 803 |
| 807 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { | 804 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { |
| 808 ASSERT(other->env() != NULL); | 805 ASSERT(other->env() != NULL); |
| 809 CopyDeoptIdFrom(*other); | 806 CopyDeoptIdFrom(*other); |
| 810 other->env()->DeepCopyTo(zone, this); | 807 other->env()->DeepCopyTo(zone, this); |
| 811 env()->set_deopt_id(deopt_id_); | 808 env()->set_deopt_id(deopt_id_); |
| 812 } | 809 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 916 // Detect that a block has been visited as part of the current | 913 // Detect that a block has been visited as part of the current |
| 917 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 914 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
| 918 // will be 'marked' by (1) having a preorder number in the range of the | 915 // will be 'marked' by (1) having a preorder number in the range of the |
| 919 // preorder array and (2) being in the preorder array at that index. | 916 // preorder array and (2) being in the preorder array at that index. |
| 920 intptr_t i = block->preorder_number(); | 917 intptr_t i = block->preorder_number(); |
| 921 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); | 918 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); |
| 922 } | 919 } |
| 923 | 920 |
| 924 | 921 |
| 925 // Base class implementation used for JoinEntry and TargetEntry. | 922 // Base class implementation used for JoinEntry and TargetEntry. |
| 926 bool BlockEntryInstr::DiscoverBlock( | 923 bool BlockEntryInstr::DiscoverBlock(BlockEntryInstr* predecessor, |
| 927 BlockEntryInstr* predecessor, | 924 GrowableArray<BlockEntryInstr*>* preorder, |
| 928 GrowableArray<BlockEntryInstr*>* preorder, | 925 GrowableArray<intptr_t>* parent) { |
| 929 GrowableArray<intptr_t>* parent) { | |
| 930 // If this block has a predecessor (i.e., is not the graph entry) we can | 926 // If this block has a predecessor (i.e., is not the graph entry) we can |
| 931 // assume the preorder array is non-empty. | 927 // assume the preorder array is non-empty. |
| 932 ASSERT((predecessor == NULL) || !preorder->is_empty()); | 928 ASSERT((predecessor == NULL) || !preorder->is_empty()); |
| 933 // Blocks with a single predecessor cannot have been reached before. | 929 // Blocks with a single predecessor cannot have been reached before. |
| 934 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); | 930 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); |
| 935 | 931 |
| 936 // 1. If the block has already been reached, add current_block as a | 932 // 1. If the block has already been reached, add current_block as a |
| 937 // basic-block predecessor and we are done. | 933 // basic-block predecessor and we are done. |
| 938 if (IsMarked(this, preorder)) { | 934 if (IsMarked(this, preorder)) { |
| 939 ASSERT(predecessor != NULL); | 935 ASSERT(predecessor != NULL); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1004 | 1000 |
| 1005 GotoInstr* goto_join = new GotoInstr(AsJoinEntry()); | 1001 GotoInstr* goto_join = new GotoInstr(AsJoinEntry()); |
| 1006 goto_join->CopyDeoptIdFrom(*parent); | 1002 goto_join->CopyDeoptIdFrom(*parent); |
| 1007 graph_entry->normal_entry()->LinkTo(goto_join); | 1003 graph_entry->normal_entry()->LinkTo(goto_join); |
| 1008 return true; | 1004 return true; |
| 1009 } | 1005 } |
| 1010 } | 1006 } |
| 1011 | 1007 |
| 1012 // Recursively search the successors. | 1008 // Recursively search the successors. |
| 1013 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { | 1009 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { |
| 1014 if (instr->SuccessorAt(i)->PruneUnreachable(graph_entry, | 1010 if (instr->SuccessorAt(i)->PruneUnreachable(graph_entry, instr, osr_id, |
| 1015 instr, | |
| 1016 osr_id, | |
| 1017 block_marks)) { | 1011 block_marks)) { |
| 1018 return true; | 1012 return true; |
| 1019 } | 1013 } |
| 1020 } | 1014 } |
| 1021 return false; | 1015 return false; |
| 1022 } | 1016 } |
| 1023 | 1017 |
| 1024 | 1018 |
| 1025 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { | 1019 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { |
| 1026 // TODO(fschneider): Make this faster by e.g. storing dominators for each | 1020 // TODO(fschneider): Make this faster by e.g. storing dominators for each |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 if ((join->phis() == NULL) || (old_index == new_index)) return; | 1083 if ((join->phis() == NULL) || (old_index == new_index)) return; |
| 1090 // Otherwise, reorder the predecessor uses in each phi. | 1084 // Otherwise, reorder the predecessor uses in each phi. |
| 1091 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 1085 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 1092 PhiInstr* phi = it.Current(); | 1086 PhiInstr* phi = it.Current(); |
| 1093 ASSERT(phi != NULL); | 1087 ASSERT(phi != NULL); |
| 1094 ASSERT(pred_count == phi->InputCount()); | 1088 ASSERT(pred_count == phi->InputCount()); |
| 1095 // Save the predecessor use. | 1089 // Save the predecessor use. |
| 1096 Value* pred_use = phi->InputAt(old_index); | 1090 Value* pred_use = phi->InputAt(old_index); |
| 1097 // Move uses between old and new. | 1091 // Move uses between old and new. |
| 1098 intptr_t step = (old_index < new_index) ? 1 : -1; | 1092 intptr_t step = (old_index < new_index) ? 1 : -1; |
| 1099 for (intptr_t use_idx = old_index; | 1093 for (intptr_t use_idx = old_index; use_idx != new_index; |
| 1100 use_idx != new_index; | |
| 1101 use_idx += step) { | 1094 use_idx += step) { |
| 1102 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); | 1095 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); |
| 1103 } | 1096 } |
| 1104 // Write the predecessor use. | 1097 // Write the predecessor use. |
| 1105 phi->SetInputAt(new_index, pred_use); | 1098 phi->SetInputAt(new_index, pred_use); |
| 1106 } | 1099 } |
| 1107 } | 1100 } |
| 1108 } | 1101 } |
| 1109 | 1102 |
| 1110 | 1103 |
| 1111 void BlockEntryInstr::ClearAllInstructions() { | 1104 void BlockEntryInstr::ClearAllInstructions() { |
| 1112 JoinEntryInstr* join = this->AsJoinEntry(); | 1105 JoinEntryInstr* join = this->AsJoinEntry(); |
| 1113 if (join != NULL) { | 1106 if (join != NULL) { |
| 1114 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 1107 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 1115 it.Current()->UnuseAllInputs(); | 1108 it.Current()->UnuseAllInputs(); |
| 1116 } | 1109 } |
| 1117 } | 1110 } |
| 1118 UnuseAllInputs(); | 1111 UnuseAllInputs(); |
| 1119 for (ForwardInstructionIterator it(this); | 1112 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { |
| 1120 !it.Done(); | |
| 1121 it.Advance()) { | |
| 1122 it.Current()->UnuseAllInputs(); | 1113 it.Current()->UnuseAllInputs(); |
| 1123 } | 1114 } |
| 1124 } | 1115 } |
| 1125 | 1116 |
| 1126 | 1117 |
| 1127 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { | 1118 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { |
| 1128 // Lazily initialize the array of phis. | 1119 // Lazily initialize the array of phis. |
| 1129 // Currently, phis are stored in a sparse array that holds the phi | 1120 // Currently, phis are stored in a sparse array that holds the phi |
| 1130 // for variable with index i at position i. | 1121 // for variable with index i at position i. |
| 1131 // TODO(fschneider): Store phis in a more compact way. | 1122 // TODO(fschneider): Store phis in a more compact way. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1232 return successor(); | 1223 return successor(); |
| 1233 } | 1224 } |
| 1234 | 1225 |
| 1235 | 1226 |
| 1236 void Instruction::Goto(JoinEntryInstr* entry) { | 1227 void Instruction::Goto(JoinEntryInstr* entry) { |
| 1237 LinkTo(new GotoInstr(entry)); | 1228 LinkTo(new GotoInstr(entry)); |
| 1238 } | 1229 } |
| 1239 | 1230 |
| 1240 | 1231 |
| 1241 bool UnboxedIntConverterInstr::CanDeoptimize() const { | 1232 bool UnboxedIntConverterInstr::CanDeoptimize() const { |
| 1242 return (to() == kUnboxedInt32) && | 1233 return (to() == kUnboxedInt32) && !is_truncating() && |
| 1243 !is_truncating() && | 1234 !RangeUtils::Fits(value()->definition()->range(), |
| 1244 !RangeUtils::Fits(value()->definition()->range(), | 1235 RangeBoundary::kRangeBoundaryInt32); |
| 1245 RangeBoundary::kRangeBoundaryInt32); | |
| 1246 } | 1236 } |
| 1247 | 1237 |
| 1248 | 1238 |
| 1249 bool UnboxInt32Instr::CanDeoptimize() const { | 1239 bool UnboxInt32Instr::CanDeoptimize() const { |
| 1250 const intptr_t value_cid = value()->Type()->ToCid(); | 1240 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1251 if (value_cid == kSmiCid) { | 1241 if (value_cid == kSmiCid) { |
| 1252 return (kSmiBits > 32) && | 1242 return (kSmiBits > 32) && !is_truncating() && |
| 1253 !is_truncating() && | 1243 !RangeUtils::Fits(value()->definition()->range(), |
| 1254 !RangeUtils::Fits(value()->definition()->range(), | 1244 RangeBoundary::kRangeBoundaryInt32); |
| 1255 RangeBoundary::kRangeBoundaryInt32); | |
| 1256 } else if (value_cid == kMintCid) { | 1245 } else if (value_cid == kMintCid) { |
| 1257 return !is_truncating() && | 1246 return !is_truncating() && |
| 1258 !RangeUtils::Fits(value()->definition()->range(), | 1247 !RangeUtils::Fits(value()->definition()->range(), |
| 1259 RangeBoundary::kRangeBoundaryInt32); | 1248 RangeBoundary::kRangeBoundaryInt32); |
| 1260 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { | 1249 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { |
| 1261 return false; | 1250 return false; |
| 1262 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { | 1251 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { |
| 1263 // Note: we don't support truncation of Bigint values. | 1252 // Note: we don't support truncation of Bigint values. |
| 1264 return !RangeUtils::Fits(value()->definition()->range(), | 1253 return !RangeUtils::Fits(value()->definition()->range(), |
| 1265 RangeBoundary::kRangeBoundaryInt32); | 1254 RangeBoundary::kRangeBoundaryInt32); |
| 1266 } else { | 1255 } else { |
| 1267 return true; | 1256 return true; |
| 1268 } | 1257 } |
| 1269 } | 1258 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1286 case Token::kBIT_AND: | 1275 case Token::kBIT_AND: |
| 1287 case Token::kBIT_OR: | 1276 case Token::kBIT_OR: |
| 1288 case Token::kBIT_XOR: | 1277 case Token::kBIT_XOR: |
| 1289 return false; | 1278 return false; |
| 1290 | 1279 |
| 1291 case Token::kSHR: | 1280 case Token::kSHR: |
| 1292 return false; | 1281 return false; |
| 1293 | 1282 |
| 1294 case Token::kSHL: | 1283 case Token::kSHL: |
| 1295 return can_overflow() || | 1284 return can_overflow() || |
| 1296 !RangeUtils::IsPositive(right()->definition()->range()); | 1285 !RangeUtils::IsPositive(right()->definition()->range()); |
| 1297 | 1286 |
| 1298 case Token::kMOD: { | 1287 case Token::kMOD: { |
| 1299 UNREACHABLE(); | 1288 UNREACHABLE(); |
| 1300 } | 1289 } |
| 1301 | 1290 |
| 1302 default: | 1291 default: |
| 1303 return can_overflow(); | 1292 return can_overflow(); |
| 1304 } | 1293 } |
| 1305 } | 1294 } |
| 1306 | 1295 |
| 1307 | 1296 |
| 1308 bool BinarySmiOpInstr::CanDeoptimize() const { | 1297 bool BinarySmiOpInstr::CanDeoptimize() const { |
| 1309 switch (op_kind()) { | 1298 switch (op_kind()) { |
| 1310 case Token::kBIT_AND: | 1299 case Token::kBIT_AND: |
| 1311 case Token::kBIT_OR: | 1300 case Token::kBIT_OR: |
| 1312 case Token::kBIT_XOR: | 1301 case Token::kBIT_XOR: |
| 1313 return false; | 1302 return false; |
| 1314 | 1303 |
| 1315 case Token::kSHR: | 1304 case Token::kSHR: |
| 1316 return !RangeUtils::IsPositive(right()->definition()->range()); | 1305 return !RangeUtils::IsPositive(right()->definition()->range()); |
| 1317 | 1306 |
| 1318 case Token::kSHL: | 1307 case Token::kSHL: |
| 1319 return can_overflow() || | 1308 return can_overflow() || |
| 1320 !RangeUtils::IsPositive(right()->definition()->range()); | 1309 !RangeUtils::IsPositive(right()->definition()->range()); |
| 1321 | 1310 |
| 1322 case Token::kMOD: { | 1311 case Token::kMOD: { |
| 1323 Range* right_range = this->right()->definition()->range(); | 1312 Range* right_range = this->right()->definition()->range(); |
| 1324 return (right_range == NULL) || right_range->Overlaps(0, 0); | 1313 return (right_range == NULL) || right_range->Overlaps(0, 0); |
| 1325 } | 1314 } |
| 1326 default: | 1315 default: |
| 1327 return can_overflow(); | 1316 return can_overflow(); |
| 1328 } | 1317 } |
| 1329 } | 1318 } |
| 1330 | 1319 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1348 case kUnboxedMint: | 1337 case kUnboxedMint: |
| 1349 return 64; | 1338 return 64; |
| 1350 default: | 1339 default: |
| 1351 UNREACHABLE(); | 1340 UNREACHABLE(); |
| 1352 return 0; | 1341 return 0; |
| 1353 } | 1342 } |
| 1354 } | 1343 } |
| 1355 | 1344 |
| 1356 | 1345 |
| 1357 static int64_t RepresentationMask(Representation r) { | 1346 static int64_t RepresentationMask(Representation r) { |
| 1358 return static_cast<int64_t>( | 1347 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> |
| 1359 static_cast<uint64_t>(-1) >> (64 - RepresentationBits(r))); | 1348 (64 - RepresentationBits(r))); |
| 1360 } | 1349 } |
| 1361 | 1350 |
| 1362 | 1351 |
| 1363 static bool ToIntegerConstant(Value* value, int64_t* result) { | 1352 static bool ToIntegerConstant(Value* value, int64_t* result) { |
| 1364 if (!value->BindsToConstant()) { | 1353 if (!value->BindsToConstant()) { |
| 1365 UnboxInstr* unbox = value->definition()->AsUnbox(); | 1354 UnboxInstr* unbox = value->definition()->AsUnbox(); |
| 1366 if (unbox != NULL) { | 1355 if (unbox != NULL) { |
| 1367 switch (unbox->representation()) { | 1356 switch (unbox->representation()) { |
| 1368 case kUnboxedDouble: | 1357 case kUnboxedDouble: |
| 1369 case kUnboxedMint: | 1358 case kUnboxedMint: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1396 return true; | 1385 return true; |
| 1397 } else if (constant.IsMint()) { | 1386 } else if (constant.IsMint()) { |
| 1398 *result = Mint::Cast(constant).value(); | 1387 *result = Mint::Cast(constant).value(); |
| 1399 return true; | 1388 return true; |
| 1400 } | 1389 } |
| 1401 | 1390 |
| 1402 return false; | 1391 return false; |
| 1403 } | 1392 } |
| 1404 | 1393 |
| 1405 | 1394 |
| 1406 static Definition* CanonicalizeCommutativeDoubleArithmetic( | 1395 static Definition* CanonicalizeCommutativeDoubleArithmetic(Token::Kind op, |
| 1407 Token::Kind op, | 1396 Value* left, |
| 1408 Value* left, | 1397 Value* right) { |
| 1409 Value* right) { | |
| 1410 int64_t left_value; | 1398 int64_t left_value; |
| 1411 if (!ToIntegerConstant(left, &left_value)) { | 1399 if (!ToIntegerConstant(left, &left_value)) { |
| 1412 return NULL; | 1400 return NULL; |
| 1413 } | 1401 } |
| 1414 | 1402 |
| 1415 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because | 1403 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because |
| 1416 // 0.0 * NaN is NaN not 0.0. | 1404 // 0.0 * NaN is NaN not 0.0. |
| 1417 // Can't apply 0.0 + x -> x to double because 0.0 + (-0.0) is 0.0 not -0.0. | 1405 // Can't apply 0.0 + x -> x to double because 0.0 + (-0.0) is 0.0 not -0.0. |
| 1418 switch (op) { | 1406 switch (op) { |
| 1419 case Token::kMUL: | 1407 case Token::kMUL: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1435 | 1423 |
| 1436 return NULL; | 1424 return NULL; |
| 1437 } | 1425 } |
| 1438 | 1426 |
| 1439 | 1427 |
| 1440 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { | 1428 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1441 #ifdef DEBUG | 1429 #ifdef DEBUG |
| 1442 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or | 1430 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or |
| 1443 // Phis introduce by load forwarding. | 1431 // Phis introduce by load forwarding. |
| 1444 ASSERT(env_use_list() == NULL); | 1432 ASSERT(env_use_list() == NULL); |
| 1445 for (Value* use = input_use_list(); | 1433 for (Value* use = input_use_list(); use != NULL; use = use->next_use()) { |
| 1446 use != NULL; | |
| 1447 use = use->next_use()) { | |
| 1448 ASSERT(use->instruction()->IsPhi() || | 1434 ASSERT(use->instruction()->IsPhi() || |
| 1449 use->instruction()->IsFloatToDouble() || | 1435 use->instruction()->IsFloatToDouble() || |
| 1450 (use->instruction()->IsStoreIndexed() && | 1436 (use->instruction()->IsStoreIndexed() && |
| 1451 (use->instruction()->AsStoreIndexed()->class_id() == | 1437 (use->instruction()->AsStoreIndexed()->class_id() == |
| 1452 kTypedDataFloat32ArrayCid))); | 1438 kTypedDataFloat32ArrayCid))); |
| 1453 } | 1439 } |
| 1454 #endif | 1440 #endif |
| 1455 if (!HasUses()) return NULL; | 1441 if (!HasUses()) return NULL; |
| 1456 if (value()->definition()->IsFloatToDouble()) { | 1442 if (value()->definition()->IsFloatToDouble()) { |
| 1457 // F2D(D2F(v)) == v. | 1443 // F2D(D2F(v)) == v. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1476 return result; | 1462 return result; |
| 1477 } | 1463 } |
| 1478 | 1464 |
| 1479 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); | 1465 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); |
| 1480 if (result != NULL) { | 1466 if (result != NULL) { |
| 1481 return result; | 1467 return result; |
| 1482 } | 1468 } |
| 1483 | 1469 |
| 1484 if ((op_kind() == Token::kMUL) && | 1470 if ((op_kind() == Token::kMUL) && |
| 1485 (left()->definition() == right()->definition())) { | 1471 (left()->definition() == right()->definition())) { |
| 1486 MathUnaryInstr* math_unary = | 1472 MathUnaryInstr* math_unary = new MathUnaryInstr( |
| 1487 new MathUnaryInstr(MathUnaryInstr::kDoubleSquare, | 1473 MathUnaryInstr::kDoubleSquare, new Value(left()->definition()), |
| 1488 new Value(left()->definition()), | 1474 DeoptimizationTarget()); |
| 1489 DeoptimizationTarget()); | |
| 1490 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); | 1475 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); |
| 1491 return math_unary; | 1476 return math_unary; |
| 1492 } | 1477 } |
| 1493 | 1478 |
| 1494 return this; | 1479 return this; |
| 1495 } | 1480 } |
| 1496 | 1481 |
| 1497 | 1482 |
| 1498 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1483 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1499 return HasUses() ? this : NULL; | 1484 return HasUses() ? this : NULL; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 } | 1610 } |
| 1626 | 1611 |
| 1627 | 1612 |
| 1628 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { | 1613 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { |
| 1629 Thread* thread = Thread::Current(); | 1614 Thread* thread = Thread::Current(); |
| 1630 Zone* zone = thread->zone(); | 1615 Zone* zone = thread->zone(); |
| 1631 Integer& result = Integer::Handle(zone); | 1616 Integer& result = Integer::Handle(zone); |
| 1632 | 1617 |
| 1633 switch (op_kind()) { | 1618 switch (op_kind()) { |
| 1634 case Token::kNEGATE: | 1619 case Token::kNEGATE: |
| 1635 result = value.ArithmeticOp(Token::kMUL, | 1620 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(zone, Smi::New(-1)), |
| 1636 Smi::Handle(zone, Smi::New(-1)), | |
| 1637 Heap::kOld); | 1621 Heap::kOld); |
| 1638 break; | 1622 break; |
| 1639 | 1623 |
| 1640 case Token::kBIT_NOT: | 1624 case Token::kBIT_NOT: |
| 1641 if (value.IsSmi()) { | 1625 if (value.IsSmi()) { |
| 1642 result = Integer::New(~Smi::Cast(value).Value()); | 1626 result = Integer::New(~Smi::Cast(value).Value()); |
| 1643 } else if (value.IsMint()) { | 1627 } else if (value.IsMint()) { |
| 1644 result = Integer::New(~Mint::Cast(value).value()); | 1628 result = Integer::New(~Mint::Cast(value).value()); |
| 1645 } | 1629 } |
| 1646 break; | 1630 break; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1670 Zone* zone = thread->zone(); | 1654 Zone* zone = thread->zone(); |
| 1671 Integer& result = Integer::Handle(zone); | 1655 Integer& result = Integer::Handle(zone); |
| 1672 | 1656 |
| 1673 switch (op_kind()) { | 1657 switch (op_kind()) { |
| 1674 case Token::kTRUNCDIV: | 1658 case Token::kTRUNCDIV: |
| 1675 case Token::kMOD: | 1659 case Token::kMOD: |
| 1676 // Check right value for zero. | 1660 // Check right value for zero. |
| 1677 if (right.IsSmi() && right.AsInt64Value() == 0) { | 1661 if (right.IsSmi() && right.AsInt64Value() == 0) { |
| 1678 break; // Will throw. | 1662 break; // Will throw. |
| 1679 } | 1663 } |
| 1680 // Fall through. | 1664 // Fall through. |
| 1681 case Token::kADD: | 1665 case Token::kADD: |
| 1682 case Token::kSUB: | 1666 case Token::kSUB: |
| 1683 case Token::kMUL: { | 1667 case Token::kMUL: { |
| 1684 result = left.ArithmeticOp(op_kind(), right, Heap::kOld); | 1668 result = left.ArithmeticOp(op_kind(), right, Heap::kOld); |
| 1685 break; | 1669 break; |
| 1686 } | 1670 } |
| 1687 case Token::kSHL: | 1671 case Token::kSHL: |
| 1688 case Token::kSHR: | 1672 case Token::kSHR: |
| 1689 if (left.IsSmi() && right.IsSmi() && (Smi::Cast(right).Value() >= 0)) { | 1673 if (left.IsSmi() && right.IsSmi() && (Smi::Cast(right).Value() >= 0)) { |
| 1690 result = Smi::Cast(left).ShiftOp(op_kind(), | 1674 result = |
| 1691 Smi::Cast(right), | 1675 Smi::Cast(left).ShiftOp(op_kind(), Smi::Cast(right), Heap::kOld); |
| 1692 Heap::kOld); | |
| 1693 } | 1676 } |
| 1694 break; | 1677 break; |
| 1695 case Token::kBIT_AND: | 1678 case Token::kBIT_AND: |
| 1696 case Token::kBIT_OR: | 1679 case Token::kBIT_OR: |
| 1697 case Token::kBIT_XOR: { | 1680 case Token::kBIT_XOR: { |
| 1698 result = left.BitOp(op_kind(), right, Heap::kOld); | 1681 result = left.BitOp(op_kind(), right, Heap::kOld); |
| 1699 break; | 1682 break; |
| 1700 } | 1683 } |
| 1701 case Token::kDIV: | 1684 case Token::kDIV: |
| 1702 break; | 1685 break; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1721 } | 1704 } |
| 1722 | 1705 |
| 1723 return result.raw(); | 1706 return result.raw(); |
| 1724 } | 1707 } |
| 1725 | 1708 |
| 1726 | 1709 |
| 1727 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, | 1710 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, |
| 1728 const Integer& result) { | 1711 const Integer& result) { |
| 1729 Definition* result_defn = flow_graph->GetConstant(result); | 1712 Definition* result_defn = flow_graph->GetConstant(result); |
| 1730 if (representation() != kTagged) { | 1713 if (representation() != kTagged) { |
| 1731 result_defn = UnboxInstr::Create(representation(), | 1714 result_defn = UnboxInstr::Create(representation(), new Value(result_defn), |
| 1732 new Value(result_defn), | |
| 1733 GetDeoptId()); | 1715 GetDeoptId()); |
| 1734 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); | 1716 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); |
| 1735 } | 1717 } |
| 1736 return result_defn; | 1718 return result_defn; |
| 1737 } | 1719 } |
| 1738 | 1720 |
| 1739 | 1721 |
| 1740 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1722 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1741 if ((left()->Type()->ToCid() == kSmiCid) && | 1723 if ((left()->Type()->ToCid() == kSmiCid) && |
| 1742 (right()->Type()->ToCid() == kSmiCid)) { | 1724 (right()->Type()->ToCid() == kSmiCid)) { |
| 1743 Definition* replacement = NULL; | 1725 Definition* replacement = NULL; |
| 1744 // Operations that can't deoptimize are specialized here: These include | 1726 // Operations that can't deoptimize are specialized here: These include |
| 1745 // bit-wise operators and comparisons. Other arithmetic operations can | 1727 // bit-wise operators and comparisons. Other arithmetic operations can |
| 1746 // overflow or divide by 0 and can't be specialized unless we have extra | 1728 // overflow or divide by 0 and can't be specialized unless we have extra |
| 1747 // range information. | 1729 // range information. |
| 1748 switch (op_kind()) { | 1730 switch (op_kind()) { |
| 1749 case Token::kBIT_AND: | 1731 case Token::kBIT_AND: |
| 1750 case Token::kBIT_OR: | 1732 case Token::kBIT_OR: |
| 1751 case Token::kBIT_XOR: | 1733 case Token::kBIT_XOR: |
| 1752 replacement = | 1734 replacement = new BinarySmiOpInstr( |
| 1753 new BinarySmiOpInstr(op_kind(), | 1735 op_kind(), new Value(left()->definition()), |
| 1754 new Value(left()->definition()), | 1736 new Value(right()->definition()), Thread::kNoDeoptId); |
| 1755 new Value(right()->definition()), | |
| 1756 Thread::kNoDeoptId); | |
| 1757 default: | 1737 default: |
| 1758 break; | 1738 break; |
| 1759 } | 1739 } |
| 1760 if (replacement != NULL) { | 1740 if (replacement != NULL) { |
| 1761 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1741 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
| 1762 return replacement; | 1742 return replacement; |
| 1763 } | 1743 } |
| 1764 } | 1744 } |
| 1765 return this; | 1745 return this; |
| 1766 } | 1746 } |
| 1767 | 1747 |
| 1768 | 1748 |
| 1769 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands( | 1749 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(Value* left, |
| 1770 Value* left, Value* right) { | 1750 Value* right) { |
| 1771 UNREACHABLE(); | 1751 UNREACHABLE(); |
| 1772 return NULL; | 1752 return NULL; |
| 1773 } | 1753 } |
| 1774 | 1754 |
| 1775 | 1755 |
| 1776 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { | 1756 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1777 if ((left()->Type()->ToCid() == kSmiCid) && | 1757 if ((left()->Type()->ToCid() == kSmiCid) && |
| 1778 (right()->Type()->ToCid() == kSmiCid)) { | 1758 (right()->Type()->ToCid() == kSmiCid)) { |
| 1779 Definition* replacement = NULL; | 1759 Definition* replacement = NULL; |
| 1780 if (Token::IsRelationalOperator(kind())) { | 1760 if (Token::IsRelationalOperator(kind())) { |
| 1781 replacement = new RelationalOpInstr(token_pos(), kind(), | 1761 replacement = new RelationalOpInstr( |
| 1782 new Value(left()->definition()), | 1762 token_pos(), kind(), new Value(left()->definition()), |
| 1783 new Value(right()->definition()), | 1763 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
| 1784 kSmiCid, | |
| 1785 Thread::kNoDeoptId); | |
| 1786 } else if (Token::IsEqualityOperator(kind())) { | 1764 } else if (Token::IsEqualityOperator(kind())) { |
| 1787 replacement = new EqualityCompareInstr(token_pos(), kind(), | 1765 replacement = new EqualityCompareInstr( |
| 1788 new Value(left()->definition()), | 1766 token_pos(), kind(), new Value(left()->definition()), |
| 1789 new Value(right()->definition()), | 1767 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
| 1790 kSmiCid, | |
| 1791 Thread::kNoDeoptId); | |
| 1792 } | 1768 } |
| 1793 if (replacement != NULL) { | 1769 if (replacement != NULL) { |
| 1794 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1770 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
| 1795 return replacement; | 1771 return replacement; |
| 1796 } | 1772 } |
| 1797 } | 1773 } |
| 1798 return this; | 1774 return this; |
| 1799 } | 1775 } |
| 1800 | 1776 |
| 1801 | 1777 |
| 1802 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1778 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1803 // If both operands are constants evaluate this expression. Might | 1779 // If both operands are constants evaluate this expression. Might |
| 1804 // occur due to load forwarding after constant propagation pass | 1780 // occur due to load forwarding after constant propagation pass |
| 1805 // have already been run. | 1781 // have already been run. |
| 1806 if (left()->BindsToConstant() && | 1782 if (left()->BindsToConstant() && left()->BoundConstant().IsInteger() && |
| 1807 left()->BoundConstant().IsInteger() && | 1783 right()->BindsToConstant() && right()->BoundConstant().IsInteger()) { |
| 1808 right()->BindsToConstant() && | 1784 const Integer& result = |
| 1809 right()->BoundConstant().IsInteger()) { | 1785 Integer::Handle(Evaluate(Integer::Cast(left()->BoundConstant()), |
| 1810 const Integer& result = Integer::Handle( | 1786 Integer::Cast(right()->BoundConstant()))); |
| 1811 Evaluate(Integer::Cast(left()->BoundConstant()), | |
| 1812 Integer::Cast(right()->BoundConstant()))); | |
| 1813 if (!result.IsNull()) { | 1787 if (!result.IsNull()) { |
| 1814 return CreateConstantResult(flow_graph, result); | 1788 return CreateConstantResult(flow_graph, result); |
| 1815 } | 1789 } |
| 1816 } | 1790 } |
| 1817 | 1791 |
| 1818 if (left()->BindsToConstant() && | 1792 if (left()->BindsToConstant() && !right()->BindsToConstant() && |
| 1819 !right()->BindsToConstant() && | |
| 1820 IsCommutative(op_kind())) { | 1793 IsCommutative(op_kind())) { |
| 1821 Value* l = left(); | 1794 Value* l = left(); |
| 1822 Value* r = right(); | 1795 Value* r = right(); |
| 1823 SetInputAt(0, r); | 1796 SetInputAt(0, r); |
| 1824 SetInputAt(1, l); | 1797 SetInputAt(1, l); |
| 1825 } | 1798 } |
| 1826 | 1799 |
| 1827 int64_t rhs; | 1800 int64_t rhs; |
| 1828 if (!ToIntegerConstant(right(), &rhs)) { | 1801 if (!ToIntegerConstant(right(), &rhs)) { |
| 1829 return this; | 1802 return this; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1847 | 1820 |
| 1848 switch (op_kind()) { | 1821 switch (op_kind()) { |
| 1849 case Token::kMUL: | 1822 case Token::kMUL: |
| 1850 if (rhs == 1) { | 1823 if (rhs == 1) { |
| 1851 return left()->definition(); | 1824 return left()->definition(); |
| 1852 } else if (rhs == 0) { | 1825 } else if (rhs == 0) { |
| 1853 return right()->definition(); | 1826 return right()->definition(); |
| 1854 } else if (rhs == 2) { | 1827 } else if (rhs == 2) { |
| 1855 ConstantInstr* constant_1 = | 1828 ConstantInstr* constant_1 = |
| 1856 flow_graph->GetConstant(Smi::Handle(Smi::New(1))); | 1829 flow_graph->GetConstant(Smi::Handle(Smi::New(1))); |
| 1857 BinaryIntegerOpInstr* shift = | 1830 BinaryIntegerOpInstr* shift = BinaryIntegerOpInstr::Make( |
| 1858 BinaryIntegerOpInstr::Make(representation(), | 1831 representation(), Token::kSHL, left()->CopyWithType(), |
| 1859 Token::kSHL, | 1832 new Value(constant_1), GetDeoptId(), can_overflow(), |
| 1860 left()->CopyWithType(), | 1833 is_truncating(), range()); |
| 1861 new Value(constant_1), | |
| 1862 GetDeoptId(), | |
| 1863 can_overflow(), | |
| 1864 is_truncating(), | |
| 1865 range()); | |
| 1866 if (shift != NULL) { | 1834 if (shift != NULL) { |
| 1867 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue); | 1835 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue); |
| 1868 return shift; | 1836 return shift; |
| 1869 } | 1837 } |
| 1870 } | 1838 } |
| 1871 | 1839 |
| 1872 break; | 1840 break; |
| 1873 case Token::kADD: | 1841 case Token::kADD: |
| 1874 if (rhs == 0) { | 1842 if (rhs == 0) { |
| 1875 return left()->definition(); | 1843 return left()->definition(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1886 if (rhs == 0) { | 1854 if (rhs == 0) { |
| 1887 return left()->definition(); | 1855 return left()->definition(); |
| 1888 } else if (rhs == range_mask) { | 1856 } else if (rhs == range_mask) { |
| 1889 return right()->definition(); | 1857 return right()->definition(); |
| 1890 } | 1858 } |
| 1891 break; | 1859 break; |
| 1892 case Token::kBIT_XOR: | 1860 case Token::kBIT_XOR: |
| 1893 if (rhs == 0) { | 1861 if (rhs == 0) { |
| 1894 return left()->definition(); | 1862 return left()->definition(); |
| 1895 } else if (rhs == range_mask) { | 1863 } else if (rhs == range_mask) { |
| 1896 UnaryIntegerOpInstr* bit_not = | 1864 UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make( |
| 1897 UnaryIntegerOpInstr::Make(representation(), | 1865 representation(), Token::kBIT_NOT, left()->CopyWithType(), |
| 1898 Token::kBIT_NOT, | 1866 GetDeoptId(), range()); |
| 1899 left()->CopyWithType(), | |
| 1900 GetDeoptId(), | |
| 1901 range()); | |
| 1902 if (bit_not != NULL) { | 1867 if (bit_not != NULL) { |
| 1903 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue); | 1868 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue); |
| 1904 return bit_not; | 1869 return bit_not; |
| 1905 } | 1870 } |
| 1906 } | 1871 } |
| 1907 break; | 1872 break; |
| 1908 | 1873 |
| 1909 case Token::kSUB: | 1874 case Token::kSUB: |
| 1910 if (rhs == 0) { | 1875 if (rhs == 0) { |
| 1911 return left()->definition(); | 1876 return left()->definition(); |
| 1912 } | 1877 } |
| 1913 break; | 1878 break; |
| 1914 | 1879 |
| 1915 case Token::kTRUNCDIV: | 1880 case Token::kTRUNCDIV: |
| 1916 if (rhs == 1) { | 1881 if (rhs == 1) { |
| 1917 return left()->definition(); | 1882 return left()->definition(); |
| 1918 } else if (rhs == -1) { | 1883 } else if (rhs == -1) { |
| 1919 UnaryIntegerOpInstr* negation = | 1884 UnaryIntegerOpInstr* negation = UnaryIntegerOpInstr::Make( |
| 1920 UnaryIntegerOpInstr::Make(representation(), | 1885 representation(), Token::kNEGATE, left()->CopyWithType(), |
| 1921 Token::kNEGATE, | 1886 GetDeoptId(), range()); |
| 1922 left()->CopyWithType(), | |
| 1923 GetDeoptId(), | |
| 1924 range()); | |
| 1925 if (negation != NULL) { | 1887 if (negation != NULL) { |
| 1926 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue); | 1888 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue); |
| 1927 return negation; | 1889 return negation; |
| 1928 } | 1890 } |
| 1929 } | 1891 } |
| 1930 break; | 1892 break; |
| 1931 | 1893 |
| 1932 case Token::kSHR: | 1894 case Token::kSHR: |
| 1933 if (rhs == 0) { | 1895 if (rhs == 0) { |
| 1934 return left()->definition(); | 1896 return left()->definition(); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2088 value()->Type()->IsAssignableTo(dst_type())) { | 2050 value()->Type()->IsAssignableTo(dst_type())) { |
| 2089 return value()->definition(); | 2051 return value()->definition(); |
| 2090 } | 2052 } |
| 2091 | 2053 |
| 2092 // For uninstantiated target types: If the instantiator type arguments | 2054 // For uninstantiated target types: If the instantiator type arguments |
| 2093 // are constant, instantiate the target type here. | 2055 // are constant, instantiate the target type here. |
| 2094 if (dst_type().IsInstantiated()) return this; | 2056 if (dst_type().IsInstantiated()) return this; |
| 2095 | 2057 |
| 2096 ConstantInstr* constant_type_args = | 2058 ConstantInstr* constant_type_args = |
| 2097 instantiator_type_arguments()->definition()->AsConstant(); | 2059 instantiator_type_arguments()->definition()->AsConstant(); |
| 2098 if (constant_type_args != NULL && | 2060 if (constant_type_args != NULL && !constant_type_args->value().IsNull() && |
| 2099 !constant_type_args->value().IsNull() && | |
| 2100 constant_type_args->value().IsTypeArguments()) { | 2061 constant_type_args->value().IsTypeArguments()) { |
| 2101 const TypeArguments& instantiator_type_args = | 2062 const TypeArguments& instantiator_type_args = |
| 2102 TypeArguments::Cast(constant_type_args->value()); | 2063 TypeArguments::Cast(constant_type_args->value()); |
| 2103 Error& bound_error = Error::Handle(); | 2064 Error& bound_error = Error::Handle(); |
| 2104 AbstractType& new_dst_type = AbstractType::Handle( | 2065 AbstractType& new_dst_type = |
| 2105 dst_type().InstantiateFrom( | 2066 AbstractType::Handle(dst_type().InstantiateFrom( |
| 2106 instantiator_type_args, &bound_error, NULL, NULL, Heap::kOld)); | 2067 instantiator_type_args, &bound_error, NULL, NULL, Heap::kOld)); |
| 2107 if (new_dst_type.IsMalformedOrMalbounded() || !bound_error.IsNull()) { | 2068 if (new_dst_type.IsMalformedOrMalbounded() || !bound_error.IsNull()) { |
| 2108 return this; | 2069 return this; |
| 2109 } | 2070 } |
| 2110 if (new_dst_type.IsTypeRef()) { | 2071 if (new_dst_type.IsTypeRef()) { |
| 2111 new_dst_type = TypeRef::Cast(new_dst_type).type(); | 2072 new_dst_type = TypeRef::Cast(new_dst_type).type(); |
| 2112 } | 2073 } |
| 2113 new_dst_type = new_dst_type.Canonicalize(); | 2074 new_dst_type = new_dst_type.Canonicalize(); |
| 2114 set_dst_type(new_dst_type); | 2075 set_dst_type(new_dst_type); |
| 2115 | 2076 |
| 2116 if (new_dst_type.IsDynamicType() || | 2077 if (new_dst_type.IsDynamicType() || new_dst_type.IsObjectType() || |
| 2117 new_dst_type.IsObjectType() || | |
| 2118 (FLAG_eliminate_type_checks && | 2078 (FLAG_eliminate_type_checks && |
| 2119 value()->Type()->IsAssignableTo(new_dst_type))) { | 2079 value()->Type()->IsAssignableTo(new_dst_type))) { |
| 2120 return value()->definition(); | 2080 return value()->definition(); |
| 2121 } | 2081 } |
| 2122 | 2082 |
| 2123 ConstantInstr* null_constant = flow_graph->constant_null(); | 2083 ConstantInstr* null_constant = flow_graph->constant_null(); |
| 2124 instantiator_type_arguments()->BindTo(null_constant); | 2084 instantiator_type_arguments()->BindTo(null_constant); |
| 2125 } | 2085 } |
| 2126 return this; | 2086 return this; |
| 2127 } | 2087 } |
| 2128 | 2088 |
| 2129 | 2089 |
| 2130 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { | 2090 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2131 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; | 2091 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; |
| 2132 } | 2092 } |
| 2133 | 2093 |
| 2134 | 2094 |
| 2135 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, | 2095 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, |
| 2136 bool opt) const { | 2096 bool opt) const { |
| 2137 const intptr_t kNumInputs = 0; | 2097 const intptr_t kNumInputs = 0; |
| 2138 const intptr_t kNumTemps = 0; | 2098 const intptr_t kNumTemps = 0; |
| 2139 LocationSummary* locs = new(zone) LocationSummary( | 2099 LocationSummary* locs = new (zone) |
| 2140 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2100 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
| 2141 return locs; | 2101 return locs; |
| 2142 } | 2102 } |
| 2143 | 2103 |
| 2144 | 2104 |
| 2145 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { | 2105 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2146 return NULL; | 2106 return NULL; |
| 2147 } | 2107 } |
| 2148 | 2108 |
| 2149 | 2109 |
| 2150 static bool HasTryBlockUse(Value* use_list) { | 2110 static bool HasTryBlockUse(Value* use_list) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 break; | 2171 break; |
| 2212 case kUnboxedUint32: | 2172 case kUnboxedUint32: |
| 2213 replacement = new BoxUint32Instr(conv->value()->CopyWithType()); | 2173 replacement = new BoxUint32Instr(conv->value()->CopyWithType()); |
| 2214 break; | 2174 break; |
| 2215 default: | 2175 default: |
| 2216 UNREACHABLE(); | 2176 UNREACHABLE(); |
| 2217 break; | 2177 break; |
| 2218 } | 2178 } |
| 2219 | 2179 |
| 2220 if (replacement != this) { | 2180 if (replacement != this) { |
| 2221 flow_graph->InsertBefore(this, | 2181 flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue); |
| 2222 replacement, | |
| 2223 NULL, | |
| 2224 FlowGraph::kValue); | |
| 2225 } | 2182 } |
| 2226 | 2183 |
| 2227 return replacement; | 2184 return replacement; |
| 2228 } | 2185 } |
| 2229 | 2186 |
| 2230 return this; | 2187 return this; |
| 2231 } | 2188 } |
| 2232 | 2189 |
| 2233 | 2190 |
| 2234 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { | 2191 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2235 if (!HasUses() && !CanDeoptimize()) return NULL; | 2192 if (!HasUses() && !CanDeoptimize()) return NULL; |
| 2236 | 2193 |
| 2237 // Fold away Unbox<rep>(Box<rep>(v)). | 2194 // Fold away Unbox<rep>(Box<rep>(v)). |
| 2238 BoxInstr* box_defn = value()->definition()->AsBox(); | 2195 BoxInstr* box_defn = value()->definition()->AsBox(); |
| 2239 if ((box_defn != NULL) && | 2196 if ((box_defn != NULL) && |
| 2240 (box_defn->from_representation() == representation())) { | 2197 (box_defn->from_representation() == representation())) { |
| 2241 return box_defn->value()->definition(); | 2198 return box_defn->value()->definition(); |
| 2242 } | 2199 } |
| 2243 | 2200 |
| 2244 if ((representation() == kUnboxedDouble) && value()->BindsToConstant()) { | 2201 if ((representation() == kUnboxedDouble) && value()->BindsToConstant()) { |
| 2245 UnboxedConstantInstr* uc = NULL; | 2202 UnboxedConstantInstr* uc = NULL; |
| 2246 | 2203 |
| 2247 const Object& val = value()->BoundConstant(); | 2204 const Object& val = value()->BoundConstant(); |
| 2248 if (val.IsSmi()) { | 2205 if (val.IsSmi()) { |
| 2249 const Double& double_val = Double::ZoneHandle(flow_graph->zone(), | 2206 const Double& double_val = Double::ZoneHandle( |
| 2207 flow_graph->zone(), |
| 2250 Double::NewCanonical(Smi::Cast(val).AsDoubleValue())); | 2208 Double::NewCanonical(Smi::Cast(val).AsDoubleValue())); |
| 2251 uc = new UnboxedConstantInstr(double_val, kUnboxedDouble); | 2209 uc = new UnboxedConstantInstr(double_val, kUnboxedDouble); |
| 2252 } else if (val.IsDouble()) { | 2210 } else if (val.IsDouble()) { |
| 2253 uc = new UnboxedConstantInstr(val, kUnboxedDouble); | 2211 uc = new UnboxedConstantInstr(val, kUnboxedDouble); |
| 2254 } | 2212 } |
| 2255 | 2213 |
| 2256 if (uc != NULL) { | 2214 if (uc != NULL) { |
| 2257 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2215 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
| 2258 return uc; | 2216 return uc; |
| 2259 } | 2217 } |
| 2260 } | 2218 } |
| 2261 | 2219 |
| 2262 return this; | 2220 return this; |
| 2263 } | 2221 } |
| 2264 | 2222 |
| 2265 | 2223 |
| 2266 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { | 2224 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2267 if (!HasUses() && !CanDeoptimize()) return NULL; | 2225 if (!HasUses() && !CanDeoptimize()) return NULL; |
| 2268 | 2226 |
| 2269 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). | 2227 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). |
| 2270 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); | 2228 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); |
| 2271 if (box_defn != NULL) { | 2229 if (box_defn != NULL) { |
| 2272 Representation from_representation = | 2230 Representation from_representation = |
| 2273 box_defn->value()->definition()->representation(); | 2231 box_defn->value()->definition()->representation(); |
| 2274 if (from_representation == representation()) { | 2232 if (from_representation == representation()) { |
| 2275 return box_defn->value()->definition(); | 2233 return box_defn->value()->definition(); |
| 2276 } else { | 2234 } else { |
| 2277 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( | 2235 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
| 2278 from_representation, | 2236 from_representation, representation(), |
| 2279 representation(), | |
| 2280 box_defn->value()->CopyWithType(), | 2237 box_defn->value()->CopyWithType(), |
| 2281 (representation() == kUnboxedInt32) ? | 2238 (representation() == kUnboxedInt32) ? GetDeoptId() |
| 2282 GetDeoptId() : Thread::kNoDeoptId); | 2239 : Thread::kNoDeoptId); |
| 2283 // TODO(vegorov): marking resulting converter as truncating when | 2240 // TODO(vegorov): marking resulting converter as truncating when |
| 2284 // unboxing can't deoptimize is a workaround for the missing | 2241 // unboxing can't deoptimize is a workaround for the missing |
| 2285 // deoptimization environment when we insert converter after | 2242 // deoptimization environment when we insert converter after |
| 2286 // EliminateEnvironments and there is a mismatch between predicates | 2243 // EliminateEnvironments and there is a mismatch between predicates |
| 2287 // UnboxIntConverterInstr::CanDeoptimize and UnboxInt32::CanDeoptimize. | 2244 // UnboxIntConverterInstr::CanDeoptimize and UnboxInt32::CanDeoptimize. |
| 2288 if ((representation() == kUnboxedInt32) && | 2245 if ((representation() == kUnboxedInt32) && |
| 2289 (is_truncating() || !CanDeoptimize())) { | 2246 (is_truncating() || !CanDeoptimize())) { |
| 2290 converter->mark_truncating(); | 2247 converter->mark_truncating(); |
| 2291 } | 2248 } |
| 2292 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2249 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
| 2293 return converter; | 2250 return converter; |
| 2294 } | 2251 } |
| 2295 } | 2252 } |
| 2296 | 2253 |
| 2297 return this; | 2254 return this; |
| 2298 } | 2255 } |
| 2299 | 2256 |
| 2300 | 2257 |
| 2301 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { | 2258 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { |
| 2302 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); | 2259 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); |
| 2303 if (replacement != this) { | 2260 if (replacement != this) { |
| 2304 return replacement; | 2261 return replacement; |
| 2305 } | 2262 } |
| 2306 | 2263 |
| 2307 ConstantInstr* c = value()->definition()->AsConstant(); | 2264 ConstantInstr* c = value()->definition()->AsConstant(); |
| 2308 if ((c != NULL) && c->value().IsSmi()) { | 2265 if ((c != NULL) && c->value().IsSmi()) { |
| 2309 if (!is_truncating() && (kSmiBits > 32)) { | 2266 if (!is_truncating() && (kSmiBits > 32)) { |
| 2310 // Check that constant fits into 32-bit integer. | 2267 // Check that constant fits into 32-bit integer. |
| 2311 const int64_t value = | 2268 const int64_t value = static_cast<int64_t>(Smi::Cast(c->value()).Value()); |
| 2312 static_cast<int64_t>(Smi::Cast(c->value()).Value()); | |
| 2313 if (!Utils::IsInt(32, value)) { | 2269 if (!Utils::IsInt(32, value)) { |
| 2314 return this; | 2270 return this; |
| 2315 } | 2271 } |
| 2316 } | 2272 } |
| 2317 | 2273 |
| 2318 UnboxedConstantInstr* uc = | 2274 UnboxedConstantInstr* uc = |
| 2319 new UnboxedConstantInstr(c->value(), kUnboxedInt32); | 2275 new UnboxedConstantInstr(c->value(), kUnboxedInt32); |
| 2320 if (c->range() != NULL) { | 2276 if (c->range() != NULL) { |
| 2321 uc->set_range(*c->range()); | 2277 uc->set_range(*c->range()); |
| 2322 } | 2278 } |
| 2323 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2279 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
| 2324 return uc; | 2280 return uc; |
| 2325 } | 2281 } |
| 2326 | 2282 |
| 2327 return this; | 2283 return this; |
| 2328 } | 2284 } |
| 2329 | 2285 |
| 2330 | 2286 |
| 2331 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { | 2287 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2332 if (!HasUses()) return NULL; | 2288 if (!HasUses()) return NULL; |
| 2333 | 2289 |
| 2334 UnboxedIntConverterInstr* box_defn = | 2290 UnboxedIntConverterInstr* box_defn = |
| 2335 value()->definition()->AsUnboxedIntConverter(); | 2291 value()->definition()->AsUnboxedIntConverter(); |
| 2336 if ((box_defn != NULL) && (box_defn->representation() == from())) { | 2292 if ((box_defn != NULL) && (box_defn->representation() == from())) { |
| 2337 if (box_defn->from() == to()) { | 2293 if (box_defn->from() == to()) { |
| 2338 return box_defn->value()->definition(); | 2294 return box_defn->value()->definition(); |
| 2339 } | 2295 } |
| 2340 | 2296 |
| 2341 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( | 2297 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
| 2342 box_defn->from(), | 2298 box_defn->from(), representation(), box_defn->value()->CopyWithType(), |
| 2343 representation(), | |
| 2344 box_defn->value()->CopyWithType(), | |
| 2345 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); | 2299 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); |
| 2346 if ((representation() == kUnboxedInt32) && is_truncating()) { | 2300 if ((representation() == kUnboxedInt32) && is_truncating()) { |
| 2347 converter->mark_truncating(); | 2301 converter->mark_truncating(); |
| 2348 } | 2302 } |
| 2349 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2303 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
| 2350 return converter; | 2304 return converter; |
| 2351 } | 2305 } |
| 2352 | 2306 |
| 2353 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); | 2307 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); |
| 2354 if (unbox_defn != NULL && | 2308 if (unbox_defn != NULL && (from() == kUnboxedMint) && |
| 2355 (from() == kUnboxedMint) && | 2309 (to() == kUnboxedInt32) && unbox_defn->HasOnlyInputUse(value())) { |
| 2356 (to() == kUnboxedInt32) && | |
| 2357 unbox_defn->HasOnlyInputUse(value())) { | |
| 2358 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter | 2310 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter |
| 2359 // and code path that unboxes Mint into Int32. We should just schedule | 2311 // and code path that unboxes Mint into Int32. We should just schedule |
| 2360 // these instructions close to each other instead of fusing them. | 2312 // these instructions close to each other instead of fusing them. |
| 2361 Definition* replacement = | 2313 Definition* replacement = |
| 2362 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate | 2314 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate |
| 2363 : UnboxInt32Instr::kNoTruncation, | 2315 : UnboxInt32Instr::kNoTruncation, |
| 2364 unbox_defn->value()->CopyWithType(), | 2316 unbox_defn->value()->CopyWithType(), GetDeoptId()); |
| 2365 GetDeoptId()); | 2317 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
| 2366 flow_graph->InsertBefore(this, | |
| 2367 replacement, | |
| 2368 env(), | |
| 2369 FlowGraph::kValue); | |
| 2370 return replacement; | 2318 return replacement; |
| 2371 } | 2319 } |
| 2372 | 2320 |
| 2373 return this; | 2321 return this; |
| 2374 } | 2322 } |
| 2375 | 2323 |
| 2376 | 2324 |
| 2377 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { | 2325 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2378 Definition* defn = value()->definition(); | 2326 Definition* defn = value()->definition(); |
| 2379 if (defn->IsComparison() && | 2327 if (defn->IsComparison() && defn->HasOnlyUse(value()) && |
| 2380 defn->HasOnlyUse(value()) && | |
| 2381 defn->Type()->ToCid() == kBoolCid) { | 2328 defn->Type()->ToCid() == kBoolCid) { |
| 2382 defn->AsComparison()->NegateComparison(); | 2329 defn->AsComparison()->NegateComparison(); |
| 2383 return defn; | 2330 return defn; |
| 2384 } | 2331 } |
| 2385 return this; | 2332 return this; |
| 2386 } | 2333 } |
| 2387 | 2334 |
| 2388 | 2335 |
| 2389 static bool MayBeBoxableNumber(intptr_t cid) { | 2336 static bool MayBeBoxableNumber(intptr_t cid) { |
| 2390 return (cid == kDynamicCid) || | 2337 return (cid == kDynamicCid) || (cid == kMintCid) || (cid == kBigintCid) || |
| 2391 (cid == kMintCid) || | |
| 2392 (cid == kBigintCid) || | |
| 2393 (cid == kDoubleCid); | 2338 (cid == kDoubleCid); |
| 2394 } | 2339 } |
| 2395 | 2340 |
| 2396 | 2341 |
| 2397 static bool MaybeNumber(CompileType* type) { | 2342 static bool MaybeNumber(CompileType* type) { |
| 2398 ASSERT(Type::Handle(Type::Number()).IsMoreSpecificThan( | 2343 ASSERT(Type::Handle(Type::Number()) |
| 2399 Type::Handle(Type::Number()), NULL, NULL, Heap::kOld)); | 2344 .IsMoreSpecificThan(Type::Handle(Type::Number()), NULL, NULL, |
| 2400 return type->ToAbstractType()->IsDynamicType() | 2345 Heap::kOld)); |
| 2401 || type->ToAbstractType()->IsObjectType() | 2346 return type->ToAbstractType()->IsDynamicType() || |
| 2402 || type->ToAbstractType()->IsTypeParameter() | 2347 type->ToAbstractType()->IsObjectType() || |
| 2403 || type->IsMoreSpecificThan(Type::Handle(Type::Number())); | 2348 type->ToAbstractType()->IsTypeParameter() || |
| 2349 type->IsMoreSpecificThan(Type::Handle(Type::Number())); |
| 2404 } | 2350 } |
| 2405 | 2351 |
| 2406 | 2352 |
| 2407 // Returns a replacement for a strict comparison and signals if the result has | 2353 // Returns a replacement for a strict comparison and signals if the result has |
| 2408 // to be negated. | 2354 // to be negated. |
| 2409 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, | 2355 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, |
| 2410 bool* negated, | 2356 bool* negated, |
| 2411 bool is_branch) { | 2357 bool is_branch) { |
| 2412 // Use propagated cid and type information to eliminate number checks. | 2358 // Use propagated cid and type information to eliminate number checks. |
| 2413 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or | 2359 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or |
| 2414 // is not a subtype of num, no need for number checks. | 2360 // is not a subtype of num, no need for number checks. |
| 2415 if (compare->needs_number_check()) { | 2361 if (compare->needs_number_check()) { |
| 2416 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || | 2362 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || |
| 2417 !MayBeBoxableNumber(compare->right()->Type()->ToCid())) { | 2363 !MayBeBoxableNumber(compare->right()->Type()->ToCid())) { |
| 2418 compare->set_needs_number_check(false); | 2364 compare->set_needs_number_check(false); |
| 2419 } else if (!MaybeNumber(compare->left()->Type()) || | 2365 } else if (!MaybeNumber(compare->left()->Type()) || |
| 2420 !MaybeNumber(compare->right()->Type())) { | 2366 !MaybeNumber(compare->right()->Type())) { |
| 2421 compare->set_needs_number_check(false); | 2367 compare->set_needs_number_check(false); |
| 2422 } | 2368 } |
| 2423 } | 2369 } |
| 2424 *negated = false; | 2370 *negated = false; |
| 2425 PassiveObject& constant = PassiveObject::Handle(); | 2371 PassiveObject& constant = PassiveObject::Handle(); |
| 2426 Value* other = NULL; | 2372 Value* other = NULL; |
| 2427 if (compare->right()->BindsToConstant()) { | 2373 if (compare->right()->BindsToConstant()) { |
| 2428 constant = compare->right()->BoundConstant().raw(); | 2374 constant = compare->right()->BoundConstant().raw(); |
| 2429 other = compare->left(); | 2375 other = compare->left(); |
| 2430 } else if (compare->left()->BindsToConstant()) { | 2376 } else if (compare->left()->BindsToConstant()) { |
| 2431 constant = compare->left()->BoundConstant().raw(); | 2377 constant = compare->left()->BoundConstant().raw(); |
| 2432 other = compare->right(); | 2378 other = compare->right(); |
| 2433 } else { | 2379 } else { |
| 2434 return compare; | 2380 return compare; |
| 2435 } | 2381 } |
| 2436 | 2382 |
| 2437 const bool can_merge = is_branch || (other->Type()->ToCid() == kBoolCid); | 2383 const bool can_merge = is_branch || (other->Type()->ToCid() == kBoolCid); |
| 2438 Definition* other_defn = other->definition(); | 2384 Definition* other_defn = other->definition(); |
| 2439 Token::Kind kind = compare->kind(); | 2385 Token::Kind kind = compare->kind(); |
| 2440 // Handle e === true. | 2386 // Handle e === true. |
| 2441 if ((kind == Token::kEQ_STRICT) && | 2387 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::True().raw()) && |
| 2442 (constant.raw() == Bool::True().raw()) && | |
| 2443 can_merge) { | 2388 can_merge) { |
| 2444 return other_defn; | 2389 return other_defn; |
| 2445 } | 2390 } |
| 2446 // Handle e !== false. | 2391 // Handle e !== false. |
| 2447 if ((kind == Token::kNE_STRICT) && | 2392 if ((kind == Token::kNE_STRICT) && (constant.raw() == Bool::False().raw()) && |
| 2448 (constant.raw() == Bool::False().raw()) && | |
| 2449 can_merge) { | 2393 can_merge) { |
| 2450 return other_defn; | 2394 return other_defn; |
| 2451 } | 2395 } |
| 2452 // Handle e !== true. | 2396 // Handle e !== true. |
| 2453 if ((kind == Token::kNE_STRICT) && | 2397 if ((kind == Token::kNE_STRICT) && (constant.raw() == Bool::True().raw()) && |
| 2454 (constant.raw() == Bool::True().raw()) && | 2398 other_defn->IsComparison() && can_merge && |
| 2455 other_defn->IsComparison() && | |
| 2456 can_merge && | |
| 2457 other_defn->HasOnlyUse(other)) { | 2399 other_defn->HasOnlyUse(other)) { |
| 2458 *negated = true; | 2400 *negated = true; |
| 2459 return other_defn; | 2401 return other_defn; |
| 2460 } | 2402 } |
| 2461 // Handle e === false. | 2403 // Handle e === false. |
| 2462 if ((kind == Token::kEQ_STRICT) && | 2404 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::False().raw()) && |
| 2463 (constant.raw() == Bool::False().raw()) && | 2405 other_defn->IsComparison() && can_merge && |
| 2464 other_defn->IsComparison() && | |
| 2465 can_merge && | |
| 2466 other_defn->HasOnlyUse(other)) { | 2406 other_defn->HasOnlyUse(other)) { |
| 2467 *negated = true; | 2407 *negated = true; |
| 2468 return other_defn; | 2408 return other_defn; |
| 2469 } | 2409 } |
| 2470 return compare; | 2410 return compare; |
| 2471 } | 2411 } |
| 2472 | 2412 |
| 2473 | 2413 |
| 2474 static bool BindsToGivenConstant(Value* v, intptr_t expected) { | 2414 static bool BindsToGivenConstant(Value* v, intptr_t expected) { |
| 2475 return v->BindsToConstant() && | 2415 return v->BindsToConstant() && v->BoundConstant().IsSmi() && |
| 2476 v->BoundConstant().IsSmi() && | 2416 (Smi::Cast(v->BoundConstant()).Value() == expected); |
| 2477 (Smi::Cast(v->BoundConstant()).Value() == expected); | |
| 2478 } | 2417 } |
| 2479 | 2418 |
| 2480 | 2419 |
| 2481 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. | 2420 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. |
| 2482 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { | 2421 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { |
| 2483 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { | 2422 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { |
| 2484 return false; | 2423 return false; |
| 2485 } | 2424 } |
| 2486 | 2425 |
| 2487 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); | 2426 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); |
| 2488 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { | 2427 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { |
| 2489 return false; | 2428 return false; |
| 2490 } | 2429 } |
| 2491 | 2430 |
| 2492 | 2431 |
| 2493 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); | 2432 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); |
| 2494 if ((mask_op == NULL) || | 2433 if ((mask_op == NULL) || (mask_op->op_kind() != Token::kBIT_AND) || |
| 2495 (mask_op->op_kind() != Token::kBIT_AND) || | |
| 2496 !mask_op->HasOnlyUse(left)) { | 2434 !mask_op->HasOnlyUse(left)) { |
| 2497 return false; | 2435 return false; |
| 2498 } | 2436 } |
| 2499 | 2437 |
| 2500 if (value == 0) { | 2438 if (value == 0) { |
| 2501 // Recognized (a & b) == 0 pattern. | 2439 // Recognized (a & b) == 0 pattern. |
| 2502 *negate = false; | 2440 *negate = false; |
| 2503 return true; | 2441 return true; |
| 2504 } | 2442 } |
| 2505 | 2443 |
| 2506 // Recognize | 2444 // Recognize |
| 2507 if (BindsToGivenConstant(mask_op->left(), value) || | 2445 if (BindsToGivenConstant(mask_op->left(), value) || |
| 2508 BindsToGivenConstant(mask_op->right(), value)) { | 2446 BindsToGivenConstant(mask_op->right(), value)) { |
| 2509 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 | 2447 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 |
| 2510 // so we need to negate original comparison. | 2448 // so we need to negate original comparison. |
| 2511 *negate = true; | 2449 *negate = true; |
| 2512 return true; | 2450 return true; |
| 2513 } | 2451 } |
| 2514 | 2452 |
| 2515 return false; | 2453 return false; |
| 2516 } | 2454 } |
| 2517 | 2455 |
| 2518 | 2456 |
| 2519 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { | 2457 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2520 Zone* zone = flow_graph->zone(); | 2458 Zone* zone = flow_graph->zone(); |
| 2521 // Only handle strict-compares. | 2459 // Only handle strict-compares. |
| 2522 if (comparison()->IsStrictCompare()) { | 2460 if (comparison()->IsStrictCompare()) { |
| 2523 bool negated = false; | 2461 bool negated = false; |
| 2524 Definition* replacement = | 2462 Definition* replacement = CanonicalizeStrictCompare( |
| 2525 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), | 2463 comparison()->AsStrictCompare(), &negated, /* is_branch = */ true); |
| 2526 &negated, /* is_branch = */ true); | |
| 2527 if (replacement == comparison()) { | 2464 if (replacement == comparison()) { |
| 2528 return this; | 2465 return this; |
| 2529 } | 2466 } |
| 2530 ComparisonInstr* comp = replacement->AsComparison(); | 2467 ComparisonInstr* comp = replacement->AsComparison(); |
| 2531 if ((comp == NULL) || | 2468 if ((comp == NULL) || comp->CanDeoptimize() || |
| 2532 comp->CanDeoptimize() || | |
| 2533 comp->HasUnmatchedInputRepresentations()) { | 2469 comp->HasUnmatchedInputRepresentations()) { |
| 2534 return this; | 2470 return this; |
| 2535 } | 2471 } |
| 2536 | 2472 |
| 2537 // Replace the comparison if the replacement is used at this branch, | 2473 // Replace the comparison if the replacement is used at this branch, |
| 2538 // and has exactly one use. | 2474 // and has exactly one use. |
| 2539 Value* use = comp->input_use_list(); | 2475 Value* use = comp->input_use_list(); |
| 2540 if ((use->instruction() == this) && comp->HasOnlyUse(use)) { | 2476 if ((use->instruction() == this) && comp->HasOnlyUse(use)) { |
| 2541 if (negated) { | 2477 if (negated) { |
| 2542 comp->NegateComparison(); | 2478 comp->NegateComparison(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2555 // Clear the comparison's temp index and ssa temp index since the | 2491 // Clear the comparison's temp index and ssa temp index since the |
| 2556 // value of the comparison is not used outside the branch anymore. | 2492 // value of the comparison is not used outside the branch anymore. |
| 2557 ASSERT(comp->input_use_list() == NULL); | 2493 ASSERT(comp->input_use_list() == NULL); |
| 2558 comp->ClearSSATempIndex(); | 2494 comp->ClearSSATempIndex(); |
| 2559 comp->ClearTempIndex(); | 2495 comp->ClearTempIndex(); |
| 2560 } | 2496 } |
| 2561 } else if (comparison()->IsEqualityCompare() && | 2497 } else if (comparison()->IsEqualityCompare() && |
| 2562 comparison()->operation_cid() == kSmiCid) { | 2498 comparison()->operation_cid() == kSmiCid) { |
| 2563 BinarySmiOpInstr* bit_and = NULL; | 2499 BinarySmiOpInstr* bit_and = NULL; |
| 2564 bool negate = false; | 2500 bool negate = false; |
| 2565 if (RecognizeTestPattern(comparison()->left(), | 2501 if (RecognizeTestPattern(comparison()->left(), comparison()->right(), |
| 2566 comparison()->right(), | |
| 2567 &negate)) { | 2502 &negate)) { |
| 2568 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); | 2503 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); |
| 2569 } else if (RecognizeTestPattern(comparison()->right(), | 2504 } else if (RecognizeTestPattern(comparison()->right(), comparison()->left(), |
| 2570 comparison()->left(), | |
| 2571 &negate)) { | 2505 &negate)) { |
| 2572 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); | 2506 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); |
| 2573 } | 2507 } |
| 2574 if (bit_and != NULL) { | 2508 if (bit_and != NULL) { |
| 2575 if (FLAG_trace_optimization) { | 2509 if (FLAG_trace_optimization) { |
| 2576 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); | 2510 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); |
| 2577 } | 2511 } |
| 2578 TestSmiInstr* test = new TestSmiInstr( | 2512 TestSmiInstr* test = new TestSmiInstr( |
| 2579 comparison()->token_pos(), | 2513 comparison()->token_pos(), |
| 2580 negate ? Token::NegateComparison(comparison()->kind()) | 2514 negate ? Token::NegateComparison(comparison()->kind()) |
| 2581 : comparison()->kind(), | 2515 : comparison()->kind(), |
| 2582 bit_and->left()->Copy(zone), | 2516 bit_and->left()->Copy(zone), bit_and->right()->Copy(zone)); |
| 2583 bit_and->right()->Copy(zone)); | |
| 2584 ASSERT(!CanDeoptimize()); | 2517 ASSERT(!CanDeoptimize()); |
| 2585 RemoveEnvironment(); | 2518 RemoveEnvironment(); |
| 2586 flow_graph->CopyDeoptTarget(this, bit_and); | 2519 flow_graph->CopyDeoptTarget(this, bit_and); |
| 2587 SetComparison(test); | 2520 SetComparison(test); |
| 2588 bit_and->RemoveFromGraph(); | 2521 bit_and->RemoveFromGraph(); |
| 2589 } | 2522 } |
| 2590 } | 2523 } |
| 2591 return this; | 2524 return this; |
| 2592 } | 2525 } |
| 2593 | 2526 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2611 return this; | 2544 return this; |
| 2612 } | 2545 } |
| 2613 | 2546 |
| 2614 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; | 2547 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; |
| 2615 } | 2548 } |
| 2616 | 2549 |
| 2617 | 2550 |
| 2618 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { | 2551 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2619 if (value()->BindsToConstant()) { | 2552 if (value()->BindsToConstant()) { |
| 2620 const Object& constant_value = value()->BoundConstant(); | 2553 const Object& constant_value = value()->BoundConstant(); |
| 2621 if (constant_value.IsSmi() && | 2554 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { |
| 2622 Smi::Cast(constant_value).Value() == cid_) { | |
| 2623 return NULL; | 2555 return NULL; |
| 2624 } | 2556 } |
| 2625 } | 2557 } |
| 2626 return this; | 2558 return this; |
| 2627 } | 2559 } |
| 2628 | 2560 |
| 2629 | 2561 |
| 2630 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { | 2562 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2631 CompileType* in_type = left()->Type(); | 2563 CompileType* in_type = left()->Type(); |
| 2632 intptr_t cid = in_type->ToCid(); | 2564 intptr_t cid = in_type->ToCid(); |
| 2633 if (cid == kDynamicCid) return this; | 2565 if (cid == kDynamicCid) return this; |
| 2634 | 2566 |
| 2635 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 2567 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
| 2636 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 2568 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
| 2637 for (intptr_t i = 0; i < data.length(); i += 2) { | 2569 for (intptr_t i = 0; i < data.length(); i += 2) { |
| 2638 if (data[i] == cid) { | 2570 if (data[i] == cid) { |
| 2639 return (data[i + 1] == true_result) | 2571 return (data[i + 1] == true_result) |
| 2640 ? flow_graph->GetConstant(Bool::True()) | 2572 ? flow_graph->GetConstant(Bool::True()) |
| 2641 : flow_graph->GetConstant(Bool::False()); | 2573 : flow_graph->GetConstant(Bool::False()); |
| 2642 } | 2574 } |
| 2643 } | 2575 } |
| 2644 | 2576 |
| 2645 // TODO(sra): Handle misses if the instruction is not deoptimizing. | 2577 // TODO(sra): Handle misses if the instruction is not deoptimizing. |
| 2646 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare | 2578 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare |
| 2647 // against `null`. | 2579 // against `null`. |
| 2648 return this; | 2580 return this; |
| 2649 } | 2581 } |
| 2650 | 2582 |
| 2651 | 2583 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2682 StaticCallInstr* call = value()->definition()->AsStaticCall(); | 2614 StaticCallInstr* call = value()->definition()->AsStaticCall(); |
| 2683 if (call == NULL) { | 2615 if (call == NULL) { |
| 2684 return this; | 2616 return this; |
| 2685 } | 2617 } |
| 2686 | 2618 |
| 2687 ConstantInstr* length = NULL; | 2619 ConstantInstr* length = NULL; |
| 2688 if (call->is_known_list_constructor() && | 2620 if (call->is_known_list_constructor() && |
| 2689 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { | 2621 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { |
| 2690 length = call->ArgumentAt(1)->AsConstant(); | 2622 length = call->ArgumentAt(1)->AsConstant(); |
| 2691 } | 2623 } |
| 2692 if ((length != NULL) && | 2624 if ((length != NULL) && length->value().IsSmi() && |
| 2693 length->value().IsSmi() && | |
| 2694 Smi::Cast(length->value()).Value() == expected_length) { | 2625 Smi::Cast(length->value()).Value() == expected_length) { |
| 2695 return NULL; // Expected length matched. | 2626 return NULL; // Expected length matched. |
| 2696 } | 2627 } |
| 2697 | 2628 |
| 2698 return this; | 2629 return this; |
| 2699 } | 2630 } |
| 2700 | 2631 |
| 2701 | 2632 |
| 2702 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2633 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2703 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; | 2634 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; |
| 2704 } | 2635 } |
| 2705 | 2636 |
| 2706 | 2637 |
| 2707 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2638 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2708 if ((left()->Type()->ToCid() == kDoubleCid) || | 2639 if ((left()->Type()->ToCid() == kDoubleCid) || |
| 2709 (right()->Type()->ToCid() == kDoubleCid)) { | 2640 (right()->Type()->ToCid() == kDoubleCid)) { |
| 2710 return NULL; // Remove from the graph. | 2641 return NULL; // Remove from the graph. |
| 2711 } | 2642 } |
| 2712 return this; | 2643 return this; |
| 2713 } | 2644 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2735 return NULL; | 2666 return NULL; |
| 2736 } | 2667 } |
| 2737 } | 2668 } |
| 2738 | 2669 |
| 2739 | 2670 |
| 2740 UnboxInstr* UnboxInstr::Create(Representation to, | 2671 UnboxInstr* UnboxInstr::Create(Representation to, |
| 2741 Value* value, | 2672 Value* value, |
| 2742 intptr_t deopt_id) { | 2673 intptr_t deopt_id) { |
| 2743 switch (to) { | 2674 switch (to) { |
| 2744 case kUnboxedInt32: | 2675 case kUnboxedInt32: |
| 2745 return new UnboxInt32Instr( | 2676 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, |
| 2746 UnboxInt32Instr::kNoTruncation, value, deopt_id); | 2677 deopt_id); |
| 2747 | 2678 |
| 2748 case kUnboxedUint32: | 2679 case kUnboxedUint32: |
| 2749 return new UnboxUint32Instr(value, deopt_id); | 2680 return new UnboxUint32Instr(value, deopt_id); |
| 2750 | 2681 |
| 2751 case kUnboxedMint: | 2682 case kUnboxedMint: |
| 2752 return new UnboxInt64Instr(value, deopt_id); | 2683 return new UnboxInt64Instr(value, deopt_id); |
| 2753 | 2684 |
| 2754 case kUnboxedDouble: | 2685 case kUnboxedDouble: |
| 2755 case kUnboxedFloat32x4: | 2686 case kUnboxedFloat32x4: |
| 2756 case kUnboxedFloat64x2: | 2687 case kUnboxedFloat64x2: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2799 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, | 2730 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, |
| 2800 bool optimizing) const { | 2731 bool optimizing) const { |
| 2801 UNREACHABLE(); | 2732 UNREACHABLE(); |
| 2802 return NULL; | 2733 return NULL; |
| 2803 } | 2734 } |
| 2804 | 2735 |
| 2805 | 2736 |
| 2806 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2737 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2807 __ Bind(compiler->GetJumpLabel(this)); | 2738 __ Bind(compiler->GetJumpLabel(this)); |
| 2808 if (!compiler->is_optimizing()) { | 2739 if (!compiler->is_optimizing()) { |
| 2809 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 2740 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
| 2810 GetDeoptId(), | |
| 2811 TokenPosition::kNoSource); | 2741 TokenPosition::kNoSource); |
| 2812 } | 2742 } |
| 2813 if (HasParallelMove()) { | 2743 if (HasParallelMove()) { |
| 2814 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2744 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 2815 } | 2745 } |
| 2816 } | 2746 } |
| 2817 | 2747 |
| 2818 | 2748 |
| 2819 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, | 2749 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, |
| 2820 bool optimizing) const { | 2750 bool optimizing) const { |
| 2821 UNREACHABLE(); | 2751 UNREACHABLE(); |
| 2822 return NULL; | 2752 return NULL; |
| 2823 } | 2753 } |
| 2824 | 2754 |
| 2825 | 2755 |
| 2826 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2756 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2827 __ Bind(compiler->GetJumpLabel(this)); | 2757 __ Bind(compiler->GetJumpLabel(this)); |
| 2828 if (!compiler->is_optimizing()) { | 2758 if (!compiler->is_optimizing()) { |
| 2829 #if !defined(TARGET_ARCH_DBC) | 2759 #if !defined(TARGET_ARCH_DBC) |
| 2830 // TODO(vegorov) re-enable edge counters on DBC if we consider them | 2760 // TODO(vegorov) re-enable edge counters on DBC if we consider them |
| 2831 // beneficial for the quality of the optimized bytecode. | 2761 // beneficial for the quality of the optimized bytecode. |
| 2832 if (compiler->NeedsEdgeCounter(this)) { | 2762 if (compiler->NeedsEdgeCounter(this)) { |
| 2833 compiler->EmitEdgeCounter(preorder_number()); | 2763 compiler->EmitEdgeCounter(preorder_number()); |
| 2834 } | 2764 } |
| 2835 #endif | 2765 #endif |
| 2836 | 2766 |
| 2837 // The deoptimization descriptor points after the edge counter code for | 2767 // The deoptimization descriptor points after the edge counter code for |
| 2838 // uniformity with ARM and MIPS, where we can reuse pattern matching | 2768 // uniformity with ARM and MIPS, where we can reuse pattern matching |
| 2839 // code that matches backwards from the end of the pattern. | 2769 // code that matches backwards from the end of the pattern. |
| 2840 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 2770 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
| 2841 GetDeoptId(), | |
| 2842 TokenPosition::kNoSource); | 2771 TokenPosition::kNoSource); |
| 2843 } | 2772 } |
| 2844 if (HasParallelMove()) { | 2773 if (HasParallelMove()) { |
| 2845 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2774 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 2846 } | 2775 } |
| 2847 } | 2776 } |
| 2848 | 2777 |
| 2849 | 2778 |
| 2850 void IndirectGotoInstr::ComputeOffsetTable() { | 2779 void IndirectGotoInstr::ComputeOffsetTable() { |
| 2851 if (GetBlock()->offset() < 0) { | 2780 if (GetBlock()->offset() < 0) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2875 offset = ientry->offset(); | 2804 offset = ientry->offset(); |
| 2876 } | 2805 } |
| 2877 | 2806 |
| 2878 ASSERT(offset > 0); | 2807 ASSERT(offset > 0); |
| 2879 offsets_.SetInt32(i * element_size, offset); | 2808 offsets_.SetInt32(i * element_size, offset); |
| 2880 } | 2809 } |
| 2881 } | 2810 } |
| 2882 | 2811 |
| 2883 | 2812 |
| 2884 LocationSummary* IndirectEntryInstr::MakeLocationSummary( | 2813 LocationSummary* IndirectEntryInstr::MakeLocationSummary( |
| 2885 Zone* zone, bool optimizing) const { | 2814 Zone* zone, |
| 2815 bool optimizing) const { |
| 2886 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); | 2816 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); |
| 2887 } | 2817 } |
| 2888 | 2818 |
| 2889 | 2819 |
| 2890 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2820 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2891 JoinEntryInstr::EmitNativeCode(compiler); | 2821 JoinEntryInstr::EmitNativeCode(compiler); |
| 2892 } | 2822 } |
| 2893 | 2823 |
| 2894 | 2824 |
| 2895 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, | 2825 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2955 return NULL; | 2885 return NULL; |
| 2956 } | 2886 } |
| 2957 | 2887 |
| 2958 | 2888 |
| 2959 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2889 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2960 UNREACHABLE(); | 2890 UNREACHABLE(); |
| 2961 } | 2891 } |
| 2962 | 2892 |
| 2963 | 2893 |
| 2964 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( | 2894 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( |
| 2965 Zone* zone, bool optimizing) const { | 2895 Zone* zone, |
| 2896 bool optimizing) const { |
| 2966 UNREACHABLE(); | 2897 UNREACHABLE(); |
| 2967 return NULL; | 2898 return NULL; |
| 2968 } | 2899 } |
| 2969 | 2900 |
| 2970 | 2901 |
| 2971 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2902 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2972 UNREACHABLE(); | 2903 UNREACHABLE(); |
| 2973 } | 2904 } |
| 2974 | 2905 |
| 2975 | 2906 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2999 | 2930 |
| 3000 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2931 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3001 // Only appears in initial definitions, never in normal code. | 2932 // Only appears in initial definitions, never in normal code. |
| 3002 UNREACHABLE(); | 2933 UNREACHABLE(); |
| 3003 } | 2934 } |
| 3004 | 2935 |
| 3005 | 2936 |
| 3006 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, | 2937 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, |
| 3007 bool optimizing) const { | 2938 bool optimizing) const { |
| 3008 return (InputCount() == 1) | 2939 return (InputCount() == 1) |
| 3009 ? LocationSummary::Make(zone, | 2940 ? LocationSummary::Make(zone, 1, Location::SameAsFirstInput(), |
| 3010 1, | 2941 LocationSummary::kNoCall) |
| 3011 Location::SameAsFirstInput(), | 2942 : LocationSummary::Make(zone, 0, Location::NoLocation(), |
| 3012 LocationSummary::kNoCall) | 2943 LocationSummary::kNoCall); |
| 3013 : LocationSummary::Make(zone, | |
| 3014 0, | |
| 3015 Location::NoLocation(), | |
| 3016 LocationSummary::kNoCall); | |
| 3017 } | 2944 } |
| 3018 | 2945 |
| 3019 | 2946 |
| 3020 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2947 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3021 #if defined(TARGET_ARCH_DBC) | 2948 #if defined(TARGET_ARCH_DBC) |
| 3022 // On DBC the action of poping the TOS value and then pushing it | 2949 // On DBC the action of poping the TOS value and then pushing it |
| 3023 // after all intermediates are poped is folded into a special | 2950 // after all intermediates are poped is folded into a special |
| 3024 // bytecode (DropR). On other architectures this is handled by | 2951 // bytecode (DropR). On other architectures this is handled by |
| 3025 // instruction prologue/epilogues. | 2952 // instruction prologue/epilogues. |
| 3026 ASSERT(!compiler->is_optimizing()); | 2953 ASSERT(!compiler->is_optimizing()); |
| 3027 if ((InputCount() != 0) && HasTemp()) { | 2954 if ((InputCount() != 0) && HasTemp()) { |
| 3028 __ DropR(num_temps()); | 2955 __ DropR(num_temps()); |
| 3029 } else { | 2956 } else { |
| 3030 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); | 2957 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); |
| 3031 } | 2958 } |
| 3032 #else | 2959 #else |
| 3033 ASSERT(!compiler->is_optimizing()); | 2960 ASSERT(!compiler->is_optimizing()); |
| 3034 // Assert that register assignment is correct. | 2961 // Assert that register assignment is correct. |
| 3035 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); | 2962 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); |
| 3036 __ Drop(num_temps()); | 2963 __ Drop(num_temps()); |
| 3037 #endif // defined(TARGET_ARCH_DBC) | 2964 #endif // defined(TARGET_ARCH_DBC) |
| 3038 } | 2965 } |
| 3039 | 2966 |
| 3040 | 2967 |
| 3041 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, | 2968 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, |
| 3042 Token::Kind kind, | 2969 Token::Kind kind, |
| 3043 Value* left, | 2970 Value* left, |
| 3044 Value* right, | 2971 Value* right, |
| 3045 bool needs_number_check) | 2972 bool needs_number_check) |
| 3046 : TemplateComparison(token_pos, | 2973 : TemplateComparison(token_pos, kind, Thread::Current()->GetNextDeoptId()), |
| 3047 kind, | |
| 3048 Thread::Current()->GetNextDeoptId()), | |
| 3049 needs_number_check_(needs_number_check) { | 2974 needs_number_check_(needs_number_check) { |
| 3050 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); | 2975 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); |
| 3051 SetInputAt(0, left); | 2976 SetInputAt(0, left); |
| 3052 SetInputAt(1, right); | 2977 SetInputAt(1, right); |
| 3053 } | 2978 } |
| 3054 | 2979 |
| 3055 | 2980 |
| 3056 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, | 2981 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, |
| 3057 bool optimizing) const { | 2982 bool optimizing) const { |
| 3058 return MakeCallSummary(zone); | 2983 return MakeCallSummary(zone); |
| 3059 } | 2984 } |
| 3060 | 2985 |
| 3061 | 2986 |
| 3062 // DBC does not use specialized inline cache stubs for smi operations. | 2987 // DBC does not use specialized inline cache stubs for smi operations. |
| 3063 #if !defined(TARGET_ARCH_DBC) | 2988 #if !defined(TARGET_ARCH_DBC) |
| 3064 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { | 2989 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { |
| 3065 if (!FLAG_two_args_smi_icd) { | 2990 if (!FLAG_two_args_smi_icd) { |
| 3066 return 0; | 2991 return 0; |
| 3067 } | 2992 } |
| 3068 switch (kind) { | 2993 switch (kind) { |
| 3069 case Token::kADD: return StubCode::SmiAddInlineCache_entry(); | 2994 case Token::kADD: |
| 3070 case Token::kSUB: return StubCode::SmiSubInlineCache_entry(); | 2995 return StubCode::SmiAddInlineCache_entry(); |
| 3071 case Token::kEQ: return StubCode::SmiEqualInlineCache_entry(); | 2996 case Token::kSUB: |
| 3072 default: return NULL; | 2997 return StubCode::SmiSubInlineCache_entry(); |
| 2998 case Token::kEQ: |
| 2999 return StubCode::SmiEqualInlineCache_entry(); |
| 3000 default: |
| 3001 return NULL; |
| 3073 } | 3002 } |
| 3074 } | 3003 } |
| 3075 #else | 3004 #else |
| 3076 static void TryFastPathSmiOp( | 3005 static void TryFastPathSmiOp(FlowGraphCompiler* compiler, |
| 3077 FlowGraphCompiler* compiler, ICData* call_ic_data, const String& name) { | 3006 ICData* call_ic_data, |
| 3007 const String& name) { |
| 3078 if (!FLAG_two_args_smi_icd) { | 3008 if (!FLAG_two_args_smi_icd) { |
| 3079 return; | 3009 return; |
| 3080 } | 3010 } |
| 3081 if (name.raw() == Symbols::Plus().raw()) { | 3011 if (name.raw() == Symbols::Plus().raw()) { |
| 3082 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3012 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3083 __ AddTOS(); | 3013 __ AddTOS(); |
| 3084 } | 3014 } |
| 3085 } else if (name.raw() == Symbols::Minus().raw()) { | 3015 } else if (name.raw() == Symbols::Minus().raw()) { |
| 3086 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3016 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3087 __ SubTOS(); | 3017 __ SubTOS(); |
| 3088 } | 3018 } |
| 3089 } else if (name.raw() == Symbols::EqualOperator().raw()) { | 3019 } else if (name.raw() == Symbols::EqualOperator().raw()) { |
| 3090 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3020 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3091 __ EqualTOS(); | 3021 __ EqualTOS(); |
| 3092 } | 3022 } |
| 3093 } else if (name.raw() == Symbols::LAngleBracket().raw()) { | 3023 } else if (name.raw() == Symbols::LAngleBracket().raw()) { |
| 3094 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3024 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3095 __ LessThanTOS(); | 3025 __ LessThanTOS(); |
| 3096 } | 3026 } |
| 3097 } else if (name.raw() == Symbols::RAngleBracket().raw()) { | 3027 } else if (name.raw() == Symbols::RAngleBracket().raw()) { |
| 3098 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3028 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3099 __ GreaterThanTOS(); | 3029 __ GreaterThanTOS(); |
| 3100 } | 3030 } |
| 3101 } else if (name.raw() == Symbols::BitAnd().raw()) { | 3031 } else if (name.raw() == Symbols::BitAnd().raw()) { |
| 3102 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3032 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3103 __ BitAndTOS(); | 3033 __ BitAndTOS(); |
| 3104 } | 3034 } |
| 3105 } else if (name.raw() == Symbols::BitOr().raw()) { | 3035 } else if (name.raw() == Symbols::BitOr().raw()) { |
| 3106 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3036 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3107 __ BitOrTOS(); | 3037 __ BitOrTOS(); |
| 3108 } | 3038 } |
| 3109 } else if (name.raw() == Symbols::Star().raw()) { | 3039 } else if (name.raw() == Symbols::Star().raw()) { |
| 3110 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3040 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
| 3111 __ MulTOS(); | 3041 __ MulTOS(); |
| 3112 } | 3042 } |
| 3113 } | 3043 } |
| 3114 } | 3044 } |
| 3115 #endif | 3045 #endif |
| 3116 | 3046 |
| 3117 | 3047 |
| 3118 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3048 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3119 Zone* zone = compiler->zone(); | 3049 Zone* zone = compiler->zone(); |
| 3120 const ICData* call_ic_data = NULL; | 3050 const ICData* call_ic_data = NULL; |
| 3121 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3051 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
| 3122 (ic_data() == NULL)) { | 3052 (ic_data() == NULL)) { |
| 3123 const Array& arguments_descriptor = | 3053 const Array& arguments_descriptor = Array::Handle( |
| 3124 Array::Handle(zone, ArgumentsDescriptor::New(ArgumentCount(), | 3054 zone, ArgumentsDescriptor::New(ArgumentCount(), argument_names())); |
| 3125 argument_names())); | |
| 3126 call_ic_data = compiler->GetOrAddInstanceCallICData( | 3055 call_ic_data = compiler->GetOrAddInstanceCallICData( |
| 3127 deopt_id(), function_name(), arguments_descriptor, | 3056 deopt_id(), function_name(), arguments_descriptor, |
| 3128 checked_argument_count()); | 3057 checked_argument_count()); |
| 3129 } else { | 3058 } else { |
| 3130 call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw()); | 3059 call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw()); |
| 3131 } | 3060 } |
| 3132 | 3061 |
| 3133 #if !defined(TARGET_ARCH_DBC) | 3062 #if !defined(TARGET_ARCH_DBC) |
| 3134 if (compiler->is_optimizing() && HasICData()) { | 3063 if (compiler->is_optimizing() && HasICData()) { |
| 3135 ASSERT(HasICData()); | 3064 ASSERT(HasICData()); |
| 3136 if (ic_data()->NumberOfUsedChecks() > 0) { | 3065 if (ic_data()->NumberOfUsedChecks() > 0) { |
| 3137 const ICData& unary_ic_data = | 3066 const ICData& unary_ic_data = |
| 3138 ICData::ZoneHandle(zone, ic_data()->AsUnaryClassChecks()); | 3067 ICData::ZoneHandle(zone, ic_data()->AsUnaryClassChecks()); |
| 3139 compiler->GenerateInstanceCall(deopt_id(), | 3068 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
| 3140 token_pos(), | 3069 locs(), unary_ic_data); |
| 3141 ArgumentCount(), | |
| 3142 locs(), | |
| 3143 unary_ic_data); | |
| 3144 } else { | 3070 } else { |
| 3145 // Call was not visited yet, use original ICData in order to populate it. | 3071 // Call was not visited yet, use original ICData in order to populate it. |
| 3146 compiler->GenerateInstanceCall(deopt_id(), | 3072 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
| 3147 token_pos(), | 3073 locs(), *call_ic_data); |
| 3148 ArgumentCount(), | |
| 3149 locs(), | |
| 3150 *call_ic_data); | |
| 3151 } | 3074 } |
| 3152 } else { | 3075 } else { |
| 3153 // Unoptimized code. | 3076 // Unoptimized code. |
| 3154 ASSERT(!HasICData()); | 3077 ASSERT(!HasICData()); |
| 3155 bool is_smi_two_args_op = false; | 3078 bool is_smi_two_args_op = false; |
| 3156 const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind()); | 3079 const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind()); |
| 3157 if (stub_entry != NULL) { | 3080 if (stub_entry != NULL) { |
| 3158 // We have a dedicated inline cache stub for this operation, add an | 3081 // We have a dedicated inline cache stub for this operation, add an |
| 3159 // an initial Smi/Smi check with count 0. | 3082 // an initial Smi/Smi check with count 0. |
| 3160 is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs(); | 3083 is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs(); |
| 3161 } | 3084 } |
| 3162 if (is_smi_two_args_op) { | 3085 if (is_smi_two_args_op) { |
| 3163 ASSERT(ArgumentCount() == 2); | 3086 ASSERT(ArgumentCount() == 2); |
| 3164 compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(), | 3087 compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(), |
| 3165 deopt_id(), token_pos(), locs()); | 3088 deopt_id(), token_pos(), locs()); |
| 3166 } else { | 3089 } else { |
| 3167 compiler->GenerateInstanceCall(deopt_id(), | 3090 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
| 3168 token_pos(), | 3091 locs(), *call_ic_data); |
| 3169 ArgumentCount(), | |
| 3170 locs(), | |
| 3171 *call_ic_data); | |
| 3172 } | 3092 } |
| 3173 } | 3093 } |
| 3174 #else | 3094 #else |
| 3175 ICData* original_ic_data = &ICData::ZoneHandle(call_ic_data->Original()); | 3095 ICData* original_ic_data = &ICData::ZoneHandle(call_ic_data->Original()); |
| 3176 | 3096 |
| 3177 // Emit smi fast path instruction. If fast-path succeeds it skips the next | 3097 // Emit smi fast path instruction. If fast-path succeeds it skips the next |
| 3178 // instruction otherwise it falls through. Only attempt in unoptimized code | 3098 // instruction otherwise it falls through. Only attempt in unoptimized code |
| 3179 // because TryFastPathSmiOp will update original_ic_data. | 3099 // because TryFastPathSmiOp will update original_ic_data. |
| 3180 if (!compiler->is_optimizing()) { | 3100 if (!compiler->is_optimizing()) { |
| 3181 TryFastPathSmiOp(compiler, original_ic_data, function_name()); | 3101 TryFastPathSmiOp(compiler, original_ic_data, function_name()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3194 if (compiler->is_optimizing()) { | 3114 if (compiler->is_optimizing()) { |
| 3195 __ InstanceCall2Opt(ArgumentCount(), call_ic_data_kidx); | 3115 __ InstanceCall2Opt(ArgumentCount(), call_ic_data_kidx); |
| 3196 } else { | 3116 } else { |
| 3197 __ InstanceCall2(ArgumentCount(), call_ic_data_kidx); | 3117 __ InstanceCall2(ArgumentCount(), call_ic_data_kidx); |
| 3198 } | 3118 } |
| 3199 break; | 3119 break; |
| 3200 default: | 3120 default: |
| 3201 UNIMPLEMENTED(); | 3121 UNIMPLEMENTED(); |
| 3202 break; | 3122 break; |
| 3203 } | 3123 } |
| 3204 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, | 3124 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, deopt_id(), |
| 3205 deopt_id(), | |
| 3206 token_pos()); | 3125 token_pos()); |
| 3207 compiler->RecordAfterCall(this); | 3126 compiler->RecordAfterCall(this); |
| 3208 | 3127 |
| 3209 if (compiler->is_optimizing()) { | 3128 if (compiler->is_optimizing()) { |
| 3210 __ PopLocal(locs()->out(0).reg()); | 3129 __ PopLocal(locs()->out(0).reg()); |
| 3211 } | 3130 } |
| 3212 #endif // !defined(TARGET_ARCH_DBC) | 3131 #endif // !defined(TARGET_ARCH_DBC) |
| 3213 } | 3132 } |
| 3214 | 3133 |
| 3215 | 3134 |
| 3216 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { | 3135 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { |
| 3217 if (FLAG_precompiled_mode && with_checks()) return false; | 3136 if (FLAG_precompiled_mode && with_checks()) return false; |
| 3218 | 3137 |
| 3219 return ic_data().HasOneTarget() && | 3138 return ic_data().HasOneTarget() && |
| 3220 (MethodRecognizer::RecognizeKind( | 3139 (MethodRecognizer::RecognizeKind(Function::Handle( |
| 3221 Function::Handle(ic_data().GetTargetAt(0))) != | 3140 ic_data().GetTargetAt(0))) != MethodRecognizer::kUnknown); |
| 3222 MethodRecognizer::kUnknown); | |
| 3223 } | 3141 } |
| 3224 | 3142 |
| 3225 | 3143 |
| 3226 // DBC does not support optimizing compiler and thus doesn't emit | 3144 // DBC does not support optimizing compiler and thus doesn't emit |
| 3227 // PolymorphicInstanceCallInstr. | 3145 // PolymorphicInstanceCallInstr. |
| 3228 #if !defined(TARGET_ARCH_DBC) | 3146 #if !defined(TARGET_ARCH_DBC) |
| 3229 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3147 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3230 ASSERT(ic_data().NumArgsTested() == 1); | 3148 ASSERT(ic_data().NumArgsTested() == 1); |
| 3231 if (!with_checks()) { | 3149 if (!with_checks()) { |
| 3232 ASSERT(ic_data().HasOneTarget()); | 3150 ASSERT(ic_data().HasOneTarget()); |
| 3233 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); | 3151 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| 3234 compiler->GenerateStaticCall(deopt_id(), | 3152 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), |
| 3235 instance_call()->token_pos(), | 3153 target, instance_call()->ArgumentCount(), |
| 3236 target, | 3154 instance_call()->argument_names(), locs(), |
| 3237 instance_call()->ArgumentCount(), | |
| 3238 instance_call()->argument_names(), | |
| 3239 locs(), | |
| 3240 ICData::Handle()); | 3155 ICData::Handle()); |
| 3241 return; | 3156 return; |
| 3242 } | 3157 } |
| 3243 | 3158 |
| 3244 compiler->EmitPolymorphicInstanceCall(ic_data(), | 3159 compiler->EmitPolymorphicInstanceCall( |
| 3245 instance_call()->ArgumentCount(), | 3160 ic_data(), instance_call()->ArgumentCount(), |
| 3246 instance_call()->argument_names(), | 3161 instance_call()->argument_names(), deopt_id(), |
| 3247 deopt_id(), | 3162 instance_call()->token_pos(), locs(), complete()); |
| 3248 instance_call()->token_pos(), | |
| 3249 locs(), | |
| 3250 complete()); | |
| 3251 } | 3163 } |
| 3252 #endif | 3164 #endif |
| 3253 | 3165 |
| 3254 | 3166 |
| 3255 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( | 3167 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
| 3256 const ICData& ic_data) { | 3168 const ICData& ic_data) { |
| 3257 bool is_string = true; | 3169 bool is_string = true; |
| 3258 bool is_integer = true; | 3170 bool is_integer = true; |
| 3259 bool is_double = true; | 3171 bool is_double = true; |
| 3260 | 3172 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3316 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, | 3228 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, |
| 3317 bool optimizing) const { | 3229 bool optimizing) const { |
| 3318 return MakeCallSummary(zone); | 3230 return MakeCallSummary(zone); |
| 3319 } | 3231 } |
| 3320 | 3232 |
| 3321 | 3233 |
| 3322 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3234 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3323 const ICData* call_ic_data = NULL; | 3235 const ICData* call_ic_data = NULL; |
| 3324 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3236 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
| 3325 (ic_data() == NULL)) { | 3237 (ic_data() == NULL)) { |
| 3326 const Array& arguments_descriptor = | 3238 const Array& arguments_descriptor = Array::Handle( |
| 3327 Array::Handle(ArgumentsDescriptor::New(ArgumentCount(), | 3239 ArgumentsDescriptor::New(ArgumentCount(), argument_names())); |
| 3328 argument_names())); | |
| 3329 MethodRecognizer::Kind recognized_kind = | 3240 MethodRecognizer::Kind recognized_kind = |
| 3330 MethodRecognizer::RecognizeKind(function()); | 3241 MethodRecognizer::RecognizeKind(function()); |
| 3331 int num_args_checked = 0; | 3242 int num_args_checked = 0; |
| 3332 switch (recognized_kind) { | 3243 switch (recognized_kind) { |
| 3333 case MethodRecognizer::kDoubleFromInteger: | 3244 case MethodRecognizer::kDoubleFromInteger: |
| 3334 case MethodRecognizer::kMathMin: | 3245 case MethodRecognizer::kMathMin: |
| 3335 case MethodRecognizer::kMathMax: | 3246 case MethodRecognizer::kMathMax: |
| 3336 num_args_checked = 2; | 3247 num_args_checked = 2; |
| 3337 break; | 3248 break; |
| 3338 default: | 3249 default: |
| 3339 break; | 3250 break; |
| 3340 } | 3251 } |
| 3341 call_ic_data = compiler->GetOrAddStaticCallICData(deopt_id(), | 3252 call_ic_data = compiler->GetOrAddStaticCallICData( |
| 3342 function(), | 3253 deopt_id(), function(), arguments_descriptor, num_args_checked); |
| 3343 arguments_descriptor, | |
| 3344 num_args_checked); | |
| 3345 } else { | 3254 } else { |
| 3346 call_ic_data = &ICData::ZoneHandle(ic_data()->raw()); | 3255 call_ic_data = &ICData::ZoneHandle(ic_data()->raw()); |
| 3347 } | 3256 } |
| 3348 | 3257 |
| 3349 #if !defined(TARGET_ARCH_DBC) | 3258 #if !defined(TARGET_ARCH_DBC) |
| 3350 compiler->GenerateStaticCall(deopt_id(), | 3259 compiler->GenerateStaticCall(deopt_id(), token_pos(), function(), |
| 3351 token_pos(), | 3260 ArgumentCount(), argument_names(), locs(), |
| 3352 function(), | |
| 3353 ArgumentCount(), | |
| 3354 argument_names(), | |
| 3355 locs(), | |
| 3356 *call_ic_data); | 3261 *call_ic_data); |
| 3357 #else | 3262 #else |
| 3358 const Array& arguments_descriptor = | 3263 const Array& arguments_descriptor = |
| 3359 (ic_data() == NULL) ? | 3264 (ic_data() == NULL) ? Array::Handle(ArgumentsDescriptor::New( |
| 3360 Array::Handle(ArgumentsDescriptor::New(ArgumentCount(), | 3265 ArgumentCount(), argument_names())) |
| 3361 argument_names())) : | 3266 : Array::Handle(ic_data()->arguments_descriptor()); |
| 3362 Array::Handle(ic_data()->arguments_descriptor()); | |
| 3363 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); | 3267 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); |
| 3364 | 3268 |
| 3365 if (compiler->is_optimizing()) { | 3269 if (compiler->is_optimizing()) { |
| 3366 __ PushConstant(function()); | 3270 __ PushConstant(function()); |
| 3367 __ StaticCall(ArgumentCount(), argdesc_kidx); | 3271 __ StaticCall(ArgumentCount(), argdesc_kidx); |
| 3368 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 3272 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 3369 deopt_id(), token_pos()); | 3273 token_pos()); |
| 3370 compiler->RecordAfterCall(this); | 3274 compiler->RecordAfterCall(this); |
| 3371 __ PopLocal(locs()->out(0).reg()); | 3275 __ PopLocal(locs()->out(0).reg()); |
| 3372 } else { | 3276 } else { |
| 3373 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); | 3277 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); |
| 3374 __ PushConstant(ic_data_kidx); | 3278 __ PushConstant(ic_data_kidx); |
| 3375 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); | 3279 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); |
| 3376 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, | 3280 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, |
| 3377 deopt_id(), token_pos()); | 3281 deopt_id(), token_pos()); |
| 3378 compiler->RecordAfterCall(this); | 3282 compiler->RecordAfterCall(this); |
| 3379 } | 3283 } |
| 3380 #endif // !defined(TARGET_ARCH_DBC) | 3284 #endif // !defined(TARGET_ARCH_DBC) |
| 3381 } | 3285 } |
| 3382 | 3286 |
| 3383 | 3287 |
| 3384 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3288 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3385 compiler->GenerateAssertAssignable(token_pos(), | 3289 compiler->GenerateAssertAssignable(token_pos(), deopt_id(), dst_type(), |
| 3386 deopt_id(), | 3290 dst_name(), locs()); |
| 3387 dst_type(), | |
| 3388 dst_name(), | |
| 3389 locs()); | |
| 3390 | 3291 |
| 3391 // DBC does not use LocationSummaries in the same way as other architectures. | 3292 // DBC does not use LocationSummaries in the same way as other architectures. |
| 3392 #if !defined(TARGET_ARCH_DBC) | 3293 #if !defined(TARGET_ARCH_DBC) |
| 3393 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); | 3294 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); |
| 3394 #endif // !defined(TARGET_ARCH_DBC) | 3295 #endif // !defined(TARGET_ARCH_DBC) |
| 3395 } | 3296 } |
| 3396 | 3297 |
| 3397 | 3298 |
| 3398 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, | 3299 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, |
| 3399 bool opt) const { | 3300 bool opt) const { |
| 3400 return new(zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); | 3301 return new (zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); |
| 3401 } | 3302 } |
| 3402 | 3303 |
| 3403 | 3304 |
| 3404 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3305 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3405 #if !defined(TARGET_ARCH_DBC) | 3306 #if !defined(TARGET_ARCH_DBC) |
| 3406 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | 3307 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); |
| 3407 #else | 3308 #else |
| 3408 compiler->EmitDeopt(deopt_id(), deopt_reason_); | 3309 compiler->EmitDeopt(deopt_id(), deopt_reason_); |
| 3409 #endif | 3310 #endif |
| 3410 } | 3311 } |
| 3411 | 3312 |
| 3412 | 3313 |
| 3413 Environment* Environment::From(Zone* zone, | 3314 Environment* Environment::From(Zone* zone, |
| 3414 const GrowableArray<Definition*>& definitions, | 3315 const GrowableArray<Definition*>& definitions, |
| 3415 intptr_t fixed_parameter_count, | 3316 intptr_t fixed_parameter_count, |
| 3416 const ParsedFunction& parsed_function) { | 3317 const ParsedFunction& parsed_function) { |
| 3417 Environment* env = | 3318 Environment* env = |
| 3418 new(zone) Environment(definitions.length(), | 3319 new (zone) Environment(definitions.length(), fixed_parameter_count, |
| 3419 fixed_parameter_count, | 3320 Thread::kNoDeoptId, parsed_function, NULL); |
| 3420 Thread::kNoDeoptId, | |
| 3421 parsed_function, | |
| 3422 NULL); | |
| 3423 for (intptr_t i = 0; i < definitions.length(); ++i) { | 3321 for (intptr_t i = 0; i < definitions.length(); ++i) { |
| 3424 env->values_.Add(new(zone) Value(definitions[i])); | 3322 env->values_.Add(new (zone) Value(definitions[i])); |
| 3425 } | 3323 } |
| 3426 return env; | 3324 return env; |
| 3427 } | 3325 } |
| 3428 | 3326 |
| 3429 | 3327 |
| 3430 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { | 3328 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { |
| 3431 ASSERT(length <= values_.length()); | 3329 ASSERT(length <= values_.length()); |
| 3432 Environment* copy = new(zone) Environment( | 3330 Environment* copy = new (zone) |
| 3433 length, | 3331 Environment(length, fixed_parameter_count_, deopt_id_, parsed_function_, |
| 3434 fixed_parameter_count_, | 3332 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); |
| 3435 deopt_id_, | |
| 3436 parsed_function_, | |
| 3437 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); | |
| 3438 if (locations_ != NULL) { | 3333 if (locations_ != NULL) { |
| 3439 Location* new_locations = zone->Alloc<Location>(length); | 3334 Location* new_locations = zone->Alloc<Location>(length); |
| 3440 copy->set_locations(new_locations); | 3335 copy->set_locations(new_locations); |
| 3441 } | 3336 } |
| 3442 for (intptr_t i = 0; i < length; ++i) { | 3337 for (intptr_t i = 0; i < length; ++i) { |
| 3443 copy->values_.Add(values_[i]->Copy(zone)); | 3338 copy->values_.Add(values_[i]->Copy(zone)); |
| 3444 if (locations_ != NULL) { | 3339 if (locations_ != NULL) { |
| 3445 copy->locations_[i] = locations_[i].Copy(); | 3340 copy->locations_[i] = locations_[i].Copy(); |
| 3446 } | 3341 } |
| 3447 } | 3342 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3468 Instruction* instr, | 3363 Instruction* instr, |
| 3469 intptr_t argc, | 3364 intptr_t argc, |
| 3470 Definition* dead, | 3365 Definition* dead, |
| 3471 Definition* result) const { | 3366 Definition* result) const { |
| 3472 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | 3367 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
| 3473 it.CurrentValue()->RemoveFromUseList(); | 3368 it.CurrentValue()->RemoveFromUseList(); |
| 3474 } | 3369 } |
| 3475 | 3370 |
| 3476 Environment* copy = DeepCopy(zone, values_.length() - argc); | 3371 Environment* copy = DeepCopy(zone, values_.length() - argc); |
| 3477 for (intptr_t i = 0; i < argc; i++) { | 3372 for (intptr_t i = 0; i < argc; i++) { |
| 3478 copy->values_.Add(new(zone) Value(dead)); | 3373 copy->values_.Add(new (zone) Value(dead)); |
| 3479 } | 3374 } |
| 3480 copy->values_.Add(new(zone) Value(result)); | 3375 copy->values_.Add(new (zone) Value(result)); |
| 3481 | 3376 |
| 3482 instr->SetEnvironment(copy); | 3377 instr->SetEnvironment(copy); |
| 3483 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 3378 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
| 3484 Value* value = it.CurrentValue(); | 3379 Value* value = it.CurrentValue(); |
| 3485 value->definition()->AddEnvUse(value); | 3380 value->definition()->AddEnvUse(value); |
| 3486 } | 3381 } |
| 3487 } | 3382 } |
| 3488 | 3383 |
| 3489 | 3384 |
| 3490 // Copies the environment as outer on an inlined instruction and updates the | 3385 // Copies the environment as outer on an inlined instruction and updates the |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3508 | 3403 |
| 3509 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, | 3404 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, |
| 3510 Value* new_right) { | 3405 Value* new_right) { |
| 3511 UNREACHABLE(); | 3406 UNREACHABLE(); |
| 3512 return NULL; | 3407 return NULL; |
| 3513 } | 3408 } |
| 3514 | 3409 |
| 3515 | 3410 |
| 3516 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, | 3411 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, |
| 3517 Value* new_right) { | 3412 Value* new_right) { |
| 3518 return new EqualityCompareInstr(token_pos(), | 3413 return new EqualityCompareInstr(token_pos(), kind(), new_left, new_right, |
| 3519 kind(), | 3414 operation_cid(), deopt_id()); |
| 3520 new_left, | |
| 3521 new_right, | |
| 3522 operation_cid(), | |
| 3523 deopt_id()); | |
| 3524 } | 3415 } |
| 3525 | 3416 |
| 3526 | 3417 |
| 3527 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, | 3418 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, |
| 3528 Value* new_right) { | 3419 Value* new_right) { |
| 3529 return new RelationalOpInstr(token_pos(), | 3420 return new RelationalOpInstr(token_pos(), kind(), new_left, new_right, |
| 3530 kind(), | 3421 operation_cid(), deopt_id()); |
| 3531 new_left, | |
| 3532 new_right, | |
| 3533 operation_cid(), | |
| 3534 deopt_id()); | |
| 3535 } | 3422 } |
| 3536 | 3423 |
| 3537 | 3424 |
| 3538 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, | 3425 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, |
| 3539 Value* new_right) { | 3426 Value* new_right) { |
| 3540 return new StrictCompareInstr(token_pos(), | 3427 return new StrictCompareInstr(token_pos(), kind(), new_left, new_right, |
| 3541 kind(), | |
| 3542 new_left, | |
| 3543 new_right, | |
| 3544 needs_number_check()); | 3428 needs_number_check()); |
| 3545 } | 3429 } |
| 3546 | 3430 |
| 3547 | 3431 |
| 3548 | |
| 3549 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, | 3432 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, |
| 3550 Value* new_right) { | 3433 Value* new_right) { |
| 3551 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); | 3434 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); |
| 3552 } | 3435 } |
| 3553 | 3436 |
| 3554 | 3437 |
| 3555 | |
| 3556 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, | 3438 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, |
| 3557 Value* new_right) { | 3439 Value* new_right) { |
| 3558 return new TestCidsInstr(token_pos(), | 3440 return new TestCidsInstr(token_pos(), kind(), new_left, cid_results(), |
| 3559 kind(), | |
| 3560 new_left, | |
| 3561 cid_results(), | |
| 3562 deopt_id()); | 3441 deopt_id()); |
| 3563 } | 3442 } |
| 3564 | 3443 |
| 3565 | 3444 |
| 3566 bool TestCidsInstr::AttributesEqual(Instruction* other) const { | 3445 bool TestCidsInstr::AttributesEqual(Instruction* other) const { |
| 3567 TestCidsInstr* other_instr = other->AsTestCids(); | 3446 TestCidsInstr* other_instr = other->AsTestCids(); |
| 3568 if (!ComparisonInstr::AttributesEqual(other)) { | 3447 if (!ComparisonInstr::AttributesEqual(other)) { |
| 3569 return false; | 3448 return false; |
| 3570 } | 3449 } |
| 3571 if (cid_results().length() != other_instr->cid_results().length()) { | 3450 if (cid_results().length() != other_instr->cid_results().length()) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3588 | 3467 |
| 3589 | 3468 |
| 3590 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | 3469 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
| 3591 Value* v1, | 3470 Value* v1, |
| 3592 Value* v2) { | 3471 Value* v2) { |
| 3593 #if !defined(TARGET_ARCH_DBC) | 3472 #if !defined(TARGET_ARCH_DBC) |
| 3594 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); | 3473 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); |
| 3595 if (comparison->IsStrictCompare()) { | 3474 if (comparison->IsStrictCompare()) { |
| 3596 // Strict comparison with number checks calls a stub and is not supported | 3475 // Strict comparison with number checks calls a stub and is not supported |
| 3597 // by if-conversion. | 3476 // by if-conversion. |
| 3598 return is_smi_result | 3477 return is_smi_result && |
| 3599 && !comparison->AsStrictCompare()->needs_number_check(); | 3478 !comparison->AsStrictCompare()->needs_number_check(); |
| 3600 } | 3479 } |
| 3601 if (comparison->operation_cid() != kSmiCid) { | 3480 if (comparison->operation_cid() != kSmiCid) { |
| 3602 // Non-smi comparisons are not supported by if-conversion. | 3481 // Non-smi comparisons are not supported by if-conversion. |
| 3603 return false; | 3482 return false; |
| 3604 } | 3483 } |
| 3605 return is_smi_result; | 3484 return is_smi_result; |
| 3606 #else | 3485 #else |
| 3607 return false; | 3486 return false; |
| 3608 #endif // !defined(TARGET_ARCH_DBC) | 3487 #endif // !defined(TARGET_ARCH_DBC) |
| 3609 } | 3488 } |
| 3610 | 3489 |
| 3611 | 3490 |
| 3612 bool PhiInstr::IsRedundant() const { | 3491 bool PhiInstr::IsRedundant() const { |
| 3613 ASSERT(InputCount() > 1); | 3492 ASSERT(InputCount() > 1); |
| 3614 Definition* first = InputAt(0)->definition(); | 3493 Definition* first = InputAt(0)->definition(); |
| 3615 for (intptr_t i = 1; i < InputCount(); ++i) { | 3494 for (intptr_t i = 1; i < InputCount(); ++i) { |
| 3616 Definition* def = InputAt(i)->definition(); | 3495 Definition* def = InputAt(i)->definition(); |
| 3617 if (def != first) return false; | 3496 if (def != first) return false; |
| 3618 } | 3497 } |
| 3619 return true; | 3498 return true; |
| 3620 } | 3499 } |
| 3621 | 3500 |
| 3622 | 3501 |
| 3623 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3502 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
| 3624 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3503 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
| 3625 } | 3504 } |
| 3626 | 3505 |
| 3627 | 3506 |
| 3628 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { | 3507 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { |
| 3629 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) ? | 3508 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) |
| 3630 NULL : this; | 3509 ? NULL |
| 3510 : this; |
| 3631 } | 3511 } |
| 3632 | 3512 |
| 3633 | 3513 |
| 3634 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { | 3514 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { |
| 3635 if (RawObject::IsExternalTypedDataClassId(class_id)) { | 3515 if (RawObject::IsExternalTypedDataClassId(class_id)) { |
| 3636 return ExternalTypedData::length_offset(); | 3516 return ExternalTypedData::length_offset(); |
| 3637 } | 3517 } |
| 3638 if (RawObject::IsTypedDataClassId(class_id)) { | 3518 if (RawObject::IsTypedDataClassId(class_id)) { |
| 3639 return TypedData::length_offset(); | 3519 return TypedData::length_offset(); |
| 3640 } | 3520 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3654 } | 3534 } |
| 3655 | 3535 |
| 3656 | 3536 |
| 3657 const Function& StringInterpolateInstr::CallFunction() const { | 3537 const Function& StringInterpolateInstr::CallFunction() const { |
| 3658 if (function_.IsNull()) { | 3538 if (function_.IsNull()) { |
| 3659 const int kNumberOfArguments = 1; | 3539 const int kNumberOfArguments = 1; |
| 3660 const Array& kNoArgumentNames = Object::null_array(); | 3540 const Array& kNoArgumentNames = Object::null_array(); |
| 3661 const Class& cls = | 3541 const Class& cls = |
| 3662 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); | 3542 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); |
| 3663 ASSERT(!cls.IsNull()); | 3543 ASSERT(!cls.IsNull()); |
| 3664 function_ = | 3544 function_ = Resolver::ResolveStatic( |
| 3665 Resolver::ResolveStatic( | 3545 cls, Library::PrivateCoreLibName(Symbols::Interpolate()), |
| 3666 cls, | 3546 kNumberOfArguments, kNoArgumentNames); |
| 3667 Library::PrivateCoreLibName(Symbols::Interpolate()), | |
| 3668 kNumberOfArguments, | |
| 3669 kNoArgumentNames); | |
| 3670 } | 3547 } |
| 3671 ASSERT(!function_.IsNull()); | 3548 ASSERT(!function_.IsNull()); |
| 3672 return function_; | 3549 return function_; |
| 3673 } | 3550 } |
| 3674 | 3551 |
| 3675 | 3552 |
| 3676 // Replace StringInterpolateInstr with a constant string if all inputs are | 3553 // Replace StringInterpolateInstr with a constant string if all inputs are |
| 3677 // constant of [string, number, boolean, null]. | 3554 // constant of [string, number, boolean, null]. |
| 3678 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case | 3555 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case |
| 3679 // deoptimization occurs. | 3556 // deoptimization occurs. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3698 return this; | 3575 return this; |
| 3699 } | 3576 } |
| 3700 const intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); | 3577 const intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); |
| 3701 Thread* thread = Thread::Current(); | 3578 Thread* thread = Thread::Current(); |
| 3702 Zone* zone = thread->zone(); | 3579 Zone* zone = thread->zone(); |
| 3703 GrowableHandlePtrArray<const String> pieces(zone, length); | 3580 GrowableHandlePtrArray<const String> pieces(zone, length); |
| 3704 for (intptr_t i = 0; i < length; i++) { | 3581 for (intptr_t i = 0; i < length; i++) { |
| 3705 pieces.Add(Object::null_string()); | 3582 pieces.Add(Object::null_string()); |
| 3706 } | 3583 } |
| 3707 | 3584 |
| 3708 for (Value::Iterator it(create_array->input_use_list()); | 3585 for (Value::Iterator it(create_array->input_use_list()); !it.Done(); |
| 3709 !it.Done(); | |
| 3710 it.Advance()) { | 3586 it.Advance()) { |
| 3711 Instruction* curr = it.Current()->instruction(); | 3587 Instruction* curr = it.Current()->instruction(); |
| 3712 if (curr == this) continue; | 3588 if (curr == this) continue; |
| 3713 | 3589 |
| 3714 StoreIndexedInstr* store = curr->AsStoreIndexed(); | 3590 StoreIndexedInstr* store = curr->AsStoreIndexed(); |
| 3715 if (!store->index()->BindsToConstant() || | 3591 if (!store->index()->BindsToConstant() || |
| 3716 !store->index()->BoundConstant().IsSmi()) { | 3592 !store->index()->BoundConstant().IsSmi()) { |
| 3717 return this; | 3593 return this; |
| 3718 } | 3594 } |
| 3719 intptr_t store_index = Smi::Cast(store->index()->BoundConstant()).Value(); | 3595 intptr_t store_index = Smi::Cast(store->index()->BoundConstant()).Value(); |
| 3720 ASSERT(store_index < length); | 3596 ASSERT(store_index < length); |
| 3721 ASSERT(store != NULL); | 3597 ASSERT(store != NULL); |
| 3722 if (store->value()->definition()->IsConstant()) { | 3598 if (store->value()->definition()->IsConstant()) { |
| 3723 ASSERT(store->index()->BindsToConstant()); | 3599 ASSERT(store->index()->BindsToConstant()); |
| 3724 const Object& obj = store->value()->definition()->AsConstant()->value(); | 3600 const Object& obj = store->value()->definition()->AsConstant()->value(); |
| 3725 // TODO(srdjan): Verify if any other types should be converted as well. | 3601 // TODO(srdjan): Verify if any other types should be converted as well. |
| 3726 if (obj.IsString()) { | 3602 if (obj.IsString()) { |
| 3727 pieces.SetAt(store_index, String::Cast(obj)); | 3603 pieces.SetAt(store_index, String::Cast(obj)); |
| 3728 } else if (obj.IsSmi()) { | 3604 } else if (obj.IsSmi()) { |
| 3729 const char* cstr = obj.ToCString(); | 3605 const char* cstr = obj.ToCString(); |
| 3730 pieces.SetAt(store_index, | 3606 pieces.SetAt(store_index, |
| 3731 String::Handle(zone, String::New(cstr, Heap::kOld))); | 3607 String::Handle(zone, String::New(cstr, Heap::kOld))); |
| 3732 } else if (obj.IsBool()) { | 3608 } else if (obj.IsBool()) { |
| 3733 pieces.SetAt(store_index, | 3609 pieces.SetAt(store_index, Bool::Cast(obj).value() ? Symbols::True() |
| 3734 Bool::Cast(obj).value() ? Symbols::True() : Symbols::False()); | 3610 : Symbols::False()); |
| 3735 } else if (obj.IsNull()) { | 3611 } else if (obj.IsNull()) { |
| 3736 pieces.SetAt(store_index, Symbols::Null()); | 3612 pieces.SetAt(store_index, Symbols::Null()); |
| 3737 } else { | 3613 } else { |
| 3738 return this; | 3614 return this; |
| 3739 } | 3615 } |
| 3740 } else { | 3616 } else { |
| 3741 return this; | 3617 return this; |
| 3742 } | 3618 } |
| 3743 } | 3619 } |
| 3744 | 3620 |
| 3745 const String& concatenated = String::ZoneHandle(zone, | 3621 const String& concatenated = |
| 3746 Symbols::FromConcatAll(thread, pieces)); | 3622 String::ZoneHandle(zone, Symbols::FromConcatAll(thread, pieces)); |
| 3747 return flow_graph->GetConstant(concatenated); | 3623 return flow_graph->GetConstant(concatenated); |
| 3748 } | 3624 } |
| 3749 | 3625 |
| 3750 | 3626 |
| 3751 static AlignmentType StrengthenAlignment(intptr_t cid, | 3627 static AlignmentType StrengthenAlignment(intptr_t cid, |
| 3752 AlignmentType alignment) { | 3628 AlignmentType alignment) { |
| 3753 switch (cid) { | 3629 switch (cid) { |
| 3754 case kTypedDataInt8ArrayCid: | 3630 case kTypedDataInt8ArrayCid: |
| 3755 case kTypedDataUint8ArrayCid: | 3631 case kTypedDataUint8ArrayCid: |
| 3756 case kTypedDataUint8ClampedArrayCid: | 3632 case kTypedDataUint8ClampedArrayCid: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3784 : TemplateDefinition(deopt_id), | 3660 : TemplateDefinition(deopt_id), |
| 3785 index_scale_(index_scale), | 3661 index_scale_(index_scale), |
| 3786 class_id_(class_id), | 3662 class_id_(class_id), |
| 3787 alignment_(StrengthenAlignment(class_id, alignment)), | 3663 alignment_(StrengthenAlignment(class_id, alignment)), |
| 3788 token_pos_(token_pos) { | 3664 token_pos_(token_pos) { |
| 3789 SetInputAt(0, array); | 3665 SetInputAt(0, array); |
| 3790 SetInputAt(1, index); | 3666 SetInputAt(1, index); |
| 3791 } | 3667 } |
| 3792 | 3668 |
| 3793 | 3669 |
| 3794 | |
| 3795 StoreIndexedInstr::StoreIndexedInstr(Value* array, | 3670 StoreIndexedInstr::StoreIndexedInstr(Value* array, |
| 3796 Value* index, | 3671 Value* index, |
| 3797 Value* value, | 3672 Value* value, |
| 3798 StoreBarrierType emit_store_barrier, | 3673 StoreBarrierType emit_store_barrier, |
| 3799 intptr_t index_scale, | 3674 intptr_t index_scale, |
| 3800 intptr_t class_id, | 3675 intptr_t class_id, |
| 3801 AlignmentType alignment, | 3676 AlignmentType alignment, |
| 3802 intptr_t deopt_id, | 3677 intptr_t deopt_id, |
| 3803 TokenPosition token_pos) | 3678 TokenPosition token_pos) |
| 3804 : TemplateDefinition(deopt_id), | 3679 : TemplateDefinition(deopt_id), |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3852 case MethodRecognizer::kMathDoublePow: | 3727 case MethodRecognizer::kMathDoublePow: |
| 3853 case MethodRecognizer::kMathAtan2: | 3728 case MethodRecognizer::kMathAtan2: |
| 3854 return 2; | 3729 return 2; |
| 3855 default: | 3730 default: |
| 3856 UNREACHABLE(); | 3731 UNREACHABLE(); |
| 3857 } | 3732 } |
| 3858 return 0; | 3733 return 0; |
| 3859 } | 3734 } |
| 3860 | 3735 |
| 3861 // Use expected function signatures to help MSVC compiler resolve overloading. | 3736 // Use expected function signatures to help MSVC compiler resolve overloading. |
| 3862 typedef double (*UnaryMathCFunction) (double x); | 3737 typedef double (*UnaryMathCFunction)(double x); |
| 3863 typedef double (*BinaryMathCFunction) (double x, double y); | 3738 typedef double (*BinaryMathCFunction)(double x, double y); |
| 3864 | 3739 |
| 3865 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcPow, 2, true /* is_float */, | 3740 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3866 reinterpret_cast<RuntimeFunction>( | 3741 LibcPow, |
| 3867 static_cast<BinaryMathCFunction>(&pow))); | 3742 2, |
| 3743 true /* is_float */, |
| 3744 reinterpret_cast<RuntimeFunction>(static_cast<BinaryMathCFunction>(&pow))); |
| 3868 | 3745 |
| 3869 DEFINE_RAW_LEAF_RUNTIME_ENTRY(DartModulo, 2, true /* is_float */, | 3746 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3747 DartModulo, |
| 3748 2, |
| 3749 true /* is_float */, |
| 3870 reinterpret_cast<RuntimeFunction>( | 3750 reinterpret_cast<RuntimeFunction>( |
| 3871 static_cast<BinaryMathCFunction>(&DartModulo))); | 3751 static_cast<BinaryMathCFunction>(&DartModulo))); |
| 3872 | 3752 |
| 3873 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan2, 2, true /* is_float */, | 3753 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3754 LibcAtan2, |
| 3755 2, |
| 3756 true /* is_float */, |
| 3874 reinterpret_cast<RuntimeFunction>( | 3757 reinterpret_cast<RuntimeFunction>( |
| 3875 static_cast<BinaryMathCFunction>(&atan2_ieee))); | 3758 static_cast<BinaryMathCFunction>(&atan2_ieee))); |
| 3876 | 3759 |
| 3877 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcFloor, 1, true /* is_float */, | 3760 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3878 reinterpret_cast<RuntimeFunction>( | 3761 LibcFloor, |
| 3879 static_cast<UnaryMathCFunction>(&floor))); | 3762 1, |
| 3763 true /* is_float */, |
| 3764 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&floor))); |
| 3880 | 3765 |
| 3881 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCeil, 1, true /* is_float */, | 3766 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3882 reinterpret_cast<RuntimeFunction>( | 3767 LibcCeil, |
| 3883 static_cast<UnaryMathCFunction>(&ceil))); | 3768 1, |
| 3769 true /* is_float */, |
| 3770 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&ceil))); |
| 3884 | 3771 |
| 3885 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTrunc, 1, true /* is_float */, | 3772 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3886 reinterpret_cast<RuntimeFunction>( | 3773 LibcTrunc, |
| 3887 static_cast<UnaryMathCFunction>(&trunc))); | 3774 1, |
| 3775 true /* is_float */, |
| 3776 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&trunc))); |
| 3888 | 3777 |
| 3889 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcRound, 1, true /* is_float */, | 3778 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3890 reinterpret_cast<RuntimeFunction>( | 3779 LibcRound, |
| 3891 static_cast<UnaryMathCFunction>(&round))); | 3780 1, |
| 3781 true /* is_float */, |
| 3782 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&round))); |
| 3892 | 3783 |
| 3893 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCos, 1, true /* is_float */, | 3784 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3894 reinterpret_cast<RuntimeFunction>( | 3785 LibcCos, |
| 3895 static_cast<UnaryMathCFunction>(&cos))); | 3786 1, |
| 3787 true /* is_float */, |
| 3788 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&cos))); |
| 3896 | 3789 |
| 3897 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcSin, 1, true /* is_float */, | 3790 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3898 reinterpret_cast<RuntimeFunction>( | 3791 LibcSin, |
| 3899 static_cast<UnaryMathCFunction>(&sin))); | 3792 1, |
| 3793 true /* is_float */, |
| 3794 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&sin))); |
| 3900 | 3795 |
| 3901 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAsin, 1, true /* is_float */, | 3796 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3902 reinterpret_cast<RuntimeFunction>( | 3797 LibcAsin, |
| 3903 static_cast<UnaryMathCFunction>(&asin))); | 3798 1, |
| 3799 true /* is_float */, |
| 3800 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&asin))); |
| 3904 | 3801 |
| 3905 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAcos, 1, true /* is_float */, | 3802 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3906 reinterpret_cast<RuntimeFunction>( | 3803 LibcAcos, |
| 3907 static_cast<UnaryMathCFunction>(&acos))); | 3804 1, |
| 3805 true /* is_float */, |
| 3806 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&acos))); |
| 3908 | 3807 |
| 3909 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTan, 1, true /* is_float */, | 3808 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3910 reinterpret_cast<RuntimeFunction>( | 3809 LibcTan, |
| 3911 static_cast<UnaryMathCFunction>(&tan))); | 3810 1, |
| 3811 true /* is_float */, |
| 3812 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&tan))); |
| 3912 | 3813 |
| 3913 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan, 1, true /* is_float */, | 3814 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3914 reinterpret_cast<RuntimeFunction>( | 3815 LibcAtan, |
| 3915 static_cast<UnaryMathCFunction>(&atan))); | 3816 1, |
| 3817 true /* is_float */, |
| 3818 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&atan))); |
| 3916 | 3819 |
| 3917 | 3820 |
| 3918 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { | 3821 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { |
| 3919 switch (recognized_kind_) { | 3822 switch (recognized_kind_) { |
| 3920 case MethodRecognizer::kDoubleTruncate: | 3823 case MethodRecognizer::kDoubleTruncate: |
| 3921 return kLibcTruncRuntimeEntry; | 3824 return kLibcTruncRuntimeEntry; |
| 3922 case MethodRecognizer::kDoubleRound: | 3825 case MethodRecognizer::kDoubleRound: |
| 3923 return kLibcRoundRuntimeEntry; | 3826 return kLibcRoundRuntimeEntry; |
| 3924 case MethodRecognizer::kDoubleFloor: | 3827 case MethodRecognizer::kDoubleFloor: |
| 3925 return kLibcFloorRuntimeEntry; | 3828 return kLibcFloorRuntimeEntry; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3945 return kLibcAtan2RuntimeEntry; | 3848 return kLibcAtan2RuntimeEntry; |
| 3946 default: | 3849 default: |
| 3947 UNREACHABLE(); | 3850 UNREACHABLE(); |
| 3948 } | 3851 } |
| 3949 return kLibcPowRuntimeEntry; | 3852 return kLibcPowRuntimeEntry; |
| 3950 } | 3853 } |
| 3951 | 3854 |
| 3952 | 3855 |
| 3953 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { | 3856 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { |
| 3954 switch (kind) { | 3857 switch (kind) { |
| 3955 case kIllegal: return "illegal"; | 3858 case kIllegal: |
| 3956 case kSqrt: return "sqrt"; | 3859 return "illegal"; |
| 3957 case kDoubleSquare: return "double-square"; | 3860 case kSqrt: |
| 3861 return "sqrt"; |
| 3862 case kDoubleSquare: |
| 3863 return "double-square"; |
| 3958 } | 3864 } |
| 3959 UNREACHABLE(); | 3865 UNREACHABLE(); |
| 3960 return ""; | 3866 return ""; |
| 3961 } | 3867 } |
| 3962 | 3868 |
| 3963 | 3869 |
| 3964 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { | 3870 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { |
| 3965 return kCaseInsensitiveCompareUC16RuntimeEntry; | 3871 return kCaseInsensitiveCompareUC16RuntimeEntry; |
| 3966 } | 3872 } |
| 3967 | 3873 |
| 3968 | 3874 |
| 3969 MergedMathInstr::MergedMathInstr(ZoneGrowableArray<Value*>* inputs, | 3875 MergedMathInstr::MergedMathInstr(ZoneGrowableArray<Value*>* inputs, |
| 3970 intptr_t deopt_id, | 3876 intptr_t deopt_id, |
| 3971 MergedMathInstr::Kind kind) | 3877 MergedMathInstr::Kind kind) |
| 3972 : PureDefinition(deopt_id), | 3878 : PureDefinition(deopt_id), inputs_(inputs), kind_(kind) { |
| 3973 inputs_(inputs), | |
| 3974 kind_(kind) { | |
| 3975 ASSERT(inputs_->length() == InputCountFor(kind_)); | 3879 ASSERT(inputs_->length() == InputCountFor(kind_)); |
| 3976 for (intptr_t i = 0; i < inputs_->length(); ++i) { | 3880 for (intptr_t i = 0; i < inputs_->length(); ++i) { |
| 3977 ASSERT((*inputs)[i] != NULL); | 3881 ASSERT((*inputs)[i] != NULL); |
| 3978 (*inputs)[i]->set_instruction(this); | 3882 (*inputs)[i]->set_instruction(this); |
| 3979 (*inputs)[i]->set_use_index(i); | 3883 (*inputs)[i]->set_use_index(i); |
| 3980 } | 3884 } |
| 3981 } | 3885 } |
| 3982 | 3886 |
| 3983 | 3887 |
| 3984 intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) { | 3888 intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) { |
| 3985 switch (kind) { | 3889 switch (kind) { |
| 3986 case MethodRecognizer::kMathSin: return 1; | 3890 case MethodRecognizer::kMathSin: |
| 3987 case MethodRecognizer::kMathCos: return 0; | 3891 return 1; |
| 3988 default: UNIMPLEMENTED(); return -1; | 3892 case MethodRecognizer::kMathCos: |
| 3893 return 0; |
| 3894 default: |
| 3895 UNIMPLEMENTED(); |
| 3896 return -1; |
| 3989 } | 3897 } |
| 3990 } | 3898 } |
| 3991 | 3899 |
| 3992 | 3900 |
| 3993 intptr_t MergedMathInstr::OutputIndexOf(Token::Kind token) { | 3901 intptr_t MergedMathInstr::OutputIndexOf(Token::Kind token) { |
| 3994 switch (token) { | 3902 switch (token) { |
| 3995 case Token::kTRUNCDIV: return 0; | 3903 case Token::kTRUNCDIV: |
| 3996 case Token::kMOD: return 1; | 3904 return 0; |
| 3997 default: UNIMPLEMENTED(); return -1; | 3905 case Token::kMOD: |
| 3906 return 1; |
| 3907 default: |
| 3908 UNIMPLEMENTED(); |
| 3909 return -1; |
| 3998 } | 3910 } |
| 3999 } | 3911 } |
| 4000 | 3912 |
| 4001 | 3913 |
| 4002 void NativeCallInstr::SetupNative() { | 3914 void NativeCallInstr::SetupNative() { |
| 4003 Zone* zone = Thread::Current()->zone(); | 3915 Zone* zone = Thread::Current()->zone(); |
| 4004 const Class& cls = Class::Handle(zone, function().Owner()); | 3916 const Class& cls = Class::Handle(zone, function().Owner()); |
| 4005 const Library& library = Library::Handle(zone, cls.library()); | 3917 const Library& library = Library::Handle(zone, cls.library()); |
| 4006 const int num_params = | 3918 const int num_params = |
| 4007 NativeArguments::ParameterCountForResolution(function()); | 3919 NativeArguments::ParameterCountForResolution(function()); |
| 4008 bool auto_setup_scope = true; | 3920 bool auto_setup_scope = true; |
| 4009 NativeFunction native_function = NativeEntry::ResolveNative( | 3921 NativeFunction native_function = NativeEntry::ResolveNative( |
| 4010 library, native_name(), num_params, &auto_setup_scope); | 3922 library, native_name(), num_params, &auto_setup_scope); |
| 4011 if (native_function == NULL) { | 3923 if (native_function == NULL) { |
| 4012 Report::MessageF(Report::kError, | 3924 Report::MessageF(Report::kError, Script::Handle(function().script()), |
| 4013 Script::Handle(function().script()), | 3925 function().token_pos(), Report::AtLocation, |
| 4014 function().token_pos(), | |
| 4015 Report::AtLocation, | |
| 4016 "native function '%s' (%" Pd " arguments) cannot be found", | 3926 "native function '%s' (%" Pd " arguments) cannot be found", |
| 4017 native_name().ToCString(), | 3927 native_name().ToCString(), function().NumParameters()); |
| 4018 function().NumParameters()); | |
| 4019 } | 3928 } |
| 4020 set_native_c_function(native_function); | 3929 set_native_c_function(native_function); |
| 4021 function().SetIsNativeAutoSetupScope(auto_setup_scope); | 3930 function().SetIsNativeAutoSetupScope(auto_setup_scope); |
| 4022 Dart_NativeEntryResolver resolver = library.native_entry_resolver(); | 3931 Dart_NativeEntryResolver resolver = library.native_entry_resolver(); |
| 4023 bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); | 3932 bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); |
| 4024 set_is_bootstrap_native(is_bootstrap_native); | 3933 set_is_bootstrap_native(is_bootstrap_native); |
| 4025 } | 3934 } |
| 4026 | 3935 |
| 4027 #undef __ | 3936 #undef __ |
| 4028 | 3937 |
| 4029 } // namespace dart | 3938 } // namespace dart |
| OLD | NEW |