mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:43:57 +00:00
df4ef72c01
TEST=pkg/analyzer/test/ TEST=CI build with class removed from `dart:ffi` Closes: https://github.com/dart-lang/sdk/issues/53923 CoreLibraryReviewExempt: VM & dart2wasm only. Change-Id: I45a39b623754f9f1b65cac55ea9adae390199f5d Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm64c-try,analyzer-analysis-server-linux-try,analyzer-mac-release-try,dart-sdk-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336960 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
174 lines
6.3 KiB
Dart
174 lines
6.3 KiB
Dart
// Copyright (c) 2021, 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.
|
|
//
|
|
// SharedObjects=ffi_test_functions
|
|
|
|
import 'dart:ffi';
|
|
import 'dart:nativewrappers';
|
|
|
|
import 'package:expect/expect.dart';
|
|
|
|
import 'dylib_utils.dart';
|
|
|
|
final nativeLib = dlopenPlatformSpecific('ffi_test_functions');
|
|
|
|
final getRootLibraryUrl = nativeLib
|
|
.lookupFunction<Handle Function(), Object Function()>('GetRootLibraryUrl');
|
|
|
|
final setFfiNativeResolverForTest =
|
|
nativeLib.lookupFunction<Void Function(Handle), void Function(Object)>(
|
|
'SetFfiNativeResolverForTest');
|
|
|
|
@Native<Handle Function(Handle, IntPtr, IntPtr)>(
|
|
symbol: 'Dart_SetNativeInstanceField')
|
|
external Object setNativeInstanceField(Object obj, int index, int ptr);
|
|
|
|
// Basic Native test functions.
|
|
|
|
@Native<IntPtr Function(IntPtr)>(symbol: 'ReturnIntPtr')
|
|
external int returnIntPtr(int x);
|
|
|
|
@Native<IntPtr Function(IntPtr)>(symbol: 'ReturnIntPtr', isLeaf: true)
|
|
external int returnIntPtrLeaf(int x);
|
|
|
|
@Native<IntPtr Function()>(symbol: 'IsThreadInGenerated')
|
|
external int isThreadInGenerated();
|
|
|
|
@Native<IntPtr Function()>(symbol: 'IsThreadInGenerated', isLeaf: true)
|
|
external int isThreadInGeneratedLeaf();
|
|
|
|
class Classy {
|
|
@Native<IntPtr Function(IntPtr)>(symbol: 'ReturnIntPtr')
|
|
external static int returnIntPtrStatic(int x);
|
|
}
|
|
|
|
// For automatic transform of NativeFieldWrapperClass1 to Pointer.
|
|
|
|
base class ClassWithNativeField extends NativeFieldWrapperClass1 {
|
|
ClassWithNativeField(int value) {
|
|
setNativeInstanceField(this, 0, value);
|
|
}
|
|
|
|
// Instance methods implicitly pass a 'self' reference as the first argument.
|
|
// Passed as Pointer if the native function takes that (and the class can be
|
|
// converted).
|
|
@Native<IntPtr Function(Pointer<Void>, IntPtr)>(symbol: 'AddPtrAndInt')
|
|
external int addSelfPtrAndIntMethod(int x);
|
|
|
|
// Instance methods implicitly pass a 'self' reference as the first argument.
|
|
// Passed as Handle if the native function takes that.
|
|
@Native<IntPtr Function(Handle, IntPtr)>(symbol: 'AddHandleFieldAndInt')
|
|
external int addSelfHandleFieldAndIntMethod(int x);
|
|
|
|
@Native<IntPtr Function(Pointer<Void>, Pointer<Void>)>(symbol: 'AddPtrAndPtr')
|
|
external int addSelfPtrAndPtrMethod(ClassWithNativeField other);
|
|
|
|
@Native<IntPtr Function(Handle, Pointer<Void>)>(
|
|
symbol: 'AddHandleFieldAndPtr')
|
|
external int addSelfHandleFieldAndPtrMethod(ClassWithNativeField other);
|
|
|
|
@Native<IntPtr Function(Handle, Handle)>(
|
|
symbol: 'AddHandleFieldAndHandleField')
|
|
external int addSelfHandleFieldAndHandleFieldMethod(
|
|
ClassWithNativeField other);
|
|
|
|
@Native<IntPtr Function(Pointer<Void>, Handle)>(
|
|
symbol: 'AddPtrAndHandleField')
|
|
external int addselfPtrAndHandleFieldMethod(ClassWithNativeField other);
|
|
}
|
|
|
|
class ClassWithoutNativeField {
|
|
// Instance methods implicitly pass their handle as the first arg.
|
|
@Native<IntPtr Function(Handle, IntPtr)>(symbol: 'ReturnIntPtrMethod')
|
|
external int returnIntPtrMethod(int x);
|
|
}
|
|
|
|
// Native function takes a Handle, so a Handle is passed as-is.
|
|
@Native<IntPtr Function(Handle)>(symbol: 'PassAsHandle')
|
|
external int passAsHandle(NativeFieldWrapperClass1 obj);
|
|
// FFI signature takes Pointer, Dart signature takes NativeFieldWrapperClass1.
|
|
// This implies automatic conversion.
|
|
@Native<IntPtr Function(Pointer<Void>)>(symbol: 'PassAsPointer')
|
|
external int passAsPointer(NativeFieldWrapperClass1 obj);
|
|
// Pass Pointer automatically, and return value.
|
|
@Native<IntPtr Function(Pointer<Void>, IntPtr)>(symbol: 'PassAsPointerAndValue')
|
|
external int passAsPointerAndValue(NativeFieldWrapperClass1 obj, int value);
|
|
// Pass Pointer automatically, and return value.
|
|
@Native<IntPtr Function(IntPtr, Pointer<Void>)>(symbol: 'PassAsValueAndPointer')
|
|
external int passAsValueAndPointer(int value, NativeFieldWrapperClass1 obj);
|
|
|
|
// Helpers for testing argument evaluation order is preserved.
|
|
int state = 0;
|
|
int setState(int value) {
|
|
state = value;
|
|
return 0;
|
|
}
|
|
|
|
base class StateSetter extends NativeFieldWrapperClass1 {
|
|
StateSetter(int value) {
|
|
setNativeInstanceField(this, 0, 0);
|
|
state = value;
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
// Register test resolver for top-level functions above.
|
|
setFfiNativeResolverForTest(getRootLibraryUrl());
|
|
|
|
// Test we can call Native functions.
|
|
Expect.equals(123, returnIntPtr(123));
|
|
Expect.equals(123, returnIntPtrLeaf(123));
|
|
Expect.equals(123, Classy.returnIntPtrStatic(123));
|
|
|
|
// Test Native leaf calls remain in generated code.
|
|
// Regular calls should transition generated -> native.
|
|
Expect.equals(0, isThreadInGenerated());
|
|
// Leaf calls should remain in generated state.
|
|
Expect.equals(1, isThreadInGeneratedLeaf());
|
|
|
|
// Test that objects extending NativeFieldWrapperClass1 can be passed to
|
|
// Native functions that take Pointer.
|
|
// Such objects should automatically be converted and pass as Pointer.
|
|
{
|
|
final cwnf = ClassWithNativeField(123456);
|
|
Expect.equals(123456, passAsHandle(cwnf));
|
|
Expect.equals(123456, passAsPointer(cwnf));
|
|
}
|
|
|
|
// Test that the order of argument evaluation is being preserved through the
|
|
// transform wrapping NativeFieldWrapperClass1 objects.
|
|
state = 0;
|
|
passAsValueAndPointer(setState(7), StateSetter(3));
|
|
Expect.equals(3, state);
|
|
|
|
// Test transforms of instance methods.
|
|
Expect.equals(234, ClassWithoutNativeField().returnIntPtrMethod(234));
|
|
Expect.equals(1012, ClassWithNativeField(12).addSelfPtrAndIntMethod(1000));
|
|
Expect.equals(
|
|
2021, ClassWithNativeField(21).addSelfHandleFieldAndIntMethod(2000));
|
|
Expect.equals(
|
|
3031,
|
|
ClassWithNativeField(31)
|
|
.addSelfPtrAndPtrMethod(ClassWithNativeField(3000)));
|
|
Expect.equals(
|
|
4041,
|
|
ClassWithNativeField(41)
|
|
.addSelfHandleFieldAndPtrMethod(ClassWithNativeField(4000)));
|
|
Expect.equals(
|
|
5051,
|
|
ClassWithNativeField(51)
|
|
.addSelfHandleFieldAndHandleFieldMethod(ClassWithNativeField(5000)));
|
|
Expect.equals(
|
|
6061,
|
|
ClassWithNativeField(61)
|
|
.addselfPtrAndHandleFieldMethod(ClassWithNativeField(6000)));
|
|
Expect.throws(() {
|
|
ClassWithNativeField(nullptr.address)
|
|
.addSelfPtrAndPtrMethod(ClassWithNativeField(7000));
|
|
});
|
|
// Does not throw.
|
|
ClassWithNativeField(8000)
|
|
.addSelfPtrAndPtrMethod(ClassWithNativeField(nullptr.address));
|
|
}
|