Skip to content

Commit 460e00a

Browse files
Clement Skaucommit-bot@chromium.org
Clement Skau
authored andcommitted
[VM] Adds leaf call option to FfiNative.
This change essentially exposes `asFunction`'s `isLeaf` in `@FfiNative`, allowing us to declare FFI Natives as leaf calls. TEST=Adds tests/ffi/ffi_native_test.dart Bug: #43889 Change-Id: I2a396fae2ab28d21df282f3afb35fa401485ed52 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/206375 Reviewed-by: Daco Harkes <[email protected]> Commit-Queue: Clement Skau <[email protected]>
1 parent 79327c9 commit 460e00a

File tree

5 files changed

+81
-10
lines changed

5 files changed

+81
-10
lines changed

pkg/vm/lib/transformations/ffi_native.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class FfiNativeTransformer extends Transformer {
3030
final Class ffiNativeClass;
3131
final Class nativeFunctionClass;
3232
final Field ffiNativeNameField;
33+
final Field ffiNativeIsLeafField;
3334
final Field resolverField;
3435
final Procedure asFunctionProcedure;
3536
final Procedure fromAddressInternal;
@@ -39,6 +40,8 @@ class FfiNativeTransformer extends Transformer {
3940
nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
4041
ffiNativeNameField =
4142
index.getField('dart:ffi', 'FfiNative', 'nativeName'),
43+
ffiNativeIsLeafField =
44+
index.getField('dart:ffi', 'FfiNative', 'isLeaf'),
4245
resolverField = index.getTopLevelField('dart:ffi', '_ffi_resolver'),
4346
asFunctionProcedure = index.getProcedure(
4447
'dart:ffi', 'NativeFunctionPointer', 'asFunction'),
@@ -71,21 +74,23 @@ class FfiNativeTransformer extends Transformer {
7174
}
7275

7376
// Transform:
74-
// @FfiNative<Double Function(Double)>('Math_sqrt')
77+
// @FfiNative<Double Function(Double)>('Math_sqrt', isLeaf:true)
7578
// external double _square_root(double x);
7679
//
7780
// Into:
7881
// final _@FfiNative__square_root =
7982
// Pointer<NativeFunction<Double Function(Double)>>
8083
// .fromAddress(_ffi_resolver('dart:math', 'Math_sqrt'))
81-
// .asFunction<double Function(double)>();
84+
// .asFunction<double Function(double)>(isLeaf:true);
8285
// double _square_root(double x) => _@FfiNative__square_root(x);
8386
Statement transformFfiNative(
8487
Procedure node, InstanceConstant annotationConst) {
8588
assert(currentLibrary != null);
8689
final params = node.function.positionalParameters;
8790
final functionName = annotationConst
8891
.fieldValues[ffiNativeNameField.getterReference] as StringConstant;
92+
final isLeaf = annotationConst
93+
.fieldValues[ffiNativeIsLeafField.getterReference] as BoolConstant;
8994

9095
// double Function(double)
9196
final DartType dartType =
@@ -115,9 +120,12 @@ class FfiNativeTransformer extends Transformer {
115120
Arguments([resolverInvocation], types: [nativeInterfaceType]));
116121

117122
// NativeFunctionPointer.asFunction
118-
// <Double Function(Double), double Function(double)>(...)
119-
final asFunctionInvocation = StaticInvocation(asFunctionProcedure,
120-
Arguments([fromAddressInvocation], types: [nativeType, dartType]));
123+
// <Double Function(Double), double Function(double)>(..., isLeaf:true)
124+
final asFunctionInvocation = StaticInvocation(
125+
asFunctionProcedure,
126+
Arguments([fromAddressInvocation],
127+
types: [nativeType, dartType],
128+
named: [NamedExpression("isLeaf", BoolLiteral(isLeaf.value))]));
121129

122130
// final _@FfiNative__square_root = ...
123131
final fieldName = Name('_@FfiNative_${node.name.text}', currentLibrary);
@@ -127,7 +135,8 @@ class FfiNativeTransformer extends Transformer {
127135
isStatic: true,
128136
isFinal: true,
129137
fileUri: currentLibrary!.fileUri,
130-
getterReference: currentLibraryIndex?.lookupGetterReference(fieldName));
138+
getterReference: currentLibraryIndex?.lookupGetterReference(fieldName))
139+
..fileOffset = node.fileOffset;
131140
currentLibrary!.addField(funcPtrField);
132141

133142
// _@FfiNative__square_root(x)

runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,4 +1080,33 @@ DART_EXPORT void ReleaseClosureCallback() {
10801080
Dart_DeletePersistentHandle_DL(closure_to_callback_);
10811081
}
10821082

1083+
////////////////////////////////////////////////////////////////////////////////
1084+
// Functions for testing @FfiNative.
1085+
1086+
DART_EXPORT Dart_Handle GetRootLibraryUrl() {
1087+
Dart_Handle root_lib = Dart_RootLibrary();
1088+
Dart_Handle lib_url = Dart_LibraryUrl(root_lib);
1089+
ENSURE(!Dart_IsError(lib_url));
1090+
return lib_url;
1091+
}
1092+
1093+
intptr_t ReturnIntPtr(intptr_t x) {
1094+
return x;
1095+
}
1096+
1097+
static void* FfiNativeResolver(const char* name) {
1098+
if (strcmp(name, "ReturnIntPtr") == 0) {
1099+
return reinterpret_cast<void*>(ReturnIntPtr);
1100+
}
1101+
// This should be unreachable in tests.
1102+
ENSURE(false);
1103+
}
1104+
1105+
DART_EXPORT void SetFfiNativeResolverForTest(Dart_Handle url) {
1106+
Dart_Handle library = Dart_LookupLibrary(url);
1107+
ENSURE(!Dart_IsError(library));
1108+
Dart_Handle result = Dart_SetFfiNativeResolver(library, &FfiNativeResolver);
1109+
ENSURE(!Dart_IsError(result));
1110+
}
1111+
10831112
} // namespace dart

runtime/vm/dart_api_impl_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9305,7 +9305,7 @@ static void* FfiNativeResolver(const char* name) {
93059305
TEST_CASE(Dart_SetFfiNativeResolver) {
93069306
const char* kScriptChars = R"(
93079307
import 'dart:ffi';
9308-
@FfiNative<IntPtr Function(Double)>('EchoInt')
9308+
@FfiNative<IntPtr Function(Double)>('EchoInt', isLeaf:true)
93099309
external int echoInt(double x);
93109310
main() => echoInt(7.0);
93119311
)";
@@ -9327,7 +9327,7 @@ TEST_CASE(Dart_SetFfiNativeResolver) {
93279327
TEST_CASE(Dart_SetFfiNativeResolver_MissingResolver) {
93289328
const char* kScriptChars = R"(
93299329
import 'dart:ffi';
9330-
@FfiNative<IntPtr Function(Double)>('EchoInt')
9330+
@FfiNative<IntPtr Function(Double)>('EchoInt', isLeaf:true)
93319331
external int echoInt(double x);
93329332
main() => echoInt(7.0);
93339333
)";

sdk/lib/ffi/ffi.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ abstract class NativeApi {
806806
///
807807
/// Example:
808808
///```dart
809-
/// @FfiNative<Int64 Function(Int64, Int64)>("FfiNative_Sum")
809+
/// @FfiNative<Int64 Function(Int64, Int64)>("FfiNative_Sum", isLeaf:true)
810810
/// external int sum(int a, int b);
811811
///```
812812
/// Calling such functions will throw an exception if no resolver
@@ -817,7 +817,8 @@ abstract class NativeApi {
817817
/// NOTE: This is an experimental feature and may change in the future.
818818
class FfiNative<T> {
819819
final String nativeName;
820-
const FfiNative(this.nativeName);
820+
final bool isLeaf;
821+
const FfiNative(this.nativeName, {this.isLeaf: false});
821822
}
822823

823824
// Bootstrapping native for getting the FFI native C function pointer to look

tests/ffi/ffi_native_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
//
5+
// SharedObjects=ffi_test_functions
6+
7+
import 'dart:ffi';
8+
9+
import 'package:expect/expect.dart';
10+
11+
import 'dylib_utils.dart';
12+
13+
final nativeLib = dlopenPlatformSpecific('ffi_test_functions');
14+
final getRootLibraryUrl = nativeLib
15+
.lookupFunction<Handle Function(), Object Function()>('GetRootLibraryUrl');
16+
final setFfiNativeResolverForTest = nativeLib
17+
.lookupFunction<Void Function(Handle), void Function(Object)>('SetFfiNativeResolverForTest');
18+
19+
@FfiNative<IntPtr Function(IntPtr)>('ReturnIntPtr')
20+
external int returnIntPtr(int x);
21+
22+
@FfiNative<IntPtr Function(IntPtr)>('ReturnIntPtr', isLeaf: true)
23+
external int returnIntPtrLeaf(int x);
24+
25+
void main() {
26+
// Register test resolver for top-level functions above.
27+
final root_lib_url = getRootLibraryUrl();
28+
setFfiNativeResolverForTest(root_lib_url);
29+
30+
Expect.equals(123, returnIntPtr(123));
31+
Expect.equals(123, returnIntPtrLeaf(123));
32+
}

0 commit comments

Comments
 (0)