diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index 555c70a58be..9a7cf79a6f0 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc @@ -978,13 +978,13 @@ void EffectGraphVisitor::BuildTypecheckPushArguments( // No instantiator when inside factory. *push_instantiator_result = PushArgument(BuildNullValue()); instantiator_type_arguments = - BuildInstantiatorTypeArguments(token_pos, NULL); + BuildInstantiatorTypeArguments(token_pos, instantiator_class, NULL); } else { instantiator = Bind(BuildStoreExprTemp(instantiator)); *push_instantiator_result = PushArgument(instantiator); Value* loaded = Bind(BuildLoadExprTemp()); instantiator_type_arguments = - BuildInstantiatorTypeArguments(token_pos, loaded); + BuildInstantiatorTypeArguments(token_pos, instantiator_class, loaded); } *push_instantiator_type_arguments_result = PushArgument(instantiator_type_arguments); @@ -1007,13 +1007,13 @@ void EffectGraphVisitor::BuildTypecheckArguments( // No instantiator when inside factory. instantiator = BuildNullValue(); instantiator_type_arguments = - BuildInstantiatorTypeArguments(token_pos, NULL); + BuildInstantiatorTypeArguments(token_pos, instantiator_class, NULL); } else { // Preserve instantiator. instantiator = Bind(BuildStoreExprTemp(instantiator)); Value* loaded = Bind(BuildLoadExprTemp()); instantiator_type_arguments = - BuildInstantiatorTypeArguments(token_pos, loaded); + BuildInstantiatorTypeArguments(token_pos, instantiator_class, loaded); } *instantiator_result = instantiator; *instantiator_type_arguments_result = instantiator_type_arguments; @@ -1843,7 +1843,11 @@ void EffectGraphVisitor::VisitClosureNode(ClosureNode* node) { Value* type_arguments = NULL; if (requires_type_arguments) { ASSERT(!function.IsImplicitStaticClosureFunction()); - type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), NULL); + const Class& instantiator_class = Class::Handle( + owner()->parsed_function().function().Owner()); + type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), + instantiator_class, + NULL); } else { type_arguments = BuildNullValue(); } @@ -2161,9 +2165,9 @@ Value* EffectGraphVisitor::BuildInstantiator() { // 'expression_temp_var' may not be used inside this method if 'instantiator' // is not NULL. Value* EffectGraphVisitor::BuildInstantiatorTypeArguments( - intptr_t token_pos, Value* instantiator) { - const Class& instantiator_class = Class::Handle( - owner()->parsed_function().function().Owner()); + intptr_t token_pos, + const Class& instantiator_class, + Value* instantiator) { if (instantiator_class.NumTypeParameters() == 0) { // The type arguments are compile time constants. AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle(); @@ -2216,10 +2220,13 @@ Value* EffectGraphVisitor::BuildInstantiatedTypeArguments( return Bind(new ConstantInstr(type_arguments)); } // The type arguments are uninstantiated. + const Class& instantiator_class = Class::ZoneHandle( + owner()->parsed_function().function().Owner()); Value* instantiator_value = - BuildInstantiatorTypeArguments(token_pos, NULL); + BuildInstantiatorTypeArguments(token_pos, instantiator_class, NULL); return Bind(new InstantiateTypeArgumentsInstr(token_pos, type_arguments, + instantiator_class, instantiator_value)); } @@ -2265,8 +2272,10 @@ void EffectGraphVisitor::BuildConstructorTypeArguments( ASSERT(owner()->parsed_function().expression_temp_var() != NULL); const LocalVariable& t1 = *owner()->parsed_function().expression_temp_var(); const LocalVariable& t2 = node->allocated_object_var(); + const Class& instantiator_class = Class::Handle( + owner()->parsed_function().function().Owner()); Value* instantiator_type_arguments = BuildInstantiatorTypeArguments( - node->token_pos(), NULL); + node->token_pos(), instantiator_class, NULL); Value* stored_instantiator = Bind(BuildStoreTemp(t1, instantiator_type_arguments)); // t1: instantiator type arguments. @@ -2275,6 +2284,7 @@ void EffectGraphVisitor::BuildConstructorTypeArguments( new ExtractConstructorTypeArgumentsInstr( node->token_pos(), node->type_arguments(), + instantiator_class, stored_instantiator)); Do(BuildStoreTemp(t2, extract_type_arguments)); @@ -2282,7 +2292,9 @@ void EffectGraphVisitor::BuildConstructorTypeArguments( Value* load_instantiator = Bind(BuildLoadLocal(t1)); Value* extract_instantiator = - Bind(new ExtractConstructorInstantiatorInstr(node, load_instantiator)); + Bind(new ExtractConstructorInstantiatorInstr(node, + instantiator_class, + load_instantiator)); Do(BuildStoreTemp(t1, extract_instantiator)); // t2: extracted constructor type arguments. // t1: extracted constructor instantiator. diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h index 1031098f115..ec525ecd765 100644 --- a/runtime/vm/flow_graph_builder.h +++ b/runtime/vm/flow_graph_builder.h @@ -274,6 +274,7 @@ class EffectGraphVisitor : public AstNodeVisitor { Value** instantiator_type_arguments); Value* BuildInstantiator(); Value* BuildInstantiatorTypeArguments(intptr_t token_pos, + const Class& instantiator_class, Value* instantiator); // Perform a type check on the given value. diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc index 38bbf2e15b0..6ad1a841e6e 100644 --- a/runtime/vm/flow_graph_optimizer.cc +++ b/runtime/vm/flow_graph_optimizer.cc @@ -4587,7 +4587,9 @@ void ConstantPropagator::VisitInstantiateTypeArguments( SetValue(instr, object); return; } - if (instr->type_arguments().IsUninstantiatedIdentity()) { + if (instr->type_arguments().IsUninstantiatedIdentity() || + instr->type_arguments().CanShareInstantiatorTypeArguments( + instr->instantiator_class())) { SetValue(instr, object); return; } diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index 16e115f4aca..934da3ff958 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -3621,9 +3621,11 @@ class InstantiateTypeArgumentsInstr : public TemplateDefinition<1> { public: InstantiateTypeArgumentsInstr(intptr_t token_pos, const AbstractTypeArguments& type_arguments, + const Class& instantiator_class, Value* instantiator) : token_pos_(token_pos), - type_arguments_(type_arguments) { + type_arguments_(type_arguments), + instantiator_class_(instantiator_class) { ASSERT(type_arguments.IsZoneHandle()); SetInputAt(0, instantiator); } @@ -3634,6 +3636,7 @@ class InstantiateTypeArgumentsInstr : public TemplateDefinition<1> { const AbstractTypeArguments& type_arguments() const { return type_arguments_; } + const Class& instantiator_class() const { return instantiator_class_; } intptr_t token_pos() const { return token_pos_; } virtual void PrintOperandsTo(BufferFormatter* f) const; @@ -3645,6 +3648,7 @@ class InstantiateTypeArgumentsInstr : public TemplateDefinition<1> { private: const intptr_t token_pos_; const AbstractTypeArguments& type_arguments_; + const Class& instantiator_class_; DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsInstr); }; @@ -3655,9 +3659,11 @@ class ExtractConstructorTypeArgumentsInstr : public TemplateDefinition<1> { ExtractConstructorTypeArgumentsInstr( intptr_t token_pos, const AbstractTypeArguments& type_arguments, + const Class& instantiator_class, Value* instantiator) : token_pos_(token_pos), - type_arguments_(type_arguments) { + type_arguments_(type_arguments), + instantiator_class_(instantiator_class) { SetInputAt(0, instantiator); } @@ -3667,6 +3673,7 @@ class ExtractConstructorTypeArgumentsInstr : public TemplateDefinition<1> { const AbstractTypeArguments& type_arguments() const { return type_arguments_; } + const Class& instantiator_class() const { return instantiator_class_; } intptr_t token_pos() const { return token_pos_; } virtual void PrintOperandsTo(BufferFormatter* f) const; @@ -3678,6 +3685,7 @@ class ExtractConstructorTypeArgumentsInstr : public TemplateDefinition<1> { private: const intptr_t token_pos_; const AbstractTypeArguments& type_arguments_; + const Class& instantiator_class_; DISALLOW_COPY_AND_ASSIGN(ExtractConstructorTypeArgumentsInstr); }; @@ -3686,8 +3694,9 @@ class ExtractConstructorTypeArgumentsInstr : public TemplateDefinition<1> { class ExtractConstructorInstantiatorInstr : public TemplateDefinition<1> { public: ExtractConstructorInstantiatorInstr(ConstructorCallNode* ast_node, + const Class& instantiator_class, Value* instantiator) - : ast_node_(*ast_node) { + : ast_node_(*ast_node), instantiator_class_(instantiator_class) { SetInputAt(0, instantiator); } @@ -3698,6 +3707,7 @@ class ExtractConstructorInstantiatorInstr : public TemplateDefinition<1> { return ast_node_.type_arguments(); } const Function& constructor() const { return ast_node_.constructor(); } + const Class& instantiator_class() const { return instantiator_class_; } intptr_t token_pos() const { return ast_node_.token_pos(); } virtual bool CanDeoptimize() const { return false; } @@ -3706,6 +3716,7 @@ class ExtractConstructorInstantiatorInstr : public TemplateDefinition<1> { private: const ConstructorCallNode& ast_node_; + const Class& instantiator_class_; DISALLOW_COPY_AND_ASSIGN(ExtractConstructorInstantiatorInstr); }; diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc index 7931c46f385..c54b6870328 100644 --- a/runtime/vm/intermediate_language_arm.cc +++ b/runtime/vm/intermediate_language_arm.cc @@ -1458,7 +1458,9 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode( // 'instantiator_reg' is the instantiator AbstractTypeArguments object // (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1507,7 +1509,9 @@ void ExtractConstructorTypeArgumentsInstr::EmitNativeCode( // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1549,7 +1553,9 @@ void ExtractConstructorInstantiatorInstr::EmitNativeCode( // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity()) { + if (type_arguments().IsUninstantiatedIdentity() || + type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // The instantiator was used in VisitExtractConstructorTypeArguments as the // instantiated type arguments, no proper instantiator needed. __ LoadImmediate(instantiator_reg, diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index 34ac72ad3d9..bd279d3e9f3 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc @@ -1875,7 +1875,9 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode( // 'instantiator_reg' is the instantiator AbstractTypeArguments object // (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1925,7 +1927,9 @@ void ExtractConstructorTypeArgumentsInstr::EmitNativeCode( // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1968,7 +1972,9 @@ void ExtractConstructorInstantiatorInstr::EmitNativeCode( // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity()) { + if (type_arguments().IsUninstantiatedIdentity() || + type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // The instantiator was used in VisitExtractConstructorTypeArguments as the // instantiated type arguments, no proper instantiator needed. __ movl(instantiator_reg, diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc index 3e2a6493b03..316cc32f4c0 100644 --- a/runtime/vm/intermediate_language_mips.cc +++ b/runtime/vm/intermediate_language_mips.cc @@ -1485,7 +1485,9 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode( // 'instantiator_reg' is the instantiator AbstractTypeArguments object // (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1541,7 +1543,9 @@ void ExtractConstructorTypeArgumentsInstr::EmitNativeCode( // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1583,7 +1587,9 @@ void ExtractConstructorInstantiatorInstr::EmitNativeCode( // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity()) { + if (type_arguments().IsUninstantiatedIdentity() || + type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // The instantiator was used in VisitExtractConstructorTypeArguments as the // instantiated type arguments, no proper instantiator needed. __ LoadImmediate(instantiator_reg, diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index e0308da8095..f899f3e1fe3 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc @@ -1845,7 +1845,9 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode( // 'instantiator_reg' is the instantiator AbstractTypeArguments object // (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1895,7 +1897,9 @@ void ExtractConstructorTypeArgumentsInstr::EmitNativeCode( // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity()) { + if (!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // If the instantiator is null and if the type argument vector // instantiated from null becomes a vector of dynamic, then use null as // the type arguments. @@ -1938,7 +1942,9 @@ void ExtractConstructorInstantiatorInstr::EmitNativeCode( // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity()) { + if (type_arguments().IsUninstantiatedIdentity() || + type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())) { // The instantiator was used in VisitExtractConstructorTypeArguments as the // instantiated type arguments, no proper instantiator needed. __ movq(instantiator_reg, diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index e2d085d43a4..30a8cd07df7 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -2619,6 +2619,14 @@ bool AbstractTypeArguments::IsUninstantiatedIdentity() const { } +bool AbstractTypeArguments::CanShareInstantiatorTypeArguments( + const Class& instantiator_class) const { + // AbstractTypeArguments is an abstract class. + UNREACHABLE(); + return false; +} + + bool AbstractTypeArguments::IsBounded() const { // AbstractTypeArguments is an abstract class. UNREACHABLE(); @@ -2848,7 +2856,7 @@ bool TypeArguments::IsInstantiated() const { bool TypeArguments::IsUninstantiatedIdentity() const { ASSERT(!IsInstantiated()); AbstractType& type = AbstractType::Handle(); - intptr_t num_types = Length(); + const intptr_t num_types = Length(); for (intptr_t i = 0; i < num_types; i++) { type = TypeAt(i); if (!type.IsTypeParameter()) { @@ -2870,6 +2878,62 @@ bool TypeArguments::IsUninstantiatedIdentity() const { } } return true; + // Note that it is not necessary to verify at runtime that the instantiator + // type vector is long enough, since this uninstantiated vector contains as + // many different type parameters as it is long. +} + + +bool TypeArguments::CanShareInstantiatorTypeArguments( + const Class& instantiator_class) const { + ASSERT(!IsInstantiated()); + const intptr_t num_instantiator_type_args = + instantiator_class.NumTypeArguments(); + const intptr_t num_instantiator_type_params = + instantiator_class.NumTypeParameters(); + const intptr_t num_super_instantiator_type_args = + num_instantiator_type_args - num_instantiator_type_params; + const intptr_t num_type_args = Length(); + // As a first requirement in order to share the instantiator type argument + // vector, this type argument vector must refer to the type parameters of the + // instantiator class in declaration order. It does not need to contain all + // type parameters. + if (num_type_args < num_super_instantiator_type_args) { + return false; + } + AbstractType& type_arg = AbstractType::Handle(); + for (intptr_t i = num_super_instantiator_type_args; i < num_type_args; i++) { + type_arg = TypeAt(i); + if (!type_arg.IsTypeParameter()) { + return false; + } + const TypeParameter& type_param = TypeParameter::Cast(type_arg); + ASSERT(type_param.IsFinalized()); + if ((type_param.index() != i)) { + return false; + } + } + // As a second requirement, the type arguments corresponding to the super type + // must be identical. + if (num_super_instantiator_type_args == 0) { + return true; + } + AbstractType& super_type = AbstractType::Handle( + instantiator_class.super_type()); + const AbstractTypeArguments& super_type_args = AbstractTypeArguments::Handle( + super_type.arguments()); + if (super_type_args.IsNull()) { + return false; + } + AbstractType& super_type_arg = AbstractType::Handle(); + for (intptr_t i = 0; i < num_super_instantiator_type_args; i++) { + type_arg = TypeAt(i); + super_type_arg = super_type_args.TypeAt(i); + if (!type_arg.Equals(super_type_arg)) { + return false; + } + } + return true; } diff --git a/runtime/vm/object.h b/runtime/vm/object.h index f9a3e75b55b..fb7f5d15279 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1024,6 +1024,8 @@ class AbstractTypeArguments : public Object { virtual bool IsResolved() const; virtual bool IsInstantiated() const; virtual bool IsUninstantiatedIdentity() const; + virtual bool CanShareInstantiatorTypeArguments( + const Class& instantiator_class) const; virtual bool IsBounded() const; virtual intptr_t Hash() const; @@ -1067,6 +1069,8 @@ class TypeArguments : public AbstractTypeArguments { virtual bool IsResolved() const; virtual bool IsInstantiated() const; virtual bool IsUninstantiatedIdentity() const; + virtual bool CanShareInstantiatorTypeArguments( + const Class& instantiator_class) const; virtual bool IsBounded() const; // Canonicalize only if instantiated, otherwise returns 'this'. virtual RawAbstractTypeArguments* Canonicalize() const; @@ -1123,7 +1127,15 @@ class InstantiatedTypeArguments : public AbstractTypeArguments { virtual void SetTypeAt(intptr_t index, const AbstractType& value) const; virtual bool IsResolved() const { return true; } virtual bool IsInstantiated() const { return true; } - virtual bool IsUninstantiatedIdentity() const { return false; } + virtual bool IsUninstantiatedIdentity() const { + UNREACHABLE(); + return false; + } + virtual bool CanShareInstantiatorTypeArguments( + const Class& instantiator_class) const { + UNREACHABLE(); + return false; + } virtual bool IsBounded() const { return false; } // Bounds were checked. RawAbstractTypeArguments* uninstantiated_type_arguments() const {