Skip to content

Commit a43c525

Browse files
dcharkescommit-bot@chromium.org
authored andcommitted
Reland "[vm/ffi] Support Windows 64 bit"
Enables dart:ffi on Windows 64 bit. Note that function_stress_test.dart fails in two different ways, these are known bugs. #36138 Relanding: Fixed compilation on Android. Closes: #35771 Change-Id: I7d0c8b64ca8c1726b7d264d4fd9213299a9f7df6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96781 Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Daco Harkes <[email protected]>
1 parent 3bc3205 commit a43c525

11 files changed

+124
-47
lines changed

runtime/bin/ffi_test_functions.cc

+9-5
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44

55
// This file contains test functions for the dart:ffi test cases.
66

7-
// The tests which use this don't run on Windows yet.
8-
#if !defined(_WIN32)
9-
107
#include <stddef.h>
118
#include <stdlib.h>
129
#include <sys/types.h>
10+
11+
#include "platform/globals.h"
12+
#if defined(HOST_OS_WINDOWS)
13+
#include <psapi.h>
14+
#else
1315
#include <unistd.h>
16+
#endif
17+
1418
#include <iostream>
1519
#include <limits>
1620

@@ -406,14 +410,14 @@ DART_EXPORT void* SmallPointer() {
406410
return reinterpret_cast<void*>(-0x80000000L);
407411
}
408412

413+
#if !defined(_WIN32)
409414
DART_EXPORT int RedirectStderr() {
410415
char filename[256];
411416
snprintf(filename, sizeof(filename), "/tmp/captured_stderr_%d", getpid());
412417
freopen(filename, "w", stderr);
413418
printf("Got file %s\n", filename);
414419
return getpid();
415420
}
421+
#endif
416422

417423
} // namespace dart
418-
419-
#endif

runtime/lib/ffi.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,9 @@ static RawCode* TrampolineCode(const Function& function,
500500
#elif !defined(TARGET_ARCH_X64)
501501
// https://github.com/dart-lang/sdk/issues/35774
502502
UNREACHABLE();
503-
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
503+
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS) && \
504+
!defined(TARGET_OS_WINDOWS)
504505
// https://github.com/dart-lang/sdk/issues/35760 Arm32 && Android
505-
// https://github.com/dart-lang/sdk/issues/35771 Windows
506506
// https://github.com/dart-lang/sdk/issues/35772 Arm64
507507
// https://github.com/dart-lang/sdk/issues/35773 DBC
508508
UNREACHABLE();
@@ -588,9 +588,9 @@ static void* GenerateFfiInverseTrampoline(const Function& signature,
588588
#elif !defined(TARGET_ARCH_X64)
589589
// https://github.com/dart-lang/sdk/issues/35774
590590
UNREACHABLE();
591-
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
591+
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS) && \
592+
!defined(TARGET_OS_WINDOWS)
592593
// https://github.com/dart-lang/sdk/issues/35760 Arm32 && Android
593-
// https://github.com/dart-lang/sdk/issues/35771 Windows
594594
// https://github.com/dart-lang/sdk/issues/35772 Arm64
595595
// https://github.com/dart-lang/sdk/issues/35773 DBC
596596
UNREACHABLE();

runtime/lib/ffi_dynamic_library.cc

+75-27
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
6-
// TODO(dacoharkes): implement dynamic libraries for other targets.
7-
// see
8-
// - runtime/vm/native_symbol.h
9-
// - runtime/vm/native_symbol_linux.cc
10-
// - runtime/bin/extensions.h (but we cannot import from bin)
6+
// TODO(dacoharkes): Implement dynamic libraries for other targets & merge the
7+
// implementation with:
8+
// - runtime/bin/extensions.h
119
// - runtime/bin/extensions_linux.cc
10+
// TODO(dacoharkes): Make the code from bin available in a manner similar to
11+
// runtime/vm/dart.h Dart_FileReadCallback.
1212
#else
1313
#include <dlfcn.h>
1414
#endif
@@ -19,29 +19,85 @@
1919

