[vm/kernel/bytecode] Bytecode generation for rarely used operations

Change-Id: Ie5154207b4763d950707b267803a688d4b3e0487
Reviewed-on: https://dart-review.googlesource.com/62002
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/bin/frontend_server_starter.dart b/pkg/vm/bin/frontend_server_starter.dart
index 5ae6bfd..dcbf63f 100644
--- a/pkg/vm/bin/frontend_server_starter.dart
+++ b/pkg/vm/bin/frontend_server_starter.dart
@@ -1,7 +1,6 @@
 library frontend_server;
 
 import 'dart:async';
-import 'dart:io';
 
 import '../lib/frontend_server.dart';
 
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 599d4c1..986874d 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -169,9 +169,7 @@
     asm.emitNativeCall(nativeEntryCpIndex);
   }
 
-  LibraryIndex _libraryIndex;
-  LibraryIndex get libraryIndex =>
-      _libraryIndex ??= new LibraryIndex.coreLibraries(component);
+  LibraryIndex get libraryIndex => coreTypes.index;
 
   Procedure _listFromLiteral;
   Procedure get listFromLiteral => _listFromLiteral ??=
@@ -211,6 +209,11 @@
       _closureFunctionTypeArguments ??= libraryIndex.getMember(
           'dart:core', '_Closure', '_function_type_arguments');
 
+  Field _closureDelayedTypeArguments;
+  Field get closureDelayedTypeArguments =>
+      _closureDelayedTypeArguments ??= libraryIndex.getMember(
+          'dart:core', '_Closure', '_delayed_type_arguments');
+
   Field _closureFunction;
   Field get closureFunction => _closureFunction ??=
       libraryIndex.getMember('dart:core', '_Closure', '_function');
@@ -223,6 +226,10 @@
   Procedure get prependTypeArguments => _prependTypeArguments ??=
       libraryIndex.getTopLevelMember('dart:_internal', '_prependTypeArguments');
 
+  Procedure _futureValue;
+  Procedure get futureValue =>
+      _futureValue ??= libraryIndex.getMember('dart:async', 'Future', 'value');
+
   void _genConstructorInitializers(Constructor node) {
     bool isRedirecting =
         node.initializers.any((init) => init is RedirectingInitializer);
@@ -1109,9 +1116,18 @@
     asm.emitDrop1();
   }
 
-//  @override
-//  visitDirectMethodInvocation(DirectMethodInvocation node) {
-//  }
+  @override
+  visitDirectMethodInvocation(DirectMethodInvocation node) {
+    final args = node.arguments;
+    _genArguments(node.receiver, args);
+    final target = node.target;
+    if (target is Procedure && !target.isGetter && !target.isSetter) {
+      _genStaticCallWithArgs(target, args, hasReceiver: true);
+    } else {
+      throw new UnsupportedOperationError(
+          'Unsupported DirectMethodInvocation with target ${target.runtimeType} $target');
+    }
+  }
 
   @override
   visitDirectPropertyGet(DirectPropertyGet node) {
@@ -1125,22 +1141,58 @@
     }
   }
 
-//  @override
-//  visitDirectPropertySet(DirectPropertySet node) {
-//  }
+  @override
+  visitDirectPropertySet(DirectPropertySet node) {
+    node.receiver.accept(this);
+    node.value.accept(this);
+    final target = node.target;
+    if (target is Field || (target is Procedure && target.isSetter)) {
+      _genStaticCall(target, new ConstantArgDesc(2), 2, isSet: true);
+    } else {
+      throw new UnsupportedOperationError(
+          'Unsupported DirectPropertySet with target ${target.runtimeType} $target');
+    }
+  }
 
   @override
   visitFunctionExpression(FunctionExpression node) {
     _genClosure(node, '<anonymous closure>', node.function);
   }
 
