Files
sdk/tests/ffi/generator/utils.dart
T
Daco Harkes 40094c8cfd [vm/ffi] Unwrap typed data in FFI calls
Enables passing inner pointers to typed data in FFI leaf calls.

This works for typed data's in the Dart heap, external typed datas
(constructed from `Pointer.asTypedList`), and typed data views.

Notable implementation details:
1. The Dart signature is used in the Marshaller now. This means it
   needs to keep track of whether there's a pointer argument in the
   signature (`asFunction`) or not (`@Native`).
2. Unwrapping is done in `FfiCallInstr::EmitNativeCode` before moving
   the arguments to their native location. This ensures we can use
   the assembler logic to load the `TypedDataBase::data` field.
3. The `XXXList` user visible classes don't have predefined cids.
   So the implementation uses symbols for comparison.
4. The type checking logic takes `isLeaf` as input to reject typed
   data. This leads to an error message about the type not accepted.
   Alternatively, we could consider adding an error message that
   specifically says the function should be leaf.
5. To cover all calling convention variants, tests are generated with
   up to 20 arguments.

TEST=pkg/analyzer/test/src/diagnostics/ffi_unwrap_typed_data_test.dart
TEST=tests/ffi/unwrap_typeddata_generated_native_test.dart
TEST=tests/ffi/unwrap_typeddata_generated_test.dart
TEST=tests/ffi/vmspecific_static_checks_typeddata_test.dart

Closes: https://github.com/dart-lang/sdk/issues/44589
Change-Id: Ia78f18bf3238d42ac6882929b441f6dc432fcefe
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/338620
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2023-12-12 00:05:02 +00:00

108 lines
3.2 KiB
Dart

// Copyright (c) 2020, 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 'dart:io';
extension TestGeneratorStringExtension on String {
String upperCaseFirst() => "${this[0].toUpperCase()}${this.substring(1)}";
String lowerCaseFirst() => "${this[0].toLowerCase()}${this.substring(1)}";
String makeCComment() => "// " + split("\n").join("\n// ");
String makeDartDocComment() => "/// " + split("\n").join("\n/// ");
String limitTo(int length) {
if (this.length > length) {
return substring(0, length);
}
return this;
}
String trimCouts() => replaceAll('" << "', '').replaceAll('"<< "', '');
}
Future<void> runProcess(String executable, List<String> arguments) async {
final commandString = [executable, ...arguments].join(' ');
stdout.writeln('Running `$commandString`.');
final process = await Process.start(
executable,
arguments,
runInShell: true,
includeParentEnvironment: true,
).then((process) {
process.stdout.forEach(stdout.add);
process.stderr.forEach(stderr.add);
return process;
});
final exitCode = await process.exitCode;
if (exitCode != 0) {
final message = 'Command `$commandString` failed with exit code $exitCode.';
stderr.writeln(message);
throw Exception(message);
}
stdout.writeln('Command `$commandString` done.');
}
String headerCommon({
required int copyrightYear,
required String generatorPath,
}) {
final year = copyrightYear;
return """
// Copyright (c) $year, 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.
//
// This file has been automatically generated. Please do not edit it manually.
// Generated by $generatorPath.""";
}
String headerC({
required int copyrightYear,
required String generatorPath,
}) {
return """
${headerCommon(copyrightYear: copyrightYear, generatorPath: generatorPath)}
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <cmath>
#include <iostream>
#include <limits>
#if defined(_WIN32)
#define DART_EXPORT extern "C" __declspec(dllexport)
#else
#define DART_EXPORT \\
extern "C" __attribute__((visibility("default"))) __attribute((used))
#endif
namespace dart {
#define CHECK(X) \\
if (!(X)) { \\
fprintf(stderr, "%s\\n", "Check failed: " #X); \\
return 1; \\
}
#define CHECK_EQ(X, Y) CHECK((X) == (Y))
// Works for positive, negative and zero.
#define CHECK_APPROX(EXPECTED, ACTUAL) \\
CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) || \\
((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
""";
}
const footerC = """
} // namespace dart
""";