Skip to content

Commit

Permalink
[vm/ffi] Replace FfiNative with Native
Browse files Browse the repository at this point in the history
See API design discussion in bugs below.

TEST=tests/ffi/native_assets/*

Design doc: http://go/dart-native-assets

Bug: #49803
Bug: #50097

Change-Id: Id6e6eb94c6eb39ccaaa637448583a40ab6110d12
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-ffi-android-debug-arm64c-try,vm-ffi-android-debug-arm-try,dart2wasm-linux-x64-d8-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/265084
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
  • Loading branch information
dcharkes authored and Commit Queue committed Jan 18, 2023
1 parent 9a8508e commit d2ef972
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 57 deletions.
4 changes: 4 additions & 0 deletions pkg/compiler/lib/src/io/mapped_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// 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.

// File is compiled with checked in SDK, update [FfiNative]s to [Native] when
// SDK is rolled.
// ignore_for_file: deprecated_member_use

import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
Expand Down
12 changes: 9 additions & 3 deletions pkg/dart2wasm/lib/ffi_native_transformer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,15 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {

final ffiConstant = ffiNativeAnnotation.constant as InstanceConstant;
final ffiFunctionType = ffiConstant.typeArguments[0] as FunctionType;
final nativeFunctionName = ffiConstant
.fieldValues[ffiNativeNameField.fieldReference] as StringConstant;
final isLeaf = (ffiConstant.fieldValues[ffiNativeIsLeafField.fieldReference]
final nativeFunctionConst =
(ffiConstant.fieldValues[nativeSymbolField.fieldReference] ??
ffiConstant.fieldValues[ffiNativeNameField.fieldReference]);
final nativeFunctionName = nativeFunctionConst is StringConstant
? nativeFunctionConst
: StringConstant(node.name.text);
final isLeaf = ((ffiConstant
.fieldValues[nativeIsLeafField.fieldReference] ??
ffiConstant.fieldValues[ffiNativeIsLeafField.fieldReference])
as BoolConstant)
.value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ additionalExports = (ffi::nullptr,
ffi::Char,
ffi::DartRepresentationOf,
ffi::Dart_CObject,
ffi::DefaultAsset,
ffi::Double,
ffi::DoubleArray,
ffi::DoublePointer,
Expand Down Expand Up @@ -82,6 +83,7 @@ additionalExports = (ffi::nullptr,
ffi::IntPtr,
ffi::Long,
ffi::LongLong,
ffi::Native,
ffi::NativeApi,
ffi::NativeFinalizer,
ffi::NativeFunction,
Expand Down Expand Up @@ -148,6 +150,7 @@ additionalExports = (ffi::nullptr,
ffi::Char,
ffi::DartRepresentationOf,
ffi::Dart_CObject,
ffi::DefaultAsset,
ffi::Double,
ffi::DoubleArray,
ffi::DoublePointer,
Expand Down Expand Up @@ -175,6 +178,7 @@ additionalExports = (ffi::nullptr,
ffi::IntPtr,
ffi::Long,
ffi::LongLong,
ffi::Native,
ffi::NativeApi,
ffi::NativeFinalizer,
ffi::NativeFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ additionalExports = (ffi::nullptr,
ffi::Char,
ffi::DartRepresentationOf,
ffi::Dart_CObject,
ffi::DefaultAsset,
ffi::Double,
ffi::DoubleArray,
ffi::DoublePointer,
Expand Down Expand Up @@ -82,6 +83,7 @@ additionalExports = (ffi::nullptr,
ffi::IntPtr,
ffi::Long,
ffi::LongLong,
ffi::Native,
ffi::NativeApi,
ffi::NativeFinalizer,
ffi::NativeFunction,
Expand Down Expand Up @@ -148,6 +150,7 @@ additionalExports = (ffi::nullptr,
ffi::Char,
ffi::DartRepresentationOf,
ffi::Dart_CObject,
ffi::DefaultAsset,
ffi::Double,
ffi::DoubleArray,
ffi::DoublePointer,
Expand Down Expand Up @@ -175,6 +178,7 @@ additionalExports = (ffi::nullptr,
ffi::IntPtr,
ffi::Long,
ffi::LongLong,
ffi::Native,
ffi::NativeApi,
ffi::NativeFinalizer,
ffi::NativeFunction,
Expand Down
119 changes: 88 additions & 31 deletions pkg/vm/lib/transformations/ffi/native.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ void transformLibraries(
class FfiNativeTransformer extends FfiTransformer {
final DiagnosticReporter diagnosticReporter;
final ReferenceFromIndex? referenceFromIndex;
final Class assetClass;
final Class ffiNativeClass;
final Class nativeClass;
final Class nativeFunctionClass;
final Field assetAssetField;
final Field nativeSymbolField;
final Field ffiNativeNameField;
final Field nativeAssetField;
final Field nativeIsLeafField;
final Field ffiNativeIsLeafField;
final Field resolverField;

StringConstant? _currentAsset;

// VariableDeclaration names can be null or empty string, in which case
// they're automatically assigned a "temporary" name like `#t0`.
static const variableDeclarationTemporaryName = null;
Expand All @@ -60,17 +68,37 @@ class FfiNativeTransformer extends FfiTransformer {
ClassHierarchy hierarchy,
this.diagnosticReporter,
this.referenceFromIndex)
: ffiNativeClass = index.getClass('dart:ffi', 'FfiNative'),
: assetClass = index.getClass('dart:ffi', 'DefaultAsset'),
nativeClass = index.getClass('dart:ffi', 'Native'),
ffiNativeClass = index.getClass('dart:ffi', 'FfiNative'),
nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
assetAssetField = index.getField('dart:ffi', 'DefaultAsset', 'id'),
nativeSymbolField = index.getField('dart:ffi', 'Native', 'symbol'),
ffiNativeNameField =
index.getField('dart:ffi', 'FfiNative', 'nativeName'),
nativeAssetField = index.getField('dart:ffi', 'Native', 'assetId'),
nativeIsLeafField = index.getField('dart:ffi', 'Native', 'isLeaf'),
ffiNativeIsLeafField =
index.getField('dart:ffi', 'FfiNative', 'isLeaf'),
resolverField = index.getTopLevelField('dart:ffi', '_ffi_resolver'),
super(index, coreTypes, hierarchy, diagnosticReporter,
referenceFromIndex);

ConstantExpression? tryGetFfiNativeAnnotation(Member node) {
@override
TreeNode visitLibrary(Library node) {
assert(_currentAsset == null);
final annotation = tryGetAssetAnnotation(node);
if (annotation != null) {
_currentAsset = (annotation.constant as InstanceConstant)
.fieldValues[assetAssetField.fieldReference] as StringConstant;
}
final result = super.visitLibrary(node);
_currentAsset = null;
return result;
}

ConstantExpression? tryGetAnnotation(
Annotatable node, List<Class> instanceOf) {
for (final Expression annotation in node.annotations) {
if (annotation is! ConstantExpression) {
continue;
Expand All @@ -79,13 +107,19 @@ class FfiNativeTransformer extends FfiTransformer {
if (annotationConstant is! InstanceConstant) {
continue;
}
if (annotationConstant.classNode == ffiNativeClass) {
if (instanceOf.contains(annotationConstant.classNode)) {
return annotation;
}
}
return null;
}

ConstantExpression? tryGetAssetAnnotation(Library node) =>
tryGetAnnotation(node, [assetClass]);

ConstantExpression? tryGetFfiNativeAnnotation(Member node) =>
tryGetAnnotation(node, [nativeClass, ffiNativeClass]);

bool _extendsNativeFieldWrapperClass1(DartType type) {
if (type is InterfaceType) {
Class? cls = type.classNode;
Expand Down Expand Up @@ -153,42 +187,48 @@ class FfiNativeTransformer extends FfiTransformer {
// .fromAddress(_ffi_resolver('..', 'DoXYZ', 1))
// .asFunction<int Function(Pointer<Void>)>(isLeaf:true);
Field _createResolvedFfiNativeField(
String dartFunctionName,
StringConstant nativeFunctionName,
bool isLeaf,
FunctionType dartFunctionType,
FunctionType ffiFunctionType,
int fileOffset,
Uri fileUri) {
String dartFunctionName,
StringConstant nativeFunctionName,
StringConstant? assetName,
bool isLeaf,
FunctionType dartFunctionType,
FunctionType ffiFunctionType,
int fileOffset,
Uri fileUri,
) {
// Derive number of arguments from the native function signature.
final numberNativeArgs = ffiFunctionType.positionalParameters.length;

final nativeFunctionType = InterfaceType(
nativeFunctionClass,
Nullability.legacy,
<DartType>[ffiFunctionType],
);

// _ffi_resolver('...', 'DoXYZ', 1)
final resolverInvocation = FunctionInvocation(
FunctionAccessKind.FunctionType,
StaticGet(resolverField),
Arguments(<Expression>[
ConstantExpression(
StringConstant(currentLibrary.importUri.toString())),
assetName ?? StringConstant(currentLibrary.importUri.toString())),
ConstantExpression(nativeFunctionName),
ConstantExpression(IntConstant(numberNativeArgs)),
]),
functionType: resolverField.type as FunctionType)
..fileOffset = fileOffset;

// _fromAddress<NativeFunction<Double Function(Double)>>(...)
final fromAddressInvocation = StaticInvocation(
final functionPointerExpression = StaticInvocation(
fromAddressInternal,
Arguments(<Expression>[
resolverInvocation
], types: [
InterfaceType(nativeFunctionClass, Nullability.legacy,
<DartType>[ffiFunctionType])
]))
Arguments(
<Expression>[resolverInvocation],
types: [nativeFunctionType],
))
..fileOffset = fileOffset;

final asFunctionInvocation = buildAsFunctionInternal(
functionPointer: fromAddressInvocation,
functionPointer: functionPointerExpression,
dartSignature: dartFunctionType,
nativeSignature: ffiFunctionType,
isLeaf: isLeaf,
Expand Down Expand Up @@ -436,6 +476,7 @@ class FfiNativeTransformer extends FfiTransformer {
Procedure _transformProcedure(
Procedure node,
StringConstant nativeFunctionName,
StringConstant? assetName,
bool isLeaf,
int annotationOffset,
FunctionType dartFunctionType,
Expand Down Expand Up @@ -464,13 +505,15 @@ class FfiNativeTransformer extends FfiTransformer {

// static final _myMethod$FfiNative$Ptr = ..
final resolvedField = _createResolvedFfiNativeField(
'${node.name.text}\$${node.kind.name}',
nativeFunctionName,
isLeaf,
wrappedDartFunctionType,
ffiFunctionType,
node.fileOffset,
fileUri);
'${node.name.text}\$${node.kind.name}',
nativeFunctionName,
assetName,
isLeaf,
wrappedDartFunctionType,
ffiFunctionType,
node.fileOffset,
fileUri,
);

// Add field to the parent the FfiNative function belongs to.
if (parent is Class) {
Expand Down Expand Up @@ -531,6 +574,7 @@ class FfiNativeTransformer extends FfiTransformer {
Procedure node,
FunctionType ffiFunctionType,
StringConstant nativeFunctionName,
StringConstant? assetName,
bool isLeaf,
int annotationOffset) {
final dartFunctionType = FunctionType([
Expand All @@ -547,6 +591,7 @@ class FfiNativeTransformer extends FfiTransformer {
return _transformProcedure(
node,
nativeFunctionName,
assetName,
isLeaf,
annotationOffset,
dartFunctionType,
Expand All @@ -569,6 +614,7 @@ class FfiNativeTransformer extends FfiTransformer {
Procedure node,
FunctionType ffiFunctionType,
StringConstant nativeFunctionName,
StringConstant? assetName,
bool isLeaf,
int annotationOffset) {
final dartFunctionType =
Expand All @@ -582,6 +628,7 @@ class FfiNativeTransformer extends FfiTransformer {
return _transformProcedure(
node,
nativeFunctionName,
assetName,
isLeaf,
annotationOffset,
dartFunctionType,
Expand Down Expand Up @@ -612,19 +659,29 @@ class FfiNativeTransformer extends FfiTransformer {

final ffiConstant = ffiNativeAnnotation.constant as InstanceConstant;
final ffiFunctionType = ffiConstant.typeArguments[0] as FunctionType;
final nativeFunctionName = ffiConstant
.fieldValues[ffiNativeNameField.fieldReference] as StringConstant;
final isLeaf = (ffiConstant.fieldValues[ffiNativeIsLeafField.fieldReference]
final nativeFunctionConst =
(ffiConstant.fieldValues[nativeSymbolField.fieldReference] ??
ffiConstant.fieldValues[ffiNativeNameField.fieldReference]);
final nativeFunctionName = nativeFunctionConst is StringConstant
? nativeFunctionConst
: StringConstant(node.name.text);
final assetConstant =
ffiConstant.fieldValues[nativeAssetField.fieldReference];
final assetName =
assetConstant is StringConstant ? assetConstant : _currentAsset;
final isLeaf = ((ffiConstant
.fieldValues[nativeIsLeafField.fieldReference] ??
ffiConstant.fieldValues[ffiNativeIsLeafField.fieldReference])
as BoolConstant)
.value;

if (!node.isStatic) {
return _transformInstanceMethod(node, ffiFunctionType, nativeFunctionName,
isLeaf, ffiNativeAnnotation.fileOffset);
assetName, isLeaf, ffiNativeAnnotation.fileOffset);
}

return _transformStaticFunction(node, ffiFunctionType, nativeFunctionName,
isLeaf, ffiNativeAnnotation.fileOffset);
assetName, isLeaf, ffiNativeAnnotation.fileOffset);
}

/// Checks whether the FFI function type is valid and reports any errors.
Expand Down
2 changes: 2 additions & 0 deletions pkg/vm/testcases/transformations/ffi/ffinative.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

// Tests for @FfiNative related transformations.

// ignore_for_file: deprecated_member_use

// @dart=2.14

import 'dart:ffi';
Expand Down
Loading

0 comments on commit d2ef972

Please sign in to comment.