[vm/ffi] void functions

Change-Id: I1544e0985d934dfa354143764dee61feb08b2592
Reviewed-on: https://dart-review.googlesource.com/c/93422
Auto-Submit: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 4b93041..ba4e06d 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -138,6 +138,7 @@
   /// [IntPtr]                             -> [int]
   /// [Double]                             -> [double]
   /// [Float]                              -> [double]
+  /// [Void]                               -> [void]
   /// [Pointer]<T>                         -> [Pointer]<T>
   /// T extends [Pointer]                  -> T
   /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
@@ -162,6 +163,9 @@
     if (nativeType_ == NativeType.kFloat || nativeType_ == NativeType.kDouble) {
       return InterfaceType(doubleClass);
     }
+    if (nativeType_ == NativeType.kVoid) {
+      return VoidType();
+    }
     if (nativeType_ == NativeType.kNativeFunction) {
       DartType fun = (nativeType as InterfaceType).typeArguments[0];
       if (fun is FunctionType) {
diff --git a/runtime/bin/ffi_test_functions.cc b/runtime/bin/ffi_test_functions.cc
index 0248829..d21ba52 100644
--- a/runtime/bin/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test_functions.cc
@@ -365,4 +365,20 @@
   return retval;
 }
 
+// Does nothing with input.
+// Used for testing functions that return void
+DART_EXPORT void DevNullFloat(float a) {
+  std::cout << "DevNullFloat(" << a << ")\n";
+  std::cout << "returning nothing\n";
+}
+
+// Invents an elite floating point number.
+// Used for testing functions that do not take any arguments.
+DART_EXPORT float InventFloatValue() {
+  std::cout << "InventFloatValue()\n";
+  float retval = 1337.0f;
+  std::cout << "returning " << retval << "\n";
+  return retval;
+}
+
 }  // namespace dart
diff --git a/runtime/vm/ffi_trampoline_stubs_x64.cc b/runtime/vm/ffi_trampoline_stubs_x64.cc
index 9374f61..001c68d 100644
--- a/runtime/vm/ffi_trampoline_stubs_x64.cc
+++ b/runtime/vm/ffi_trampoline_stubs_x64.cc
@@ -4,6 +4,7 @@
 
 // TODO(dacoharkes): Move this into compiler namespace.
 
+#include "vm/class_id.h"
 #include "vm/globals.h"
 
 #include "vm/stub_code.h"
@@ -391,6 +392,9 @@
                                     const AbstractType& result_type,
                                     Address closure_dart) {
   switch (result_type.type_class_id()) {
+    case kFfiVoidCid:
+      __ LoadObject(RAX, Object::null_object());
+      return;
     case kFfiInt8Cid:
     case kFfiInt16Cid:
     case kFfiInt32Cid:
diff --git a/tests/standalone_2/ffi/function_test.dart b/tests/standalone_2/ffi/function_test.dart
index dacce5d..c2019f7 100644
--- a/tests/standalone_2/ffi/function_test.dart
+++ b/tests/standalone_2/ffi/function_test.dart
@@ -28,6 +28,8 @@
   testNullManyArgs();
   testNullPointers();
   testFloatRounding();
+  testVoidReturn();
+  testNoArgs();
 }
 
 ffi.DynamicLibrary ffiTestFunctions =
@@ -284,3 +286,28 @@
 
   p2.free();
 }
+
+typedef NativeFloatToVoid = ffi.Void Function(ffi.Float);
+typedef DoubleToVoid = void Function(double);
+
+void testVoidReturn() {
+  DoubleToVoid devNullFloat = ffiTestFunctions
+      .lookupFunction<NativeFloatToVoid, DoubleToVoid>("DevNullFloat");
+
+  devNullFloat(1337.0);
+
+  dynamic loseSignature = devNullFloat;
+  dynamic result = loseSignature(1337.0);
+  Expect.isNull(result);
+}
+
+typedef NativeVoidToFloat = ffi.Float Function();
+typedef VoidToDouble = double Function();
+
+void testNoArgs() {
+  VoidToDouble inventFloatValue = ffiTestFunctions
+      .lookupFunction<NativeVoidToFloat, VoidToDouble>("InventFloatValue");
+
+  double result = inventFloatValue();
+  Expect.approxEquals(1337.0, result);
+}