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

Unified Diff: runtime/vm/intermediate_language.cc

Issue 12221139: Revert "Remove SminessPropagator and FlowGraphTypePropagator and all associated infrastructure and … (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/intermediate_language.cc
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index d3fb7d295292c81d52523656fe9535dc4d7ce6a7..7b8e997150c84ea4da8d6cf68d74312d98a54121 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -25,15 +25,15 @@ DEFINE_FLAG(bool, new_identity_spec, true,
DEFINE_FLAG(bool, propagate_ic_data, true,
"Propagate IC data from unoptimized to optimized IC calls.");
DECLARE_FLAG(bool, enable_type_checks);
-DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(int, max_polymorphic_checks);
DECLARE_FLAG(bool, trace_optimization);
Definition::Definition()
: range_(NULL),
- type_(NULL),
temp_index_(-1),
ssa_temp_index_(-1),
+ propagated_type_(AbstractType::Handle()),
+ propagated_cid_(kIllegalCid),
input_use_list_(NULL),
env_use_list_(NULL),
use_kind_(kValue), // Phis and parameters rely on this default.
@@ -146,7 +146,10 @@ bool LoadFieldInstr::AttributesEqual(Instruction* other) const {
LoadFieldInstr* other_load = other->AsLoadField();
ASSERT(other_load != NULL);
ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) ||
- ((immutable_ == other_load->immutable_)));
+ ((immutable_ == other_load->immutable_) &&
+ ((ResultCid() == other_load->ResultCid()) ||
+ (ResultCid() == kDynamicCid) ||
+ (other_load->ResultCid() == kDynamicCid))));
return offset_in_bytes() == other_load->offset_in_bytes();
}
@@ -404,17 +407,178 @@ void FlowGraphVisitor::VisitBlocks() {
}
-bool Value::NeedsStoreBuffer() {
- if (Type()->IsNull() ||
- (Type()->ToNullableCid() == kSmiCid) ||
- (Type()->ToNullableCid() == kBoolCid)) {
+// TODO(regis): Support a set of compile types for the given value.
+bool Value::CanComputeIsNull(bool* is_null) const {
+ ASSERT(is_null != NULL);
+ // For now, we can only return a meaningful result if the value is constant.
+ if (!BindsToConstant()) {
return false;
}
+ // Return true if the constant value is Object::null.
+ if (BindsToConstantNull()) {
+ *is_null = true;
+ return true;
+ }
+
+ // Consider the compile type of the value to check for sentinels, which are
+ // also treated as null.
+ const AbstractType& compile_type = AbstractType::Handle(CompileType());
+ ASSERT(!compile_type.IsMalformed());
+ ASSERT(!compile_type.IsVoidType());
+
+ // There are only three instances that can be of type Null:
+ // Object::null(), Object::sentinel(), and Object::transition_sentinel().
+ // The inline code and run time code performing the type check will only
+ // encounter the 2 sentinel values if type check elimination was disabled.
+ // Otherwise, the type check of a sentinel value will be eliminated here,
+ // because these sentinel values can only be encountered as constants, never
+ // as actual value of a heap object being type checked.
+ if (compile_type.IsNullType()) {
+ *is_null = true;
+ return true;
+ }
+
+ return false;
+}
+
+
+// TODO(regis): Support a set of compile types for the given value.
+bool Value::CanComputeIsInstanceOf(const AbstractType& type,
+ bool* is_instance) const {
+ ASSERT(is_instance != NULL);
+ // We cannot give an answer if the given type is malformed.
+ if (type.IsMalformed()) {
+ return false;
+ }
+
+ // We should never test for an instance of null.
+ ASSERT(!type.IsNullType());
+
+ // Consider the compile type of the value.
+ const AbstractType& compile_type = AbstractType::Handle(CompileType());
+ if (compile_type.IsMalformed()) {
+ return false;
+ }
+
+ // If the compile type of the value is void, we are type checking the result
+ // of a void function, which was checked to be null at the return statement
+ // inside the function.
+ if (compile_type.IsVoidType()) {
+ ASSERT(FLAG_enable_type_checks);
+ *is_instance = true;
+ return true;
+ }
+
+ // The Null type is only a subtype of Object and of dynamic.
+ // Functions that do not explicitly return a value, implicitly return null,
+ // except generative constructors, which return the object being constructed.
+ // It is therefore acceptable for void functions to return null.
+ if (compile_type.IsNullType()) {
+ *is_instance =
+ type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
+ return true;
+ }
+
+ // Until we support a set of compile types, we can only give answers for
+ // constant values. Indeed, a variable of the proper compile time type may
+ // still hold null at run time and therefore fail the test.
+ if (!BindsToConstant()) {
+ return false;
+ }
+
+ // A non-null constant is not an instance of void.
+ if (type.IsVoidType()) {
+ *is_instance = false;
+ return true;
+ }
+
+ // Since the value is a constant, its type is instantiated.
+ ASSERT(compile_type.IsInstantiated());
+
+ // The run time type of the value is guaranteed to be a subtype of the
+ // compile time type of the value. However, establishing here that the
+ // compile time type is a subtype of the given type does not guarantee that
+ // the run time type will also be a subtype of the given type, because the
+ // subtype relation is not transitive when an uninstantiated type is
+ // involved.
+ Error& malformed_error = Error::Handle();
+ if (type.IsInstantiated()) {
+ // Perform the test on the compile-time type and provide the answer, unless
+ // the type test produced a malformed error (e.g. an upper bound error).
+ *is_instance = compile_type.IsSubtypeOf(type, &malformed_error);
+ } else {
+ // However, the 'more specific than' relation is transitive and used here.
+ // In other words, if the compile type of the value is more specific than
+ // the given type, the run time type of the value, which is guaranteed to be
+ // a subtype of the compile type, is also guaranteed to be a subtype of the
+ // given type.
+ *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
+ }
+ return malformed_error.IsNull();
+}
+
+
+bool Value::NeedsStoreBuffer() const {
+ const intptr_t cid = ResultCid();
+ if ((cid == kSmiCid) || (cid == kBoolCid) || (cid == kNullCid)) {
+ return false;
+ }
return !BindsToConstant();
}
+RawAbstractType* PhiInstr::CompileType() const {
+ ASSERT(!HasPropagatedType());
+ // Since type propagation has not yet occured, we are reaching this phi via a
+ // back edge phi input. Return null as compile type so that this input is
+ // ignored in the first iteration of type propagation.
+ return AbstractType::null();
+}
+
+
+RawAbstractType* PhiInstr::LeastSpecificInputType() const {
+ AbstractType& least_specific_type = AbstractType::Handle();
+ AbstractType& input_type = AbstractType::Handle();
+ for (intptr_t i = 0; i < InputCount(); i++) {
+ input_type = InputAt(i)->CompileType();
+ if (input_type.IsNull()) {
+ // This input is on a back edge and we are in the first iteration of type
+ // propagation. Ignore it.
+ continue;
+ }
+ ASSERT(!input_type.IsNull());
+ if (least_specific_type.IsNull() ||
+ least_specific_type.IsMoreSpecificThan(input_type, NULL)) {
+ // Type input_type is less specific than the current least_specific_type.
+ least_specific_type = input_type.raw();
+ } else if (input_type.IsMoreSpecificThan(least_specific_type, NULL)) {
+ // Type least_specific_type is less specific than input_type. No change.
+ } else {
+ // The types are unrelated. No need to continue.
+ least_specific_type = Type::ObjectType();
+ break;
+ }
+ }
+ return least_specific_type.raw();
+}
+
+
+RawAbstractType* ParameterInstr::CompileType() const {
+ ASSERT(!HasPropagatedType());
+ // Note that returning the declared type of the formal parameter would be
+ // incorrect, because ParameterInstr is used as input to the type check
+ // verifying the run time type of the passed-in parameter and this check would
+ // always be wrongly eliminated.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* PushArgumentInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) {
// Require the predecessors to be sorted by block_id to make managing
// their corresponding phi inputs simpler.
@@ -563,6 +727,45 @@ void Definition::ReplaceWith(Definition* other,
}
+bool Definition::SetPropagatedCid(intptr_t cid) {
+ if (cid == kIllegalCid) {
+ return false;
+ }
+ if (propagated_cid_ == kIllegalCid) {
+ // First setting, nothing has changed.
+ propagated_cid_ = cid;
+ return false;
+ }
+ bool has_changed = (propagated_cid_ != cid);
+ propagated_cid_ = cid;
+ return has_changed;
+}
+
+
+intptr_t Definition::GetPropagatedCid() {
+ if (has_propagated_cid()) return propagated_cid();
+ intptr_t cid = ResultCid();
+ ASSERT(cid != kIllegalCid);
+ SetPropagatedCid(cid);
+ return cid;
+}
+
+
+intptr_t PhiInstr::GetPropagatedCid() {
+ return propagated_cid();
+}
+
+
+intptr_t ParameterInstr::GetPropagatedCid() {
+ return propagated_cid();
+}
+
+
+intptr_t AssertAssignableInstr::GetPropagatedCid() {
+ return propagated_cid();
+}
+
+
// ==== Postorder graph traversal.
static bool IsMarked(BlockEntryInstr* block,
GrowableArray<BlockEntryInstr*>* preorder) {
@@ -824,6 +1027,154 @@ void Instruction::Goto(JoinEntryInstr* entry) {
}
+RawAbstractType* Value::CompileType() const {
+ if (definition()->HasPropagatedType()) {
+ return definition()->PropagatedType();
+ }
+ // The compile type may be requested when building the flow graph, i.e. before
+ // type propagation has occurred. To avoid repeatedly computing the compile
+ // type of the definition, we store it as initial propagated type.
+ AbstractType& type = AbstractType::Handle(definition()->CompileType());
+ definition()->SetPropagatedType(type);
+ return type.raw();
+}
+
+
+intptr_t Value::ResultCid() const {
+ if (reaching_cid() == kIllegalCid) {
+ return definition()->GetPropagatedCid();
+ }
+ return reaching_cid();
+}
+
+
+
+RawAbstractType* ConstantInstr::CompileType() const {
+ if (value().IsNull()) {
+ return Type::NullType();
+ }
+ if (value().IsInstance()) {
+ return Instance::Cast(value()).GetType();
+ } else {
+ ASSERT(value().IsAbstractTypeArguments());
+ return AbstractType::null();
+ }
+}
+
+
+intptr_t ConstantInstr::ResultCid() const {
+ if (value().IsNull()) {
+ return kNullCid;
+ }
+ if (value().IsInstance()) {
+ return Class::Handle(value().clazz()).id();
+ } else {
+ ASSERT(value().IsAbstractTypeArguments());
+ return kDynamicCid;
+ }
+}
+
+
+RawAbstractType* AssertAssignableInstr::CompileType() const {
+ const AbstractType& value_compile_type =
+ AbstractType::Handle(value()->CompileType());
+ if (!value_compile_type.IsNull() &&
+ value_compile_type.IsMoreSpecificThan(dst_type(), NULL)) {
+ return value_compile_type.raw();
+ }
+ return dst_type().raw();
+}
+
+
+RawAbstractType* AssertBooleanInstr::CompileType() const {
+ return Type::BoolType();
+}
+
+
+RawAbstractType* ArgumentDefinitionTestInstr::CompileType() const {
+ return Type::BoolType();
+}
+
+
+RawAbstractType* CurrentContextInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* StoreContextInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* ClosureCallInstr::CompileType() const {
+ // Because of function subtyping rules, the declared return type of a closure
+ // call cannot be relied upon for compile type analysis. For example, a
+ // function returning dynamic can be assigned to a closure variable declared
+ // to return int and may actually return a double at run-time.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* InstanceCallInstr::CompileType() const {
+ // TODO(regis): Return a more specific type than dynamic for recognized
+ // combinations of receiver type and method name.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* PolymorphicInstanceCallInstr::CompileType() const {
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* StaticCallInstr::CompileType() const {
+ if (FLAG_enable_type_checks) {
+ return function().result_type();
+ }
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* LoadLocalInstr::CompileType() const {
+ if (FLAG_enable_type_checks) {
+ return local().type().raw();
+ }
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* StoreLocalInstr::CompileType() const {
+ return value()->CompileType();
+}
+
+
+RawAbstractType* StrictCompareInstr::CompileType() const {
+ return Type::BoolType();
+}
+
+
+// Only known == targets return a Boolean.
+RawAbstractType* EqualityCompareInstr::CompileType() const {
+ if ((receiver_class_id() == kSmiCid) ||
+ (receiver_class_id() == kDoubleCid) ||
+ (receiver_class_id() == kNumberCid)) {
+ return Type::BoolType();
+ }
+ return Type::DynamicType();
+}
+
+
+intptr_t EqualityCompareInstr::ResultCid() const {
+ if ((receiver_class_id() == kSmiCid) ||
+ (receiver_class_id() == kDoubleCid) ||
+ (receiver_class_id() == kNumberCid)) {
+ // Known/library equalities that are guaranteed to return Boolean.
+ return kBoolCid;
+ }
+ return kDynamicCid;
+}
+
+
bool EqualityCompareInstr::IsPolymorphic() const {
return HasICData() &&
(ic_data()->NumberOfChecks() > 0) &&
@@ -831,6 +1182,194 @@ bool EqualityCompareInstr::IsPolymorphic() const {
}
+RawAbstractType* RelationalOpInstr::CompileType() const {
+ if ((operands_class_id() == kSmiCid) ||
+ (operands_class_id() == kDoubleCid) ||
+ (operands_class_id() == kNumberCid)) {
+ // Known/library relational ops that are guaranteed to return Boolean.
+ return Type::BoolType();
+ }
+ return Type::DynamicType();
+}
+
+
+intptr_t RelationalOpInstr::ResultCid() const {
+ if ((operands_class_id() == kSmiCid) ||
+ (operands_class_id() == kDoubleCid) ||
+ (operands_class_id() == kNumberCid)) {
+ // Known/library relational ops that are guaranteed to return Boolean.
+ return kBoolCid;
+ }
+ return kDynamicCid;
+}
+
+
+RawAbstractType* NativeCallInstr::CompileType() const {
+ // The result type of the native function is identical to the result type of
+ // the enclosing native Dart function. However, we prefer to check the type
+ // of the value returned from the native call.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* StringFromCharCodeInstr::CompileType() const {
+ return Type::StringType();
+}
+
+
+RawAbstractType* LoadIndexedInstr::CompileType() const {
+ switch (class_id_) {
+ case kArrayCid:
+ case kImmutableArrayCid:
+ return Type::DynamicType();
+ case kFloat32ArrayCid :
+ case kFloat64ArrayCid :
+ return Type::Double();
+ case kInt8ArrayCid:
+ case kUint8ArrayCid:
+ case kUint8ClampedArrayCid:
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
+ case kInt16ArrayCid:
+ case kUint16ArrayCid:
+ case kInt32ArrayCid:
+ case kUint32ArrayCid:
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return Type::IntType();
+ default:
+ UNIMPLEMENTED();
+ return Type::IntType();
+ }
+}
+
+
+RawAbstractType* StoreIndexedInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* StoreInstanceFieldInstr::CompileType() const {
+ return value()->CompileType();
+}
+
+
+RawAbstractType* LoadStaticFieldInstr::CompileType() const {
+ if (FLAG_enable_type_checks) {
+ return field().type();
+ }
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* StoreStaticFieldInstr::CompileType() const {
+ return value()->CompileType();
+}
+
+
+RawAbstractType* BooleanNegateInstr::CompileType() const {
+ return Type::BoolType();
+}
+
+
+RawAbstractType* InstanceOfInstr::CompileType() const {
+ return Type::BoolType();
+}
+
+
+RawAbstractType* CreateArrayInstr::CompileType() const {
+ return type().raw();
+}
+
+
+RawAbstractType* CreateClosureInstr::CompileType() const {
+ const Function& fun = function();
+ const Class& signature_class = Class::Handle(fun.signature_class());
+ return signature_class.SignatureType();
+}
+
+
+RawAbstractType* AllocateObjectInstr::CompileType() const {
+ // TODO(regis): Be more specific.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* AllocateObjectWithBoundsCheckInstr::CompileType() const {
+ // TODO(regis): Be more specific.
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* LoadFieldInstr::CompileType() const {
+ // Type may be null if the field is a VM field, e.g. context parent.
+ // Keep it as null for debug purposes and do not return dynamic in production
+ // mode, since misuse of the type would remain undetected.
+ if (type().IsNull()) {
+ return AbstractType::null();
+ }
+ if (FLAG_enable_type_checks) {
+ return type().raw();
+ }
+ return Type::DynamicType();
+}
+
+
+RawAbstractType* StoreVMFieldInstr::CompileType() const {
+ return value()->CompileType();
+}
+
+
+RawAbstractType* InstantiateTypeArgumentsInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* ExtractConstructorTypeArgumentsInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* ExtractConstructorInstantiatorInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* AllocateContextInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* ChainContextInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CloneContextInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CatchEntryInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CheckStackOverflowInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* BinarySmiOpInstr::CompileType() const {
+ return Type::SmiType();
+}
+
+
+intptr_t BinarySmiOpInstr::ResultCid() const {
+ return kSmiCid;
+}
+
+
bool BinarySmiOpInstr::CanDeoptimize() const {
switch (op_kind()) {
case Token::kBIT_AND:
@@ -859,6 +1398,47 @@ bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const {
}
+RawAbstractType* BinaryMintOpInstr::CompileType() const {
+ return Type::IntType();
+}
+
+
+intptr_t BinaryMintOpInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
+RawAbstractType* ShiftMintOpInstr::CompileType() const {
+ return Type::IntType();
+}
+
+
+intptr_t ShiftMintOpInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
+RawAbstractType* UnaryMintOpInstr::CompileType() const {
+ return Type::IntType();
+}
+
+
+intptr_t UnaryMintOpInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
+RawAbstractType* BinaryDoubleOpInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+intptr_t BinaryDoubleOpInstr::ResultCid() const {
+ // The output is not an instance but when it is boxed it becomes double.
+ return kDoubleCid;
+}
+
+
static bool ToIntegerConstant(Value* value, intptr_t* result) {
if (!value->BindsToConstant()) {
if (value->definition()->IsUnboxDouble()) {
@@ -1019,6 +1599,96 @@ Definition* BinaryMintOpInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
}
+RawAbstractType* MathSqrtInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+RawAbstractType* UnboxDoubleInstr::CompileType() const {
+ return Type::null();
+}
+
+
+intptr_t BoxDoubleInstr::ResultCid() const {
+ return kDoubleCid;
+}
+
+
+RawAbstractType* BoxDoubleInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+intptr_t BoxIntegerInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
+RawAbstractType* BoxIntegerInstr::CompileType() const {
+ return Type::IntType();
+}
+
+
+intptr_t UnboxIntegerInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
+RawAbstractType* UnboxIntegerInstr::CompileType() const {
+ return Type::null();
+}
+
+
+RawAbstractType* UnarySmiOpInstr::CompileType() const {
+ return Type::SmiType();
+}
+
+
+RawAbstractType* SmiToDoubleInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+RawAbstractType* DoubleToIntegerInstr::CompileType() const {
+ return Type::IntType();
+}
+
+
+RawAbstractType* DoubleToSmiInstr::CompileType() const {
+ return Type::SmiType();
+}
+
+
+RawAbstractType* DoubleToDoubleInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+RawAbstractType* InvokeMathCFunctionInstr::CompileType() const {
+ return Type::Double();
+}
+
+
+RawAbstractType* CheckClassInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CheckSmiInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CheckArrayBoundInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
+RawAbstractType* CheckEitherNonSmiInstr::CompileType() const {
+ return AbstractType::null();
+}
+
+
// Optimizations that eliminate or simplify individual instructions.
Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) {
return this;
@@ -1082,7 +1752,7 @@ Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
StaticCallInstr* call = value()->definition()->AsStaticCall();
if (call != NULL &&
call->is_known_constructor() &&
- (call->Type()->ToCid() == kArrayCid)) {
+ call->ResultCid() == kArrayCid) {
return call->ArgumentAt(1)->value()->definition();
}
return this;
@@ -1090,18 +1760,33 @@ Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) {
- return value()->definition();
- }
-
- return this;
+ const intptr_t value_cid = value()->ResultCid();
+ return (value_cid == kBoolCid) ? value()->definition() : this;
}
Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- if (FLAG_eliminate_type_checks &&
- value()->Type()->IsAssignableTo(dst_type())) {
- return value()->definition();
+ // (1) Replace the assert with its input if the input has a known compatible
+ // class-id. The class-ids handled here are those that are known to be
+ // results of IL instructions.
+ intptr_t cid = value()->ResultCid();
+ bool is_redundant = false;
+ if (dst_type().IsIntType()) {
+ is_redundant = (cid == kSmiCid) || (cid == kMintCid);
+ } else if (dst_type().IsDoubleType()) {
+ is_redundant = (cid == kDoubleCid);
+ } else if (dst_type().IsBoolType()) {
+ is_redundant = (cid == kBoolCid);
+ }
+ if (is_redundant) return value()->definition();
+
+ // (2) Replace the assert with its input if the input is the result of a
+ // compatible assert itself.
+ AssertAssignableInstr* check = value()->definition()->AsAssertAssignable();
+ if ((check != NULL) && check->dst_type().Equals(dst_type())) {
+ // TODO(fschneider): Propagate type-assertions across phi-nodes.
+ // TODO(fschneider): Eliminate more asserts with subtype relation.
+ return check;
}
// (3) For uninstantiated target types: If the instantiator type arguments
@@ -1174,7 +1859,7 @@ Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
// Handles e === true.
if ((kind() == Token::kEQ_STRICT) &&
(right_constant.raw() == Bool::True().raw()) &&
- (left()->Type()->ToCid() == kBoolCid)) {
+ (left()->ResultCid() == kBoolCid)) {
// Return left subexpression as the replacement for this instruction.
return left_defn;
}
@@ -1183,10 +1868,7 @@ Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- // TODO(vegorov): Replace class checks with null checks when ToNullableCid
- // matches.
-
- const intptr_t value_cid = value()->Type()->ToCid();
+ const intptr_t value_cid = value()->ResultCid();
if (value_cid == kDynamicCid) {
return this;
}
@@ -1205,14 +1887,14 @@ Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- return (value()->Type()->ToCid() == kSmiCid) ? NULL : this;
+ return (value()->ResultCid() == kSmiCid) ? NULL : this;
}
Instruction* CheckEitherNonSmiInstr::Canonicalize(
FlowGraphOptimizer* optimizer) {
- if ((left()->Type()->ToCid() == kDoubleCid) ||
- (right()->Type()->ToCid() == kDoubleCid)) {
+ if ((left()->ResultCid() == kDoubleCid) ||
+ (right()->ResultCid() == kDoubleCid)) {
return NULL; // Remove from the graph.
}
return this;
@@ -1431,11 +2113,13 @@ void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- compiler->GenerateAssertAssignable(token_pos(),
- deopt_id(),
- dst_type(),
- dst_name(),
- locs());
+ if (!is_eliminated()) {
+ compiler->GenerateAssertAssignable(token_pos(),
+ deopt_id(),
+ dst_type(),
+ dst_name(),
+ locs());
+ }
ASSERT(locs()->in(0).reg() == locs()->out().reg());
}
@@ -1707,7 +2391,7 @@ RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) {
void Definition::InferRange() {
- ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis.
+ ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis.
if (range_ == NULL) {
range_ = Range::Unknown();
}
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698