-//  @override
-//  visitInstantiation(Instantiation node) {
-//  }
-//
-//  @override
-//  visitInvalidExpression(InvalidExpression node) {
-//  }
+  @override
+  visitInstantiation(Instantiation node) {
+    final int oldClosure = locals.tempIndexInFrame(node, tempIndex: 0);
+    final int newClosure = locals.tempIndexInFrame(node, tempIndex: 1);
+
+    node.expression.accept(this);
+    asm.emitPopLocal(oldClosure);
+
+    assert(closureClass.typeParameters.isEmpty);
+    asm.emitAllocate(cp.add(new ConstantClass(closureClass)));
+    asm.emitStoreLocal(newClosure);
+
+    _genTypeArguments(node.typeArguments);
+    asm.emitStoreFieldTOS(
+        cp.add(new ConstantFieldOffset(closureDelayedTypeArguments)));
+
+    // Copy the rest of the fields from old closure to a new closure.
+    final fieldsToCopy = <Field>[
+      closureInstantiatorTypeArguments,
+      closureFunctionTypeArguments,
+      closureFunction,
+      closureContext,
+    ];
+
+    for (Field field in fieldsToCopy) {
+      final fieldOffsetCpIndex = cp.add(new ConstantFieldOffset(field));
+      asm.emitPush(newClosure);
+      asm.emitPush(oldClosure);
+      asm.emitLoadFieldTOS(fieldOffsetCpIndex);
+      asm.emitStoreFieldTOS(fieldOffsetCpIndex);
+    }
+
+    asm.emitPush(newClosure);
+  }
 
   @override
   visitIsExpression(IsExpression node) {
@@ -1322,7 +1374,7 @@
   @override
   visitSuperPropertyGet(SuperPropertyGet node) {
     _genPushReceiver();
-    Member target =
+    final Member target =
         hierarchy.getDispatchTarget(enclosingClass.superclass, node.name);
     if (target == null) {
       throw new UnsupportedOperationError(
@@ -1336,9 +1388,23 @@
     }
   }
 
-//  @override
-//  visitSuperPropertySet(SuperPropertySet node) {
-//  }
+  @override
+  visitSuperPropertySet(SuperPropertySet node) {
+    _genPushReceiver();
+    node.value.accept(this);
+    final Member target = hierarchy
+        .getDispatchTarget(enclosingClass.superclass, node.name, setter: true);
+    if (target == null) {
+      throw new UnsupportedOperationError(
+          'Unsupported SuperPropertySet without target');
+    }
+    if (target is Field || (target is Procedure && target.isSetter)) {
+      _genStaticCall(target, new ConstantArgDesc(2), 2, isSet: true);
+    } else {
+      throw new UnsupportedOperationError(
+          'Unsupported SuperPropertySet with target ${target.runtimeType} $target');
+    }
+  }
 
   @override
   visitNot(Not node) {
@@ -1528,33 +1594,20 @@
     }
   }
 
-//  @override
-//  visitLoadLibrary(LoadLibrary node) {
-//  }
-//
-//  @override
-//  visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
-//  }
-//
-//  @override
-//  visitVectorCreation(VectorCreation node) {
-//  }
-//
-//  @override
-//  visitVectorGet(VectorGet node) {
-//  }
-//
-//  @override
-//  visitVectorSet(VectorSet node) {
-//  }
-//
-//  @override
-//  visitVectorCopy(VectorCopy node) {
-//  }
-//
-//  @override
-//  visitClosureCreation(ClosureCreation node) {
-//  }
+  void _genFutureNull() {
+    _genPushNull();
+    _genStaticCall(futureValue, new ConstantArgDesc(1), 1);
+  }
+
+  @override
+  visitLoadLibrary(LoadLibrary node) {
+    _genFutureNull();
+  }
+
+  @override
+  visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
+    _genFutureNull();
+  }
 
   @override
   visitAssertStatement(AssertStatement node) {
@@ -2163,16 +2216,15 @@
     asm.emitDrop1();
   }
 
