From e285bc52d79c4c8a05d4e0206344b997529ebc69 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Wed, 6 Jun 2018 22:03:54 +0000 Subject: [PATCH] [vm/kernel/bytecode] Optimize instantiation of types and type arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL contains 2 optimizations: * instantiator type arguments are reused if possible; * instantiator and function type arguments are not loaded if they are not needed for a particular type being instantiated. Change-Id: Id1f6e5385051044b3b9f78cef884a917e65e801d Reviewed-on: https://dart-review.googlesource.com/58680 Reviewed-by: Zach Anderson Reviewed-by: Régis Crelier Commit-Queue: Alexander Markov --- pkg/vm/lib/bytecode/gen_bytecode.dart | 122 ++++++++++-- .../testcases/bytecode/closures.dart.expect | 122 ++++++------ .../testcases/bytecode/instance_creation.dart | 19 ++ .../bytecode/instance_creation.dart.expect | 184 +++++++++++++++++- .../testcases/bytecode/literals.dart.expect | 12 +- .../testcases/bytecode/type_ops.dart.expect | 39 ++-- 6 files changed, 384 insertions(+), 114 deletions(-) diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart index 51f5fdc6267..ff56e3e06c1 100644 --- a/pkg/vm/lib/bytecode/gen_bytecode.dart +++ b/pkg/vm/lib/bytecode/gen_bytecode.dart @@ -11,6 +11,8 @@ import 'package:kernel/core_types.dart' show CoreTypes; import 'package:kernel/library_index.dart' show LibraryIndex; import 'package:kernel/transformations/constants.dart' show ConstantEvaluator, ConstantsBackend, EvaluationEnvironment; +import 'package:kernel/type_algebra.dart' + show Substitution, containsTypeVariable; import 'package:kernel/type_environment.dart' show TypeEnvironment; import 'package:kernel/vm/constants_native_effects.dart' show VmConstantsBackend; @@ -57,6 +59,9 @@ class BytecodeGenerator extends RecursiveVisitor { Class enclosingClass; Member enclosingMember; + Set classTypeParameters; + Set functionTypeParameters; + List instantiatorTypeArguments; LocalVariables locals; ConstantEvaluator constantEvaluator; Map labeledStatements; @@ -285,31 +290,45 @@ class BytecodeGenerator extends RecursiveVisitor { } void _genTypeArguments(List typeArgs, {Class instantiatingClass}) { - int typeArgsCPIndex = cp.add(new ConstantTypeArguments(typeArgs)); - if (instantiatingClass != null) { - typeArgsCPIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation( - instantiatingClass, typeArgsCPIndex)); + int typeArgsCPIndex() { + int cpIndex = cp.add(new ConstantTypeArguments(typeArgs)); + if (instantiatingClass != null) { + cpIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation( + instantiatingClass, cpIndex)); + } + return cpIndex; } + if (typeArgs.isEmpty || !hasTypeParameters(typeArgs)) { - asm.emitPushConstant(typeArgsCPIndex); + asm.emitPushConstant(typeArgsCPIndex()); } else { - // TODO(alexmarkov): try to reuse instantiator type arguments - _genPushInstantiatorAndFunctionTypeArguments(typeArgs); - asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex); + if (_canReuseInstantiatorTypeArguments(typeArgs, instantiatingClass)) { + _genPushInstantiatorTypeArguments(); + } else { + _genPushInstantiatorAndFunctionTypeArguments(typeArgs); + asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex()); + } } } void _genPushInstantiatorAndFunctionTypeArguments(List types) { - // TODO(alexmarkov): do not load instantiator type arguments / function type - // arguments if they are not needed for these particular [types]. - _genPushInstantiatorTypeArguments(); - _genPushFunctionTypeArguments(); + if (classTypeParameters != null && + types.any((t) => containsTypeVariable(t, classTypeParameters))) { + assert(instantiatorTypeArguments != null); + _genPushInstantiatorTypeArguments(); + } else { + _genPushNull(); + } + if (functionTypeParameters != null && + types.any((t) => containsTypeVariable(t, functionTypeParameters))) { + _genPushFunctionTypeArguments(); + } else { + _genPushNull(); + } } void _genPushInstantiatorTypeArguments() { - // TODO(alexmarkov): access to type arguments in factory constructors. - if ((enclosingMember.isInstanceMember || enclosingMember is Constructor) && - hasInstantiatorTypeArguments(enclosingClass)) { + if (instantiatorTypeArguments != null) { _genPushReceiver(); final int cpIndex = cp.add(new ConstantTypeArgumentsFieldOffset(enclosingClass)); @@ -319,6 +338,48 @@ class BytecodeGenerator extends RecursiveVisitor { } } + List _flattenInstantiatorTypeArguments( + Class instantiatedClass, List typeArgs) { + assert(typeArgs.length == instantiatedClass.typeParameters.length); + + List flatTypeArgs; + final supertype = instantiatedClass.supertype; + if (supertype == null) { + flatTypeArgs = []; + } else { + final substitution = + Substitution.fromPairs(instantiatedClass.typeParameters, typeArgs); + flatTypeArgs = _flattenInstantiatorTypeArguments(supertype.classNode, + substitution.substituteSupertype(supertype).typeArguments); + } + flatTypeArgs.addAll(typeArgs); + return flatTypeArgs; + } + + bool _canReuseInstantiatorTypeArguments( + List typeArgs, Class instantiatingClass) { + if (instantiatorTypeArguments == null) { + return false; + } + + if (instantiatingClass != null) { + typeArgs = + _flattenInstantiatorTypeArguments(instantiatingClass, typeArgs); + } + + if (typeArgs.length > instantiatorTypeArguments.length) { + return false; + } + + for (int i = 0; i < typeArgs.length; ++i) { + if (typeArgs[i] != instantiatorTypeArguments[i]) { + return false; + } + } + + return true; + } + void _genPushFunctionTypeArguments() { if (locals.hasTypeArgsVar) { asm.emitPush(locals.typeArgsVarIndexInFrame); @@ -440,6 +501,24 @@ class BytecodeGenerator extends RecursiveVisitor { void start(Member node) { enclosingClass = node.enclosingClass; enclosingMember = node; + if (enclosingMember.isInstanceMember || enclosingMember is Constructor) { + if (enclosingClass.typeParameters.isNotEmpty) { + classTypeParameters = + new Set.from(enclosingClass.typeParameters); + } + if (hasInstantiatorTypeArguments(enclosingClass)) { + final typeParameters = enclosingClass.typeParameters + .map((p) => new TypeParameterType(p)) + .toList(); + instantiatorTypeArguments = + _flattenInstantiatorTypeArguments(enclosingClass, typeParameters); + } + } + if (enclosingMember.function != null && + enclosingMember.function.typeParameters.isNotEmpty) { + functionTypeParameters = + new Set.from(enclosingMember.function.typeParameters); + } locals = new LocalVariables(node); // TODO(alexmarkov): improve caching in ConstantEvaluator and reuse it constantEvaluator = new ConstantEvaluator(constantsBackend, typeEnvironment, @@ -496,6 +575,9 @@ class BytecodeGenerator extends RecursiveVisitor { enclosingClass = null; enclosingMember = null; + classTypeParameters = null; + functionTypeParameters = null; + instantiatorTypeArguments = null; locals = null; constantEvaluator = null; labeledStatements = null; @@ -610,6 +692,12 @@ class BytecodeGenerator extends RecursiveVisitor { _pushAssemblerState(); locals.enterScope(node); + + if (function.typeParameters.isNotEmpty) { + functionTypeParameters ??= new Set(); + functionTypeParameters.addAll(function.typeParameters); + } + List