[vm/bytecode] Add eager bounds checks to partial instantiations in bytecode

This is the follow-up to
https://github.com/dart-lang/sdk/commit/dbe868de02d3b8e156c963d39f26fd95b6683e9b

Similarly to StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation,
bytecode generator adds _boundsCheckForPartialInstantiation calls
to partial instantiations of tear-offs.

Fixes language_2/partial_instantiation_eager_bounds_check_test in bytecode mode.

Change-Id: I2daf1902aa3df99133b2a25f1413e1bac53b6c30
Reviewed-on: https://dart-review.googlesource.com/72549
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 62fa462..1b228dd 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -239,6 +239,11 @@
   Procedure get prependTypeArguments => _prependTypeArguments ??=
       libraryIndex.getTopLevelMember('dart:_internal', '_prependTypeArguments');
 
+  Procedure _boundsCheckForPartialInstantiation;
+  Procedure get boundsCheckForPartialInstantiation =>
+      _boundsCheckForPartialInstantiation ??= libraryIndex.getTopLevelMember(
+          'dart:_internal', '_boundsCheckForPartialInstantiation');
+
   Procedure _futureValue;
   Procedure get futureValue =>
       _futureValue ??= libraryIndex.getMember('dart:async', 'Future', 'value');
@@ -1409,15 +1414,23 @@
   visitInstantiation(Instantiation node) {
     final int oldClosure = locals.tempIndexInFrame(node, tempIndex: 0);
     final int newClosure = locals.tempIndexInFrame(node, tempIndex: 1);
+    final int typeArguments = locals.tempIndexInFrame(node, tempIndex: 2);
 
     node.expression.accept(this);
-    asm.emitPopLocal(oldClosure);
+    asm.emitStoreLocal(oldClosure);
+
+    _genTypeArguments(node.typeArguments);
+    asm.emitStoreLocal(typeArguments);
+
+    _genStaticCall(
+        boundsCheckForPartialInstantiation, new ConstantArgDesc(2), 2);
+    asm.emitDrop1();
 
     assert(closureClass.typeParameters.isEmpty);
     asm.emitAllocate(cp.add(new ConstantClass(closureClass)));
     asm.emitStoreLocal(newClosure);
 
-    _genTypeArguments(node.typeArguments);
+    asm.emitPush(typeArguments);
     asm.emitStoreFieldTOS(
         cp.add(new ConstantInstanceField(closureDelayedTypeArguments)));
 
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 45d8351..a92c969 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -1136,6 +1136,6 @@
 
   @override
   visitInstantiation(Instantiation node) {
-    _visit(node, temps: 2);
+    _visit(node, temps: 3);
   }
 }
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index f125b99..eb11001 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -1493,7 +1493,7 @@
 }
 [@vm.bytecode=
 Bytecode {
-  Entry                6
+  Entry                7
   CheckStack
   Allocate             CP#17
   StoreLocal           r3
@@ -1514,10 +1514,15 @@
   StoreFieldTOS        CP#1
   PopLocal             r2
   Push                 r2
-  PopLocal             r3
+  StoreLocal           r3
+  PushConstant         CP#22
+  StoreLocal           r6
+  PushConstant         CP#24
+  IndirectStaticCall   2, CP#23
+  Drop1
   Allocate             CP#17
   StoreLocal           r5
-  PushConstant         CP#22
+  Push                 r6
   StoreFieldTOS        CP#3
   Push                 r5
   Push                 r3
@@ -1566,6 +1571,8 @@
   [20] = InstanceField dart.core::_Closure::_function
   [21] = Reserved
   [22] = TypeArgs [dart.core::int]
+  [23] = ArgDesc num-args 2, num-type-args 0, names []
+  [24] = StaticICData target 'dart._internal::_boundsCheckForPartialInstantiation', arg-desc CP#23
 }
 Closure CP#0 {
   EntryFixed           2, 3