-//  @override
-//  visitLocalInitializer(LocalInitializer node) {
-//  }
-//
-//  @override
-//  visitAssertInitializer(AssertInitializer node) {
-//  }
-//
-//  @override
-//  visitInvalidInitializer(InvalidInitializer node) {}
+  @override
+  visitLocalInitializer(LocalInitializer node) {
+    node.variable.accept(this);
+  }
+
+  @override
+  visitAssertInitializer(AssertInitializer node) {
+    node.statement.accept(this);
+  }
 
   @override
   visitConstantExpression(ConstantExpression node) {
@@ -2226,8 +2278,9 @@
   int visitTearOffConstant(TearOffConstant node) =>
       cp.add(new ConstantTearOff(node.procedure));
 
-//  @override
-//  int visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
+  @override
+  int visitTypeLiteralConstant(TypeLiteralConstant node) =>
+      cp.add(new ConstantType(node.type));
 }
 
 class UnsupportedOperationError {
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 5bea5f6..1c4edcd 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -994,4 +994,9 @@
   visitTryFinally(TryFinally node) {
     _visit(node, temps: 2);
   }
+
+  @override
+  visitInstantiation(Instantiation node) {
+    _visit(node, temps: 2);
+  }
 }
diff --git a/pkg/vm/testcases/bytecode/closures.dart b/pkg/vm/testcases/bytecode/closures.dart
index 102cb0f..ff1c650 100644
--- a/pkg/vm/testcases/bytecode/closures.dart
+++ b/pkg/vm/testcases/bytecode/closures.dart
@@ -131,4 +131,12 @@
   }
 }
 
