Chromium Code Reviews| Index: runtime/vm/flow_graph_builder.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_builder.cc (revision 6710) |
| +++ runtime/vm/flow_graph_builder.cc (working copy) |
| @@ -220,21 +220,12 @@ |
| owner()->parsed_function().function().result_type()); |
| const String& dst_name = |
| String::ZoneHandle(String::NewSymbol("function result")); |
| - Value* type_arguments = NULL; |
| - if (!dst_type.IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), for_value.temp_index()); |
| - } |
| - AssertAssignableComp* assert = |
| - new AssertAssignableComp(node->id(), |
| - node->value()->token_index(), |
| - owner()->try_index(), |
| - return_value, |
| - type_arguments, |
| - dst_type, |
| - dst_name); |
| - AddInstruction(new BindInstr(temp_index(), assert)); |
| - return_value = new TempVal(temp_index()); |
| + return_value = BuildAssignableValue(node->id(), |
| + node->value()->token_index(), |
| + return_value, |
| + dst_type, |
| + dst_name, |
| + temp_index()); |
| } |
| } |
| @@ -275,27 +266,71 @@ |
| void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } |
| +// Returns true if the type check can be skipped, for example, if the type is |
| +// Dynamic or if the value is a compile time constant and an instance of type. |
| +static bool CanSkipTypeCheck(Value* value, const AbstractType& dst_type) { |
| + ASSERT(FLAG_enable_type_checks); |
| + ASSERT(!dst_type.IsNull()); |
| + ASSERT(dst_type.IsFinalized()); |
| + |
| + // Any expression is assignable to the Dynamic type and to the Object type. |
| + // Skip the test. |
| + if (!dst_type.IsMalformed() && |
| + (dst_type.IsDynamicType() || dst_type.IsObjectType())) { |
| + return true; |
| + } |
| + |
| + // It is a compile-time error to explicitly return a value (including null) |
| + // from a void function. However, functions that do not explicitly return a |
| + // value, implicitly return null. This includes void functions. Therefore, we |
| + // skip the type test here and trust the parser to only return null in void |
| + // function. |
| + if (dst_type.IsVoidType()) { |
| + return true; |
| + } |
| + |
| + // Eliminate the test if it can be performed successfully at compile time. |
| + if ((value != NULL) && value->IsConstant()) { |
| + Instance& literal_value = Instance::Handle(); |
| + literal_value ^= value->AsConstant()->value().raw(); |
| + const Class& cls = Class::Handle(literal_value.clazz()); |
| + if (cls.IsNullClass()) { |
| + ASSERT(literal_value.IsNull() || |
| + (literal_value.raw() == Object::sentinel()) || |
| + (literal_value.raw() == Object::transition_sentinel())); |
|
srdjan
2012/04/18 21:33:16
Why is this assert needed?
regis
2012/04/18 21:58:31
The assert is only to document the fact that we el
|
| + return true; |
| + } |
| + Error& malformed_error = Error::Handle(); |
| + if (!dst_type.IsMalformed() && |
| + dst_type.IsInstantiated() && |
| + literal_value.IsInstanceOf(dst_type, |
| + TypeArguments::Handle(), |
| + &malformed_error)) { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| + |
| // <Expression> :: Assignable { expr: <Expression> |
| // type: AbstractType |
| // dst_name: String } |
| void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| + UNREACHABLE(); |
| +} |
| + |
| + |
| +void ValueGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| ValueGraphVisitor for_value(owner(), temp_index()); |
| node->expr()->Visit(&for_value); |
| Append(for_value); |
| - Value* type_arguments = NULL; |
| - if (!node->type().IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), for_value.temp_index()); |
| - } |
| - AssertAssignableComp* assert_assignable = |
| - new AssertAssignableComp(node->id(), |
| - node->token_index(), |
| - owner()->try_index(), |
| - for_value.value(), |
| - type_arguments, |
| - node->type(), |
| - node->dst_name()); |
| - ReturnComputation(assert_assignable); |
| + ReturnValue(BuildAssignableValue(node->id(), |
| + node->token_index(), |
| + for_value.value(), |
| + node->type(), |
| + node->dst_name(), |
| + temp_index())); |
| } |
| @@ -473,6 +508,62 @@ |
| } |
| +void EffectGraphVisitor::BuildAssertAssignable(intptr_t node_id, |
| + intptr_t token_index, |
| + Value* value, |
| + const AbstractType& dst_type, |
| + const String& dst_name, |
| + intptr_t start_index) { |
| + // We should not call this function if the type check can be skipped. |
| + ASSERT(!CanSkipTypeCheck(value, dst_type)); |
| + |
| + // Build the type check computation. |
| + Value* instantiator_type_arguments = NULL; |
| + if (!dst_type.IsInstantiated()) { |
| + instantiator_type_arguments = |
| + BuildInstantiatorTypeArguments(token_index, start_index + 1); |
| + } |
| + AssertAssignableComp* assert_assignable = |
| + new AssertAssignableComp(node_id, |
| + token_index, |
| + owner()->try_index(), |
| + value, |
| + instantiator_type_arguments, |
| + dst_type, |
| + dst_name); |
| + AddInstruction(new DoInstr(assert_assignable)); |
| +} |
| + |
| + |
| +Value* EffectGraphVisitor::BuildAssignableValue(intptr_t node_id, |
| + intptr_t token_index, |
| + Value* value, |
| + const AbstractType& dst_type, |
| + const String& dst_name, |
| + intptr_t start_index) { |
| + if (CanSkipTypeCheck(value, dst_type)) { |
| + return value; |
| + } |
| + |
| + // Build the type check computation. |
| + Value* instantiator_type_arguments = NULL; |
| + if (!dst_type.IsInstantiated()) { |
| + instantiator_type_arguments = |
| + BuildInstantiatorTypeArguments(token_index, start_index + 1); |
| + } |
| + AssertAssignableComp* assert_assignable = |
| + new AssertAssignableComp(node_id, |
| + token_index, |
| + owner()->try_index(), |
| + value, |
| + instantiator_type_arguments, |
| + dst_type, |
| + dst_name); |
| + AddInstruction(new BindInstr(start_index, assert_assignable)); |
| + return new TempVal(start_index); |
| +} |
| + |
| + |
| void EffectGraphVisitor::BuildInstanceOf(ComparisonNode* node) { |
| ASSERT(Token::IsInstanceofOperator(node->kind())); |
| EffectGraphVisitor for_left_value(owner(), temp_index()); |
| @@ -1797,28 +1888,17 @@ |
| ValueGraphVisitor for_value(owner(), temp_index()); |
| node->value()->Visit(&for_value); |
| Append(for_value); |
| - |
| - Value* value = for_value.value(); |
| + Value* store_value = for_value.value(); |
| if (FLAG_enable_type_checks) { |
| - Value* type_arguments = NULL; |
| - if (!node->local().type().IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), for_value.temp_index()); |
| - } |
| - AssertAssignableComp* assert_assignable = |
| - new AssertAssignableComp(node->id(), |
| - node->value()->token_index(), |
| - owner()->try_index(), |
| - value, |
| - type_arguments, |
| - node->local().type(), |
| - node->local().name()); |
| - AddInstruction(new BindInstr(temp_index(), assert_assignable)); |
| - value = new TempVal(temp_index()); |
| + store_value = BuildAssignableValue(node->id(), |
| + node->value()->token_index(), |
| + store_value, |
| + node->local().type(), |
| + node->local().name(), |
| + temp_index()); |
| } |
| - |
| StoreLocalComp* store = |
| - new StoreLocalComp(node->local(), value, owner()->context_level()); |
| + new StoreLocalComp(node->local(), store_value, owner()->context_level()); |
| ReturnComputation(store); |
| } |
| @@ -1845,21 +1925,13 @@ |
| Value* store_value = for_value.value(); |
| if (FLAG_enable_type_checks) { |
| const AbstractType& type = AbstractType::ZoneHandle(node->field().type()); |
| - Value* type_arguments = NULL; |
| - if (!type.IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), for_value.temp_index()); |
| - } |
| - AssertAssignableComp* assert_assignable = |
| - new AssertAssignableComp(node->id(), |
| - node->value()->token_index(), |
| - owner()->try_index(), |
| - store_value, |
| - type_arguments, |
| - type, |
| - String::ZoneHandle(node->field().name())); |
| - AddInstruction(new BindInstr(temp_index() + 1, assert_assignable)); |
| - store_value = new TempVal(temp_index() + 1); |
| + const String& dst_name = String::ZoneHandle(node->field().name()); |
| + store_value = BuildAssignableValue(node->id(), |
| + node->value()->token_index(), |
| + store_value, |
| + type, |
| + dst_name, |
| + for_instance.temp_index()); |
| } |
| StoreInstanceFieldComp* store = |
| new StoreInstanceFieldComp(node, for_instance.value(), store_value); |
| @@ -1880,21 +1952,13 @@ |
| Value* store_value = for_value.value(); |
| if (FLAG_enable_type_checks) { |
| const AbstractType& type = AbstractType::ZoneHandle(node->field().type()); |
| - Value* type_arguments = NULL; |
| - if (!type.IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), for_value.temp_index()); |
| - } |
| - AssertAssignableComp* assert_assignable = |
| - new AssertAssignableComp(node->id(), |
| - node->value()->token_index(), |
| - owner()->try_index(), |
| - store_value, |
| - type_arguments, |
| - type, |
| - String::ZoneHandle(node->field().name())); |
| - AddInstruction(new BindInstr(temp_index(), assert_assignable)); |
| - store_value = new TempVal(temp_index()); |
| + const String& dst_name = String::ZoneHandle(node->field().name()); |
| + store_value = BuildAssignableValue(node->id(), |
| + node->value()->token_index(), |
| + store_value, |
| + type, |
| + dst_name, |
| + temp_index()); |
| } |
| StoreStaticFieldComp* store = |
| new StoreStaticFieldComp(node->field(), store_value); |
| @@ -2048,24 +2112,18 @@ |
| for (int pos = 0; pos < num_params; pos++) { |
| const LocalVariable& parameter = *scope->VariableAt(pos); |
| ASSERT(parameter.owner() == scope); |
| - LoadLocalComp* load = new LoadLocalComp(parameter, |
| - owner()->context_level()); |
| - AddInstruction(new BindInstr(temp_index(), load)); |
| - TempVal* argument_value = new TempVal(temp_index()); |
| - Value* type_arguments = NULL; |
| - if (!parameter.type().IsInstantiated()) { |
| - type_arguments = BuildInstantiatorTypeArguments( |
| - node->token_index(), temp_index() + 1); |
| + if (!CanSkipTypeCheck(NULL, parameter.type())) { |
| + LoadLocalComp* load = new LoadLocalComp(parameter, |
| + owner()->context_level()); |
| + AddInstruction(new BindInstr(temp_index(), load)); |
| + TempVal* argument_value = new TempVal(temp_index()); |
| + BuildAssertAssignable(node->id(), |
| + parameter.token_index(), |
| + argument_value, |
| + parameter.type(), |
| + parameter.name(), |
| + temp_index()); |
| } |
| - AssertAssignableComp* assert_assignable = |
| - new AssertAssignableComp(node->id(), |
| - parameter.token_index(), |
| - owner()->try_index(), |
| - argument_value, |
| - type_arguments, |
| - parameter.type(), |
| - parameter.name()); |
| - AddInstruction(new DoInstr(assert_assignable)); |
| } |
| } |
| @@ -2304,9 +2362,9 @@ |
| OS::Print(", %s, '%s'", |
| String::Handle(comp->dst_type().Name()).ToCString(), |
| comp->dst_name().ToCString()); |
| - if (comp->type_arguments() != NULL) { |
| - OS::Print(" (type-arg:"); |
| - comp->type_arguments()->Accept(this); |
| + if (comp->instantiator_type_arguments() != NULL) { |
| + OS::Print(" (instantiator:"); |
| + comp->instantiator_type_arguments()->Accept(this); |
| } |
| OS::Print(")"); |
| } |