| Index: pkg/compiler/lib/src/ssa/optimize.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
|
| index 4700112b3211ec528f9b1bd3194091f8c985be00..980fb4faa746909e345ebfc653797fa6d8bfddca 100644
|
| --- a/pkg/compiler/lib/src/ssa/optimize.dart
|
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart
|
| @@ -1037,6 +1037,69 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| return handleInterceptedCall(node);
|
| }
|
|
|
| + bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
|
| + ClassWorld classWorld = compiler.world;
|
| + if (classWorld.isUsedAsMixin(cls)) return true;
|
| +
|
| + return classWorld.anyStrictSubclassOf(cls, (ClassElement subclass) {
|
| + return !backend.rti.isTrivialSubstitution(subclass, cls);
|
| + });
|
| + }
|
| +
|
| + HInstruction visitTypeInfoExpression(HTypeInfoExpression node) {
|
| + // Identify the case where the type info expression would be of the form:
|
| + //
|
| + // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)]
|
| + //
|
| + // and k is the number of type arguments of 'this'. We can simply copy the
|
| + // list from 'this'.
|
| + HInstruction tryCopyInfo() {
|
| + if (node.kind != TypeInfoExpressionKind.INSTANCE) return null;
|
| +
|
| + HInstruction source;
|
| + int expectedIndex = 0;
|
| +
|
| + for (HInstruction argument in node.inputs) {
|
| + if (argument is HTypeInfoReadVariable) {
|
| + HInstruction nextSource = argument.object;
|
| + if (nextSource is HThis) {
|
| + if (source == null) {
|
| + source = nextSource;
|
| + ClassElement contextClass =
|
| + nextSource.sourceElement.enclosingClass;
|
| + if (node.inputs.length != contextClass.typeVariables.length) {
|
| + return null;
|
| + }
|
| + if (needsSubstitutionForTypeVariableAccess(contextClass)) {
|
| + return null;
|
| + }
|
| + }
|
| + if (nextSource != source) return null;
|
| + // Check that the index is the one we expect.
|
| + int index = argument.variable.element.index;
|
| + if (index != expectedIndex++) return null;
|
| + } else {
|
| + // TODO(sra): Handle non-this cases (i.e. inlined code). Some
|
| + // non-this cases will have a TypeMask that does not need
|
| + // substitution, even though the general case does, e.g. inlining a
|
| + // method on an exact class.
|
| + return null;
|
| + }
|
| + } else {
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + if (source == null) return null;
|
| + return new HTypeInfoReadRaw(source, backend.dynamicType);
|
| + }
|
| +
|
| + // TODO(sra): Consider fusing type expression trees with no type variables,
|
| + // as these could be represented like constants.
|
| +
|
| + return tryCopyInfo() ?? node;
|
| + }
|
| +
|
| HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
|
| TypeVariableType variable = node.variable;
|
| HInstruction object = node.object;
|
|
|