+typedef IntFunc(int arg);
+
+IntFunc testPartialInstantiation() {
+  void foo<T>(T t) {}
+  IntFunc intFunc = foo;
+  return intFunc;
+}
+
 main() {}
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 2080a18..2bece87 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
+typedef IntFunc = (core::int) → dynamic;
 class C1 extends core::Object {
 [@vm.bytecode=
 Bytecode {
@@ -1409,6 +1410,103 @@
 }
 [@vm.bytecode=
 Bytecode {
+  Entry                6
+  CheckStack
+  Allocate             CP#12
+  StoreLocal           r3
+  Push                 r3
+  PushConstant         CP#7
+  StoreFieldTOS        CP#13
+  Push                 r3
+  PushConstant         CP#7
+  StoreFieldTOS        CP#2
+  Push                 r3
+  PushConstant         CP#0
+  StoreFieldTOS        CP#14
+  Push                 r3
+  Push                 r0
+  StoreFieldTOS        CP#1
+  PopLocal             r2
+  Push                 r2
+  PopLocal             r3
+  Allocate             CP#12
+  StoreLocal           r5
+  PushConstant         CP#15
+  StoreFieldTOS        CP#16
+  Push                 r5
+  Push                 r3
+  LoadFieldTOS         CP#13
+  StoreFieldTOS        CP#13
+  Push                 r5
+  Push                 r3
+  LoadFieldTOS         CP#2
+  StoreFieldTOS        CP#2
+  Push                 r5
+  Push                 r3
+  LoadFieldTOS         CP#14
+  StoreFieldTOS        CP#14
+  Push                 r5
+  Push                 r3
+  LoadFieldTOS         CP#1
+  StoreFieldTOS        CP#1
+  Push                 r5
+  PopLocal             r4
+  Push                 r4
+  ReturnTOS
+  PushConstant         CP#7
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ClosureFunction foo <T extends dart.core::Object = dynamic>(T t) → void;
+  [1] = FieldOffset dart.core::_Closure::_context
+  [2] = FieldOffset dart.core::_Closure::_function_type_arguments
+  [3] = Int 0
+  [4] = Int 1
+  [5] = ArgDesc num-args 4, num-type-args 0, names []
+  [6] = StaticICData target 'dart._internal::_prependTypeArguments', arg-desc CP#5
+  [7] = Null
+  [8] = Type T
+  [9] = String 't'
+  [10] = SubtypeTestCache
+  [11] = EndClosureFunctionScope
+  [12] = Class dart.core::_Closure
+  [13] = FieldOffset dart.core::_Closure::_instantiator_type_arguments
+  [14] = FieldOffset dart.core::_Closure::_function
+  [15] = TypeArgs [dart.core::int]
+  [16] = FieldOffset dart.core::_Closure::_delayed_type_arguments
+}
+Closure CP#0 {
+  Entry                2
+  CheckStack
+  Push                 FP[-6]
+  LoadFieldTOS         CP#1
+  PopLocal             r0
+  Push                 FP[-7]
+  Push                 FP[-6]
+  LoadFieldTOS         CP#2
+  PushConstant         CP#3
+  PushConstant         CP#4
+  PushConstant         CP#6
+  IndirectStaticCall   4, CP#5
+  PopLocal             FP[-7]
+  Push                 FP[-5]
+  PushConstant         CP#7
+  Push                 FP[-7]
+  PushConstant         CP#8
+  PushConstant         CP#9
+  AssertAssignable     0, CP#10
+  Drop1
+  PushConstant         CP#7
+  ReturnTOS
+
+}
+]static method testPartialInstantiation() → (core::int) → dynamic {
+  function foo<T extends core::Object = dynamic>(T t) → void {}
+  (core::int) → dynamic intFunc = foo<core::int>;
+  return intFunc;
+}
+[@vm.bytecode=
+Bytecode {
   Entry                0
   CheckStack
   PushConstant         CP#0
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart b/pkg/vm/testcases/bytecode/deferred_lib.dart
new file mode 100644
index 0000000..b93cc06
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "hello.dart" deferred as lib;
+
+callDeferred() => lib.main();
+
+testLoadLibrary() => lib.loadLibrary();
+
+main() {}
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
new file mode 100644
index 0000000..8d4cb94
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
@@ -0,0 +1,56 @@
+library #lib;
+import self as self;
+import "./hello.dart" as hel;
+
+[@vm.bytecode=
+Bytecode {
+  Entry                1
+  CheckStack
+  PushConstant         CP#0
+  PushConstant         CP#2
+  IndirectStaticCall   1, CP#1
+  PopLocal             r0
+  PushConstant         CP#4
+  IndirectStaticCall   0, CP#3
+  ReturnTOS
+  PushConstant         CP#0
+  ReturnTOS
+}
+ConstantPool {
+  [0] = Null
+  [1] = ArgDesc num-args 1, num-type-args 0, names []
+  [2] = StaticICData target 'dart.async::Future::value', arg-desc CP#1
+  [3] = ArgDesc num-args 0, num-type-args 0, names []
+  [4] = StaticICData target '#lib1::main', arg-desc CP#3
+}
+]static method callDeferred() → dynamic
+  return let final dynamic #t1 = CheckLibraryIsLoaded(lib) in hel::main();
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  PushConstant         CP#0
+  PushConstant         CP#2
+  IndirectStaticCall   1, CP#1
+  ReturnTOS
+  PushConstant         CP#0
+  ReturnTOS
+}
+ConstantPool {
+  [0] = Null
+  [1] = ArgDesc num-args 1, num-type-args 0, names []
+  [2] = StaticICData target 'dart.async::Future::value', arg-desc CP#1
+}
+]static method testLoadLibrary() → dynamic
+  return LoadLibrary(lib);
+[@vm.bytecode=
+Bytecode {
+  Entry                0
+  CheckStack
+  PushConstant         CP#0
+  ReturnTOS
+}
+ConstantPool {
+  [0] = Null
+}
+]static method main() → dynamic {}
diff --git a/pkg/vm/testcases/bytecode/literals.dart b/pkg/vm/testcases/bytecode/literals.dart
index 69a0e85..0acd65b 100644
--- a/pkg/vm/testcases/bytecode/literals.dart
+++ b/pkg/vm/testcases/bytecode/literals.dart
@@ -45,7 +45,7 @@
   print(42);
   print('foo');
   print(A.elem2);
-  print(const [42, 'foo']);
+  print(const [42, 'foo', int]);
   print(const <String, A>{'E2': A.elem2, 'E4': A.elem4});
   print(
       const D(const C(4, 5, 6), const {'foo': 42, 'bar': const B(c2.length)}));
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index a3c9ec2..7d6702f 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -360,19 +360,19 @@
   PushConstant         CP#9
   IndirectStaticCall   1, CP#1
   Drop1
-  PushConstant         CP#10
   PushConstant         CP#11
+  PushConstant         CP#12
   IndirectStaticCall   1, CP#1
   Drop1
-  PushConstant         CP#19
   PushConstant         CP#20
+  PushConstant         CP#21
   IndirectStaticCall   1, CP#1
   Drop1
-  PushConstant         CP#30
   PushConstant         CP#31
+  PushConstant         CP#32
   IndirectStaticCall   1, CP#1
   Drop1
-  PushConstant         CP#32
+  PushConstant         CP#33
   ReturnTOS
 }
 ConstantPool {
@@ -386,35 +386,36 @@
   [7] = String 'A.elem2'
   [8] = Instance #lib::A type-args CP#5 {index: 6, _name: 7}
   [9] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [10] = List type-arg dart.core::Object, entries CP# [0, 3]
-  [11] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [12] = TypeArgs [dart.core::String, #lib::A]
-  [13] = String 'E2'
-  [14] = String 'E4'
-  [15] = Int 3
-  [16] = String 'A.elem4'
-  [17] = Instance #lib::A type-args CP#5 {index: 15, _name: 16}
-  [18] = List type-arg dynamic, entries CP# [13, 8, 14, 17]
-  [19] = Instance dart.core::_ImmutableMap type-args CP#12 {_kvPairs: 18}
-  [20] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [21] = Int 9
-  [22] = Int 30
-  [23] = Instance #lib::C type-args CP#5 {j: 21, i: 22}
-  [24] = TypeArgs [dart.core::String, dart.core::Object]
-  [25] = String 'bar'
-  [26] = Int 6
-  [27] = Instance #lib::B type-args CP#5 {i: 26}
-  [28] = List type-arg dynamic, entries CP# [3, 0, 25, 27]
-  [29] = Instance dart.core::_ImmutableMap type-args CP#24 {_kvPairs: 28}
-  [30] = Instance #lib::D type-args CP#5 {x: 23, y: 29}
-  [31] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [32] = Null
+  [10] = Type dart.core::int
+  [11] = List type-arg dart.core::Object, entries CP# [0, 3, 10]
+  [12] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [13] = TypeArgs [dart.core::String, #lib::A]
+  [14] = String 'E2'
+  [15] = String 'E4'
+  [16] = Int 3
+  [17] = String 'A.elem4'
+  [18] = Instance #lib::A type-args CP#5 {index: 16, _name: 17}
+  [19] = List type-arg dynamic, entries CP# [14, 8, 15, 18]
+  [20] = Instance dart.core::_ImmutableMap type-args CP#13 {_kvPairs: 19}
+  [21] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [22] = Int 9
+  [23] = Int 30
+  [24] = Instance #lib::C type-args CP#5 {j: 22, i: 23}
+  [25] = TypeArgs [dart.core::String, dart.core::Object]
+  [26] = String 'bar'
+  [27] = Int 6
+  [28] = Instance #lib::B type-args CP#5 {i: 27}
+  [29] = List type-arg dynamic, entries CP# [3, 0, 26, 28]
+  [30] = Instance dart.core::_ImmutableMap type-args CP#25 {_kvPairs: 29}
+  [31] = Instance #lib::D type-args CP#5 {x: 24, y: 30}
+  [32] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [33] = Null
 }
 ]static method test_constants2() → void {
   core::print(42);
   core::print("foo");
   core::print(self::A::elem2);
-  core::print(const <core::Object>[42, "foo"]);
+  core::print(const <core::Object>[42, "foo", core::int]);
   core::print(const <core::String, self::A>{"E2": self::A::elem2, "E4": self::A::elem4});
   core::print(const self::D::•(const self::C::•(4, 5, 6), const <core::String, core::Object>{"foo": 42, "bar": const self::B::•(self::c2.{core::String::length})}));
 }