Skip to content

Commit

Permalink
[cfe/ffi] Refactor dart:ffi transformations
Browse files Browse the repository at this point in the history
Introduces the `NativeTypeCfe` type hierarchy for cleaner calculation
of sizes and offsets of native types and cleaner code generation.

The transformation ensures we're only visiting the structs in
topological order, which means the struct type can always look up its
(indirectly) nested structs in the `structCache`.

This simplifies adding inline arrays
(https://dart-review.googlesource.com/c/sdk/+/183640), packed structs,
and unions to this transformation.

`typedDataBaseOffset` is moved to the `FfiTransformer` because the
dependent CL uses it in the `FfiUseSiteTransformer`.

Bug: #35763
Bug: #38158
Bug: #38491

TEST=tests/ffi(_2)/(.*)by_value(.*)_test.dart

Change-Id: I345e02c48844ca795f9137a5addd5ba89992e1c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/184421
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
  • Loading branch information
dcharkes authored and commit-bot@chromium.org committed Feb 11, 2021
1 parent fca959e commit 0bada8c
Show file tree
Hide file tree
Showing 3 changed files with 435 additions and 274 deletions.
118 changes: 118 additions & 0 deletions pkg/vm/lib/transformations/ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ class FfiTransformer extends Transformer {
/// Classes corresponding to [NativeType], indexed by [NativeType].
final List<Class> nativeTypesClasses;

Library currentLibrary;
IndexedLibrary currentLibraryIndex;

FfiTransformer(this.index, this.coreTypes, this.hierarchy,
this.diagnosticReporter, this.referenceFromIndex)
: env = new TypeEnvironment(coreTypes, hierarchy),
Expand Down Expand Up @@ -336,6 +339,16 @@ class FfiTransformer extends Transformer {
'DynamicLibraryExtension',
LibraryIndex.tearoffPrefix + 'lookupFunction');

@override
TreeNode visitLibrary(Library node) {
assert(currentLibrary == null);
currentLibrary = node;
currentLibraryIndex = referenceFromIndex?.lookupLibrary(node);
final result = super.visitLibrary(node);
currentLibrary = null;
return result;
}

/// Computes the Dart type corresponding to a ffi.[NativeType], returns null
/// if it is not a valid NativeType.
///
Expand Down Expand Up @@ -441,6 +454,111 @@ class FfiTransformer extends Transformer {
Arguments([StaticInvocation(abiMethod, Arguments([]))]),
listElementAt);
}

/// Generates an expression that returns a new `Pointer<dartType>` offset
/// by [offset] from [pointer].
///
/// Sample output:
///
/// ```
/// _fromAddress<dartType>(pointer.address + #offset)
/// ```
Expression _pointerOffset(Expression pointer, Expression offset,
DartType dartType, int fileOffset) =>
StaticInvocation(
fromAddressInternal,
Arguments([
MethodInvocation(
PropertyGet(pointer, addressGetter.name, addressGetter)
..fileOffset = fileOffset,
numAddition.name,
Arguments([offset]),
numAddition)
], types: [
dartType
]))
..fileOffset = fileOffset;

/// Generates an expression that returns a new `TypedData` offset
/// by [offset] from [typedData].
///
/// Sample output:
///
/// ```
/// TypedData #typedData = typedData;
/// #typedData.buffer.asInt8List(#typedData.offsetInBytes + offset, length)
/// ```
Expression _typedDataOffset(Expression typedData, Expression offset,
Expression length, int fileOffset) {
final typedDataVar = VariableDeclaration("#typedData",
initializer: typedData,
type: InterfaceType(typedDataClass, Nullability.nonNullable))
..fileOffset = fileOffset;
return Let(
typedDataVar,
MethodInvocation(
PropertyGet(VariableGet(typedDataVar), typedDataBufferGetter.name,
typedDataBufferGetter)
..fileOffset = fileOffset,
byteBufferAsUint8List.name,
Arguments([
MethodInvocation(
PropertyGet(
VariableGet(typedDataVar),
typedDataOffsetInBytesGetter.name,
typedDataOffsetInBytesGetter)
..fileOffset = fileOffset,
numAddition.name,
Arguments([offset]),
numAddition),
length
]),
byteBufferAsUint8List));
}

/// Generates an expression that returns a new `TypedDataBase` offset
/// by [offset] from [typedDataBase].
///
/// If [typedDataBase] is a `Pointer`, returns a `Pointer<dartType>`.
/// If [typedDataBase] is a `TypedData` returns a `TypedData`.
///
/// Sample output:
///
/// ```
/// Object #typedDataBase = typedDataBase;
/// int #offset = offset;
/// #typedDataBase is Pointer ?
/// _pointerOffset<dartType>(#typedDataBase, #offset) :
/// _typedDataOffset((#typedDataBase as TypedData), #offset, length)
/// ```
Expression typedDataBaseOffset(Expression typedDataBase, Expression offset,
Expression length, DartType dartType, int fileOffset) {
final typedDataBaseVar = VariableDeclaration("#typedDataBase",
initializer: typedDataBase, type: coreTypes.objectNonNullableRawType)
..fileOffset = fileOffset;
final offsetVar = VariableDeclaration("#offset",
initializer: offset, type: coreTypes.intNonNullableRawType)
..fileOffset = fileOffset;
return BlockExpression(
Block([typedDataBaseVar, offsetVar]),
ConditionalExpression(
IsExpression(VariableGet(typedDataBaseVar),
InterfaceType(pointerClass, Nullability.nonNullable)),
_pointerOffset(VariableGet(typedDataBaseVar),
VariableGet(offsetVar), dartType, fileOffset),
_typedDataOffset(
StaticInvocation(
unsafeCastMethod,
Arguments([
VariableGet(typedDataBaseVar)
], types: [
InterfaceType(typedDataClass, Nullability.nonNullable)
])),
VariableGet(offsetVar),
length,
fileOffset),
coreTypes.objectNonNullableRawType));
}
}

/// Contains all information collected by _FfiDefinitionTransformer that is
Expand Down
Loading

0 comments on commit 0bada8c

Please sign in to comment.