Further improve type optimization reusing the type argument vector of the

instantiator of generic objects (fixes issue 10149).
This optimization considers the generic type argument vector of the instance
being allocated as well as the generic type argument vector of the compile
time type of the instantiator.
If the instance vector is a prefix of the instantiator vector, the instantiator
vector can be shared by the new instance.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//14106013

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@22155 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
regis@google.com 2013-04-29 23:39:46 +00:00
parent 04cb8721ad
commit 0e030b6f5c
10 changed files with 155 additions and 29 deletions

View file

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

View file

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

View file

@ -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;
}

View file

@ -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);
};

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
}

View file

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