2020
namespace dart {
2121

22-
DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) {
23-
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
24-
UNREACHABLE();
22+
static void* LoadExtensionLibrary(const char* library_file) {
23+
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)
24+
void* handle = dlopen(library_file, RTLD_LAZY);
25+
if (handle == nullptr) {
26+
char* error = dlerror();
27+
const String& msg = String::Handle(
28+
String::NewFormatted("Failed to load dynamic library (%s)", error));
29+
Exceptions::ThrowArgumentError(msg);
30+
}
31+
32+
return handle;
33+
#elif defined(TARGET_OS_WINDOWS)
34+
SetLastError(0); // Clear any errors.
35+
36+
// Convert to wchar_t string.
37+
const int name_len =
38+
MultiByteToWideChar(CP_UTF8, 0, library_file, -1, NULL, 0);
39+
wchar_t* name = new wchar_t[name_len];
40+
MultiByteToWideChar(CP_UTF8, 0, library_file, -1, name, name_len);
41+
42+
void* ext = LoadLibraryW(name);
43+
delete[] name;
44+
45+
if (ext == nullptr) {
46+
const int error = GetLastError();
47+
const String& msg = String::Handle(
48+
String::NewFormatted("Failed to load dynamic library (%i)", error));
49+
Exceptions::ThrowArgumentError(msg);
50+
}
51+
52+
return ext;
2553
#else
54+
const Array& args = Array::Handle(Array::New(1));
55+
args.SetAt(0,
56+
String::Handle(String::New(
57+
"The dart:ffi library is not available on this platform.")));
58+
Exceptions::ThrowByType(Exceptions::kUnsupported, args);
59+
#endif
60+
}
61+
62+
DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) {
2663
GET_NON_NULL_NATIVE_ARGUMENT(String, lib_path, arguments->NativeArgAt(0));
2764

65+
void* handle = LoadExtensionLibrary(lib_path.ToCString());
66+
67+
return DynamicLibrary::New(handle);
68+
}
69+
70+
static void* ResolveSymbol(void* handle, const char* symbol) {
71+
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)
2872
dlerror(); // Clear any errors.
29-
void* handle = dlopen(lib_path.ToCString(), RTLD_LAZY);
30-
if (handle == nullptr) {
73+
void* pointer = dlsym(handle, symbol);
74+
if (pointer == nullptr) {
3175
char* error = dlerror();
3276
const String& msg = String::Handle(
33-
String::NewFormatted("Failed to load dynamic library(%s)", error));
77+
String::NewFormatted("Failed to lookup symbol (%s)", error));
78+
Exceptions::ThrowArgumentError(msg);
79+
}
80+
return pointer;
81+
#elif defined(TARGET_OS_WINDOWS)
82+
SetLastError(0);
83+
void* pointer = GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol);
84+
if (pointer == nullptr) {
85+
const int error = GetLastError();
86+
const String& msg = String::Handle(
87+
String::NewFormatted("Failed to lookup symbol (%i)", error));
3488
Exceptions::ThrowArgumentError(msg);
3589
}
36-
37-
return DynamicLibrary::New(handle);
90+
return pointer;
91+
#else
92+
const Array& args = Array::Handle(Array::New(1));
93+
args.SetAt(0,
94+
String::Handle(String::New(
95+
"The dart:ffi library is not available on this platform.")));
96+
Exceptions::ThrowByType(Exceptions::kUnsupported, args);
3897
#endif
3998
}
4099

41100
DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
42-
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
43-
UNREACHABLE();
44-
#else
45101
GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
46102

47103
GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0));
@@ -50,22 +106,14 @@ DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
50106

51107
void* handle = dlib.GetHandle();
52108

53-
dlerror(); // Clear any errors.
54-
intptr_t pointer =
55-
reinterpret_cast<intptr_t>(dlsym(handle, argSymbolName.ToCString()));
56-
char* error;
57-
if ((error = dlerror()) != NULL) {
58-
const String& msg = String::Handle(
59-
String::NewFormatted("Failed to lookup symbol (%s)", error));
60-
Exceptions::ThrowArgumentError(msg);
61-
}
109+
const intptr_t pointer = reinterpret_cast<intptr_t>(
110+
ResolveSymbol(handle, argSymbolName.ToCString()));
62111

63-
// TODO(dacoharkes): should this return NULL if addres is 0?
112+
// TODO(dacoharkes): should this return Object::null() if address is 0?
64113
// https://github.com/dart-lang/sdk/issues/35756
65114
RawPointer* result =
66115
Pointer::New(type_arg, Integer::Handle(zone, Integer::New(pointer)));
67116
return result;
68-
#endif
69117
}
70118

