[vm/kernel/bytecode] Optimize instantiation of types and type arguments

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 <zra@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 51f5fdc..ff56e3e 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -11,6 +11,8 @@
 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 enclosingClass;
   Member enclosingMember;
+  Set<TypeParameter> classTypeParameters;
+  Set<TypeParameter> functionTypeParameters;
+  List<DartType> instantiatorTypeArguments;
   LocalVariables locals;
   ConstantEvaluator constantEvaluator;
   Map<LabeledStatement, Label> labeledStatements;
@@ -285,31 +290,45 @@
   }
 
   void _genTypeArguments(List<DartType> 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<DartType> 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 @@
     }
   }
 
+  List<DartType> _flattenInstantiatorTypeArguments(
+      Class instantiatedClass, List<DartType> typeArgs) {
+    assert(typeArgs.length == instantiatedClass.typeParameters.length);
+
+    List<DartType> flatTypeArgs;
+    final supertype = instantiatedClass.supertype;
+    if (supertype == null) {
+      flatTypeArgs = <DartType>[];
+    } else {
+      final substitution =
+          Substitution.fromPairs(instantiatedClass.typeParameters, typeArgs);
+      flatTypeArgs = _flattenInstantiatorTypeArguments(supertype.classNode,
+          substitution.substituteSupertype(supertype).typeArguments);
+    }
+    flatTypeArgs.addAll(typeArgs);
+    return flatTypeArgs;
+  }
+
+  bool _canReuseInstantiatorTypeArguments(
+      List<DartType> 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 @@
   void start(Member node) {
     enclosingClass = node.enclosingClass;
     enclosingMember = node;
+    if (enclosingMember.isInstanceMember || enclosingMember is Constructor) {
+      if (enclosingClass.typeParameters.isNotEmpty) {
+        classTypeParameters =
+            new Set<TypeParameter>.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<TypeParameter>.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 @@
 
     enclosingClass = null;
     enclosingMember = null;
+    classTypeParameters = null;
+    functionTypeParameters = null;
+    instantiatorTypeArguments = null;
     locals = null;
     constantEvaluator = null;
     labeledStatements = null;
@@ -610,6 +692,12 @@
     _pushAssemblerState();
 
     locals.enterScope(node);
+
+    if (function.typeParameters.isNotEmpty) {
+      functionTypeParameters ??= new Set<TypeParameter>();
+      functionTypeParameters.addAll(function.typeParameters);
+    }
+
     List<Label> savedYieldPoints = yieldPoints;
     yieldPoints = locals.isSyncYieldingFrame ? <Label>[] : null;
 
@@ -644,6 +732,10 @@
 
     cp.add(new ConstantEndClosureFunctionScope());
 
+    if (function.typeParameters.isNotEmpty) {
+      functionTypeParameters.removeAll(function.typeParameters);
+    }
+
     locals.leaveScope();
 
     closures.add(new ClosureBytecode(
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 7bf2d87..6f72b9f 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -228,7 +228,7 @@
   Push                 r2
   InstanceCall1        1, CP#52
   Drop1
-  PushConstant         CP#36
+  PushConstant         CP#18
   ReturnTOS
 }
 ConstantPool {
@@ -250,30 +250,30 @@
   [15] = Int 0
   [16] = Type #lib::A::T1
   [17] = TypeArgumentsFieldOffset #lib::A
-  [18] = Int 1
-  [19] = Type #lib::A::T2
-  [20] = Type #lib::A::foo::T3
-  [21] = Int 3
-  [22] = Type #lib::A::foo::T4
-  [23] = Type T5
-  [24] = Int 5
-  [25] = Type T6
-  [26] = Type T7
-  [27] = Int 7
-  [28] = Type T8
-  [29] = ArgDesc num-args 1, num-type-args 1, names []
-  [30] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#29
-  [31] = ArgDesc num-args 1, num-type-args 0, names []
-  [32] = StaticICData target 'dart.core::print', arg-desc CP#31
-  [33] = TypeArgs [#lib::A::T1, #lib::A::T2, #lib::A::foo::T3, #lib::A::foo::T4, T5, T6, T7, T8]
-  [34] = ArgDesc num-args 0, num-type-args 8, names []
-  [35] = StaticICData target '#lib::callWithArgs', arg-desc CP#34
-  [36] = Null
+  [18] = Null
+  [19] = Int 1
+  [20] = Type #lib::A::T2
+  [21] = Type #lib::A::foo::T3
+  [22] = Int 3
+  [23] = Type #lib::A::foo::T4
+  [24] = Type T5
+  [25] = Int 5
+  [26] = Type T6
+  [27] = Type T7
+  [28] = Int 7
+  [29] = Type T8
+  [30] = ArgDesc num-args 1, num-type-args 1, names []
+  [31] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#30
+  [32] = ArgDesc num-args 1, num-type-args 0, names []
+  [33] = StaticICData target 'dart.core::print', arg-desc CP#32
+  [34] = TypeArgs [#lib::A::T1, #lib::A::T2, #lib::A::foo::T3, #lib::A::foo::T4, T5, T6, T7, T8]
+  [35] = ArgDesc num-args 0, num-type-args 8, names []
+  [36] = StaticICData target '#lib::callWithArgs', arg-desc CP#35
   [37] = EndClosureFunctionScope
   [38] = Class dart.core::_Closure
   [39] = FieldOffset dart.core::_Closure::_instantiator_type_arguments
   [40] = FieldOffset dart.core::_Closure::_function
-  [41] = ICData target-name 'call', arg-desc CP#31
+  [41] = ICData target-name 'call', arg-desc CP#32
   [42] = EndClosureFunctionScope
   [43] = TypeArgs [#lib::C7, #lib::C8]
   [44] = ArgDesc num-args 1, num-type-args 2, names []
@@ -306,79 +306,67 @@
   Push                 r1
   LoadFieldTOS         CP#1
   LoadFieldTOS         CP#17
-  Push                 r0
+  PushConstant         CP#18
   InstantiateType      CP#16
   StoreIndexedTOS
   Push                 r3
+  PushConstant         CP#19
+  Push                 r1
+  LoadFieldTOS         CP#1
+  LoadFieldTOS         CP#17
   PushConstant         CP#18
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
-  Push                 r0
-  InstantiateType      CP#19
-  StoreIndexedTOS
-  Push                 r3
-  PushConstant         CP#5
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
-  Push                 r0
   InstantiateType      CP#20
   StoreIndexedTOS
   Push                 r3
-  PushConstant         CP#21
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
+  PushConstant         CP#5
+  PushConstant         CP#18
   Push                 r0
-  InstantiateType      CP#22
+  InstantiateType      CP#21
   StoreIndexedTOS
   Push                 r3
-  PushConstant         CP#6
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
+  PushConstant         CP#22
+  PushConstant         CP#18
   Push                 r0
   InstantiateType      CP#23
   StoreIndexedTOS
   Push                 r3
-  PushConstant         CP#24
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
+  PushConstant         CP#6
+  PushConstant         CP#18
   Push                 r0
-  InstantiateType      CP#25
+  InstantiateType      CP#24
   StoreIndexedTOS
   Push                 r3
-  PushConstant         CP#10
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
+  PushConstant         CP#25
+  PushConstant         CP#18
   Push                 r0
   InstantiateType      CP#26
   StoreIndexedTOS
   Push                 r3
-  PushConstant         CP#27
-  Push                 r1
-  LoadFieldTOS         CP#1
-  LoadFieldTOS         CP#17
+  PushConstant         CP#10
+  PushConstant         CP#18
   Push                 r0
-  InstantiateType      CP#28
+  InstantiateType      CP#27
   StoreIndexedTOS
-  PushConstant         CP#30
-  IndirectStaticCall   2, CP#29
-  PushConstant         CP#32
-  IndirectStaticCall   1, CP#31
+  Push                 r3
+  PushConstant         CP#28
+  PushConstant         CP#18
+  Push                 r0
+  InstantiateType      CP#29
+  StoreIndexedTOS
+  PushConstant         CP#31
+  IndirectStaticCall   2, CP#30
+  PushConstant         CP#33
+  IndirectStaticCall   1, CP#32
   Drop1
   Push                 r1
   LoadFieldTOS         CP#1
   LoadFieldTOS         CP#17
   Push                 r0
-  InstantiateTypeArgumentsTOS 1, CP#33
-  PushConstant         CP#35
-  IndirectStaticCall   1, CP#34
-  Drop1
+  InstantiateTypeArgumentsTOS 1, CP#34
   PushConstant         CP#36
+  IndirectStaticCall   1, CP#35
+  Drop1
+  PushConstant         CP#18
   ReturnTOS
 
 }
@@ -417,7 +405,7 @@
   Push                 r2
   InstanceCall1        1, CP#41
   Drop1
-  PushConstant         CP#36
+  PushConstant         CP#18
   ReturnTOS
 
 }
@@ -461,7 +449,7 @@
   Push                 r2
   InstanceCall1        1, CP#47
   Drop1
-  PushConstant         CP#36
+  PushConstant         CP#18
   ReturnTOS
 
 }
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart b/pkg/vm/testcases/bytecode/instance_creation.dart
index 98259da..3f607a5 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart
@@ -38,6 +38,25 @@
   new B<List<T>>();
 }
 
+class E<K, V> {
+  test_reuse1() => new Map<K, V>();
+}
+
+class F<K, V> extends E<String, List<V>> {
+  test_reuse2() => new Map<String, List<V>>();
+}
+
+class G<K, V> {
+  G();
+  factory G.test_factory() => new H<String, K, V>();
+}
+
+class H<P1, P2, P3> extends G<P2, P3> {}
+
+void foo4() {
+  new G<int, List<String>>.test_factory();
+}
+
 main() {
   foo1();
   foo2();
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index 239c9ac..4f032eb 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -185,6 +185,158 @@
     core::print("C: ${s}");
   }
 }
+class E<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  PushConstant         CP#1
+  IndirectStaticCall   1, CP#0
+  Drop1
+  PushConstant         CP#2
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ArgDesc num-args 1, num-type-args 0, names []
+  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [2] = Null
+}
+]  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  LoadFieldTOS         CP#0
+  PushConstant         CP#2
+  IndirectStaticCall   1, CP#1
+  ReturnTOS
+  PushConstant         CP#3
+  ReturnTOS
+}
+ConstantPool {
+  [0] = TypeArgumentsFieldOffset #lib::E
+  [1] = ArgDesc num-args 0, num-type-args 2, names []
+  [2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
+  [3] = Null
+}
+]  method test_reuse1() → dynamic
+    return core::Map::•<self::E::K, self::E::V>();
+}
+class F<K extends core::Object = dynamic, V extends core::Object = dynamic> extends self::E<core::String, core::List<self::F::V>> {
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  PushConstant         CP#1
+  IndirectStaticCall   1, CP#0
+  Drop1
+  PushConstant         CP#2
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ArgDesc num-args 1, num-type-args 0, names []
+  [1] = StaticICData target '#lib::E::', arg-desc CP#0
+  [2] = Null
+}
+]  synthetic constructor •() → void
+    : super self::E::•()
+    ;
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  LoadFieldTOS         CP#0
+  PushConstant         CP#2
+  IndirectStaticCall   1, CP#1
+  ReturnTOS
+  PushConstant         CP#3
+  ReturnTOS
+}
+ConstantPool {
+  [0] = TypeArgumentsFieldOffset #lib::F
+  [1] = ArgDesc num-args 0, num-type-args 2, names []
+  [2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
+  [3] = Null
+}
+]  method test_reuse2() → dynamic
+    return core::Map::•<core::String, core::List<self::F::V>>();
+}
+class G<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  PushConstant         CP#1
+  IndirectStaticCall   1, CP#0
+  Drop1
+  PushConstant         CP#2
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ArgDesc num-args 1, num-type-args 0, names []
+  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [2] = Null
+}
+]  constructor •() → void
+    : super core::Object::•()
+    ;
+[@vm.bytecode=
+Bytecode {
+  Entry                1
+  CheckStack
+  PushConstant         CP#1
+  Push                 FP[-5]
+  InstantiateTypeArgumentsTOS 1, CP#3
+  PushConstant         CP#0
+  AllocateT
+  StoreLocal           r0
+  Push                 r0
+  PushConstant         CP#5
+  IndirectStaticCall   1, CP#4
+  Drop1
+  ReturnTOS
+  PushConstant         CP#1
+  ReturnTOS
+}
+ConstantPool {
+  [0] = Class #lib::H
+  [1] = Null
+  [2] = TypeArgs [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
+  [3] = TypeArgumentsForInstanceAllocation #lib::H type-args CP#2
+  [4] = ArgDesc num-args 1, num-type-args 0, names []
+  [5] = StaticICData target '#lib::H::', arg-desc CP#4
+}
+]  static factory test_factory<K extends core::Object = dynamic, V extends core::Object = dynamic>() → self::G<self::G::test_factory::K, self::G::test_factory::V>
+    return new self::H::•<core::String, self::G::test_factory::K, self::G::test_factory::V>();
+}
+class H<P1 extends core::Object = dynamic, P2 extends core::Object = dynamic, P3 extends core::Object = dynamic> extends self::G<self::H::P2, self::H::P3> {
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  Push                 FP[-5]
+  PushConstant         CP#1
+  IndirectStaticCall   1, CP#0
+  Drop1
+  PushConstant         CP#2
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ArgDesc num-args 1, num-type-args 0, names []
+  [1] = StaticICData target '#lib::G::', arg-desc CP#0
+  [2] = Null
+}
+]  synthetic constructor •() → void
+    : super self::G::•()
+    ;
+}
 [@vm.bytecode=
 Bytecode {
   Entry                1
@@ -257,9 +409,9 @@
 Bytecode {
   Entry                1
   CheckStack
-  PushConstant         CP#3
+  PushConstant         CP#1
   Push                 FP[-5]
-  InstantiateTypeArgumentsTOS 1, CP#2
+  InstantiateTypeArgumentsTOS 1, CP#3
   PushConstant         CP#0
   AllocateT
   StoreLocal           r0
@@ -268,14 +420,14 @@
   IndirectStaticCall   1, CP#4
   Drop1
   Drop1
-  PushConstant         CP#3
+  PushConstant         CP#1
   ReturnTOS
 }
 ConstantPool {
   [0] = Class #lib::B
-  [1] = TypeArgs [dart.core::List<#lib::foo3::T>]
-  [2] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#1
-  [3] = Null
+  [1] = Null
+  [2] = TypeArgs [dart.core::List<#lib::foo3::T>]
+  [3] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#2
   [4] = ArgDesc num-args 1, num-type-args 0, names []
   [5] = StaticICData target '#lib::B::', arg-desc CP#4
 }
@@ -286,6 +438,26 @@
 Bytecode {
   Entry                0
   CheckStack
+  PushConstant         CP#0
+  PushConstant         CP#2
+  IndirectStaticCall   1, CP#1
+  Drop1
+  PushConstant         CP#3
+  ReturnTOS
+}
+ConstantPool {
+  [0] = TypeArgs [dart.core::int, dart.core::List<dart.core::String>]
+  [1] = ArgDesc num-args 0, num-type-args 2, names []
+  [2] = StaticICData target '#lib::G::test_factory', arg-desc CP#1
+  [3] = Null
+}
+]static method foo4() → void {
+  self::G::test_factory<core::int, core::List<core::String>>();
+}
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
   PushConstant         CP#1
   IndirectStaticCall   0, CP#0
   Drop1
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index 1d49cf2..c248ce0 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -551,16 +551,16 @@
   PushConstant         CP#15
   IndirectStaticCall   1, CP#9
   Drop1
-  PushConstant         CP#17
+  PushConstant         CP#16
   Push                 FP[-8]
-  InstantiateTypeArgumentsTOS 1, CP#16
+  InstantiateTypeArgumentsTOS 1, CP#17
   PushConstant         CP#18
   PushConstant         CP#19
   IndirectStaticCall   2, CP#7
   PushConstant         CP#20
   IndirectStaticCall   1, CP#9
   Drop1
-  PushConstant         CP#17
+  PushConstant         CP#16
   Push                 FP[-8]
   InstantiateTypeArgumentsTOS 1, CP#21
   PushConstant         CP#1
@@ -580,7 +580,7 @@
   PushConstant         CP#23
   IndirectStaticCall   1, CP#9
   Drop1
-  PushConstant         CP#17
+  PushConstant         CP#16
   ReturnTOS
 }
 ConstantPool {
@@ -600,8 +600,8 @@
   [13] = ICData target-name 'toString', arg-desc CP#9
   [14] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#7
   [15] = StaticICData target 'dart.core::print', arg-desc CP#9
-  [16] = TypeArgs [dart.core::String, #lib::test_map_literal::T]
-  [17] = Null
+  [16] = Null
+  [17] = TypeArgs [dart.core::String, #lib::test_map_literal::T]
   [18] = List type-arg dynamic, entries CP# []
   [19] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#7
   [20] = StaticICData target 'dart.core::print', arg-desc CP#9
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index fe9a2d4..16f4aaf 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -159,8 +159,7 @@
   Entry                0
   CheckStack
   Push                 FP[-5]
-  Push                 FP[-6]
-  LoadFieldTOS         CP#0
+  PushConstant         CP#0
   Push                 FP[-7]
   PushConstant         CP#1
   InstanceCall1        4, CP#3
@@ -174,31 +173,31 @@
 L1:
   Push                 FP[-5]
   Push                 FP[-6]
-  LoadFieldTOS         CP#0
+  LoadFieldTOS         CP#8
   Push                 FP[-7]
-  PushConstant         CP#8
-  InstanceCall1        4, CP#9
+  PushConstant         CP#9
+  InstanceCall1        4, CP#10
   PushConstant         CP#4
   IfNeStrictTOS
   Jump                 L2
-  PushConstant         CP#10
   PushConstant         CP#11
+  PushConstant         CP#12
   IndirectStaticCall   1, CP#6
   Drop1
 L2:
   Push                 FP[-5]
   Push                 FP[-6]
-  LoadFieldTOS         CP#0
+  LoadFieldTOS         CP#8
   Push                 FP[-7]
-  PushConstant         CP#12
-  InstanceCall1        4, CP#13
-  InstanceCall1        1, CP#14
+  PushConstant         CP#13
+  InstanceCall1        4, CP#14
+  InstanceCall1        1, CP#15
   ReturnTOS
-  PushConstant         CP#15
+  PushConstant         CP#0
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsFieldOffset #lib::D
+  [0] = Null
   [1] = Type #lib::A<#lib::D::foo3::T1>
   [2] = ArgDesc num-args 4, num-type-args 0, names []
   [3] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
@@ -206,14 +205,14 @@
   [5] = String '31'
   [6] = ArgDesc num-args 1, num-type-args 0, names []
   [7] = StaticICData target 'dart.core::print', arg-desc CP#6
-  [8] = Type #lib::C<dart.core::Map<#lib::D::foo3::T1, #lib::D::P>, dart.core::List<#lib::D::foo3::T2>, #lib::D::Q>
-  [9] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
-  [10] = String '32'
-  [11] = StaticICData target 'dart.core::print', arg-desc CP#6
-  [12] = Type dart.core::Map<#lib::D::foo3::T2, #lib::D::Q>
-  [13] = ICData target-name 'dart.core::_as', arg-desc CP#2
-  [14] = ICData get target-name 'values', arg-desc CP#6
-  [15] = Null
+  [8] = TypeArgumentsFieldOffset #lib::D
+  [9] = Type #lib::C<dart.core::Map<#lib::D::foo3::T1, #lib::D::P>, dart.core::List<#lib::D::foo3::T2>, #lib::D::Q>
+  [10] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
+  [11] = String '32'
+  [12] = StaticICData target 'dart.core::print', arg-desc CP#6
+  [13] = Type dart.core::Map<#lib::D::foo3::T2, #lib::D::Q>
+  [14] = ICData target-name 'dart.core::_as', arg-desc CP#2
+  [15] = ICData get target-name 'values', arg-desc CP#6
 }
 ]  method foo3<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic>(dynamic z) → dynamic {
     if(z is self::A<self::D::foo3::T1>) {