71119
DEFINE_NATIVE_ENTRY(Ffi_dl_getHandle, 0, 1) {

runtime/vm/dart_api_impl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,9 @@ class Api : AllStatic {
300300
#if !defined(TARGET_ARCH_X64)
301301
// https://github.com/dart-lang/sdk/issues/35774
302302
return false;
303-
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
303+
#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS) && \
304+
!defined(TARGET_OS_WINDOWS)
304305
// https://github.com/dart-lang/sdk/issues/35760 Arm32 && Android
305-
// https://github.com/dart-lang/sdk/issues/35771 Windows
306306
// https://github.com/dart-lang/sdk/issues/35772 Arm64
307307
// https://github.com/dart-lang/sdk/issues/35773 DBC
308308
return false;

samples/ffi/dylib_utils.dart

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ String _platformPath(String name, {String path}) {
99
if (path == null) path = "";
1010
if (Platform.isLinux) return path + "lib" + name + ".so";
1111
if (Platform.isMacOS) return path + "lib" + name + ".dylib";
12+
if (Platform.isWindows) return path + name + ".dll";
1213
throw Exception("Platform not implemented");
1314
}
1415

tests/standalone_2/ffi/dylib_utils.dart

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ String _platformPath(String name, {String path}) {
99
if (path == null) path = "";
1010
if (Platform.isLinux) return path + "lib" + name + ".so";
1111
if (Platform.isMacOS) return path + "lib" + name + ".dylib";
12+
if (Platform.isWindows) return path + name + ".dll";
1213
throw Exception("Platform not implemented");
1314
}
1415

tests/standalone_2/ffi/function_stress_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ test(GCWatcher watcher, void Function() testee,
3232
}
3333

3434
main() async {
35-
final watcher = GCWatcher();
35+
final watcher = GCWatcher.ifAvailable();
3636
try {
3737
await test(watcher, testBoxInt64);
3838
// On 64-bit platforms this won't trigger GC because the result fits into a

tests/standalone_2/ffi/gc_helper.dart

+27-4
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,48 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:io';
6-
import 'dart:convert';
76
import 'dylib_utils.dart';
87
import 'dart:ffi';
8+
import 'dart:io' show Platform;
99

1010
DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
1111

12+
abstract class GCWatcher {
13+
factory GCWatcher() => _GCWatcherImpl();
14+
factory GCWatcher.dummy() => _MockGCWatcher();
15+
factory GCWatcher.ifAvailable() =>
16+
Platform.isWindows ? GCWatcher.dummy() : GCWatcher();
17+
18+
Future<int> size();
19+
void dispose();
20+
}
21+
1222
// Requires --verbose-gc.
13-
class GCWatcher {
23+
class _GCWatcherImpl implements GCWatcher {
1424
int _suffix;
1525

1626
Future<int> size() async {
1727
return await File("/tmp/captured_stderr_$_suffix").length();
1828
}
1929

20-
GCWatcher() {
30+
_GCWatcherImpl() {
2131
print("Starting...");
2232
_suffix = ffiTestFunctions
2333
.lookupFunction<Int32 Function(), int Function()>("RedirectStderr")();
2434
}
2535

26-
dispose() => File("/tmp/captured_stderr_$_suffix").deleteSync();
36+
dispose() {
37+
try {
38+
File("/tmp/captured_stderr_$_suffix").deleteSync();
39+
} catch (e) {
40+
print("deleting file failed");
41+
}
42+
}
43+
}
44+
45+
class _MockGCWatcher implements GCWatcher {
46+
int _ctr = 0;
47+
48+
Future<int> size() async => ++_ctr;
49+
dispose() {}
2750
}

tests/standalone_2/ffi/subtype_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Future<void> testGC() async {
3939
CString cs = ffi.fromAddress<CString>(11);
4040
bar = cs;
4141
foo = "";
42-
final watcher = GCWatcher();
42+
final watcher = GCWatcher.ifAvailable();
4343
int counts = await watcher.size();
4444
for (int i = 0; i < 1000000; ++i) {
4545
foo = new X(i);

tests/standalone_2/standalone_2_kernel.status

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,8 @@ io/socket_many_connections_test: Skip # Timeout
229229
io/web_socket_compression_test: Skip # Timeout
230230
io/web_socket_test: Skip # Timeout
231231

232-
[ $arch != x64 || $compiler != dartk || $mode == product || $system != linux && $system != macos]
233-
ffi/function_stress_test: SkipByDesign # FFI must be supported. Also requires --verbose-gc, which isn't included in product.
232+
[ $arch != x64 || $compiler != dartk || $mode == product || $system != linux && $system != macos ]
233+
ffi/function_stress_test: SkipByDesign # FFI must be supported. Also requires --verbose-gc, which isn't included in product. Windows issues will be fixed in IL CL: https://github.com/dart-lang/sdk/issues/36138
234234
ffi/subtype_test: SkipByDesign # FFI must be supported. Also requires --verbose-gc, which isn't included in product.
235235

236236
[ $mode == product || $mode != product ]

tests/standalone_2/standalone_2_vm.status

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,5 +133,5 @@ full_coverage_test: Skip # TODO(vegorov) SIMDBC interpreter doesn't support cove
133133
link_natives_lazily_test: SkipByDesign # SIMDBC interpreter doesn't support lazy linking of natives.
134134
no_lazy_dispatchers_test: SkipByDesign # SIMDBC interpreter doesn't support --no_lazy_dispatchers
135135

136-
[ $arch != x64 || $system != linux && $system != macos ]
136+
[ $arch != x64 || $system != linux && $system != macos && $system != windows ]
137137
ffi: Skip # ffi not yet supported on other systems than linux/macos 64

0 commit comments

Comments
 (0)