[vm/ffi] Change Pointer.elementAt and sizeOf to use static type

This CL changes the semantics of
`Pointer<T extends NativeType>.elementAt` and
`sizeOf<T extends NativeType>` to use the compile-time `T` rather than
the runtime `T`.

Issue: https://github.com/dart-lang/sdk/issues/38721

TEST=tests/ffi/data_test.dart
TEST=tests/ffi/sizeof_test.dart
TEST=tests/ffi/structs_test.dart
TEST=tests/ffi/vmspecific_static_checks_test.dart

Change-Id: Ifb25a4bd66d50a385d3db6dec9213b96dff21722
Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,analyzer-nnbd-linux-release-try,front-end-linux-release-x64-try,front-end-nnbd-linux-release-x64-try,benchmark-linux-try,dart-sdk-linux-try,pkg-linux-release-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178200
Reviewed-by: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Daco Harkes 2021-02-17 11:39:42 +00:00 committed by commit-bot@chromium.org
parent f169abcee0
commit 3593de9179
14 changed files with 29 additions and 113 deletions

View file

@ -474,7 +474,6 @@ const List<ErrorCode> errorCodeValues = [
FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
FfiCode.MUST_BE_A_SUBTYPE,
FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
FfiCode.NON_SIZED_TYPE_ARGUMENT,
FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,

View file

@ -183,20 +183,6 @@ class FfiCode extends AnalyzerErrorCode {
"parameters are not constants.",
correction: "Try changing the type argument to be a constant type.");
/**
* Parameters:
* 0: the name of the function, method, or constructor having type arguments
*/
static const FfiCode NON_CONSTANT_TYPE_ARGUMENT_WARNING = FfiCode(
name: 'NON_CONSTANT_TYPE_ARGUMENT_WARNING',
message:
"Support for using non-constant type arguments '{0}' in this FFI API"
" is deprecated and will be removed in the next stable version of "
"Dart. Rewrite the code to ensure that type arguments are compile "
"time constants referring to a valid native type.",
correction: "Try changing the type argument to be a constant type.",
type: ErrorType.HINT);
/**
* Parameters:
* 0: the type that should be a valid dart:ffi native type.

View file

@ -525,9 +525,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
final AstNode errorNode = node;
_errorReporter.reportErrorForNode(
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
errorNode,
['elementAt']);
FfiCode.NON_CONSTANT_TYPE_ARGUMENT, errorNode, ['elementAt']);
}
}
}
@ -703,7 +701,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
final AstNode errorNode = node;
_errorReporter.reportErrorForNode(
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['sizeOf']);
FfiCode.NON_CONSTANT_TYPE_ARGUMENT, errorNode, ['sizeOf']);
}
}

View file

@ -62,7 +62,6 @@ export '../fasta/fasta_codes.dart'
templateFfiFieldCyclic,
templateFfiFieldInitializer,
templateFfiFieldNoAnnotation,
templateFfiNonConstantTypeArgumentWarning,
templateFfiNotStatic,
templateFfiStructGeneric,
templateFfiTypeInvalid,

View file

@ -915,35 +915,6 @@ Message _withArgumentsFfiExpectedNoExceptionalReturn(
arguments: {'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
templateFfiNonConstantTypeArgumentWarning = const Template<
Message Function(DartType _type, bool isNonNullableByDefault)>(
messageTemplate:
r"""Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""",
withArguments: _withArgumentsFfiNonConstantTypeArgumentWarning);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(DartType _type, bool isNonNullableByDefault)>
codeFfiNonConstantTypeArgumentWarning =
const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
"FfiNonConstantTypeArgumentWarning",
analyzerCodes: <String>["NON_CONSTANT_TYPE_ARGUMENT_WARNING"],
severity: Severity.info);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiNonConstantTypeArgumentWarning(
DartType _type, bool isNonNullableByDefault) {
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
List<Object> typeParts = labeler.labelType(_type);
String type = typeParts.join();
return new Message(codeFfiNonConstantTypeArgumentWarning,
message:
"""Support for using non-constant type arguments '${type}' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""" +
labeler.originMessages,
arguments: {'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(

View file

@ -4242,13 +4242,6 @@ FfiFieldCyclic:
#names
external: test/ffi_test.dart
FfiNonConstantTypeArgumentWarning:
# Used by dart:ffi
template: "Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type."
analyzerCode: NON_CONSTANT_TYPE_ARGUMENT_WARNING
severity: INFO
external: test/ffi_test.dart
FfiNotStatic:
# Used by dart:ffi
template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."

View file

@ -13,7 +13,6 @@ import 'package:front_end/src/api_unstable/vm.dart'
templateFfiExpectedExceptionalReturn,
templateFfiExpectedNoExceptionalReturn,
templateFfiExtendsOrImplementsSealedClass,
templateFfiNonConstantTypeArgumentWarning,
templateFfiNotStatic,
templateFfiTypeInvalid,
templateFfiTypeMismatch;
@ -189,7 +188,7 @@ class _FfiUseSiteTransformer extends FfiTransformer {
// TODO(http://dartbug.com/38721): Change this to an error after
// package:ffi is no longer using sizeOf generically.
if (!isFfiLibrary) {
_warningNativeTypeValid(nativeType, node);
_ensureNativeTypeValid(nativeType, node);
}
if (nativeType is InterfaceType) {
@ -467,13 +466,7 @@ class _FfiUseSiteTransformer extends FfiTransformer {
node.receiver.getStaticType(_staticTypeContext);
final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
_warningNativeTypeValid(nativeType, node);
// TODO(http://dartbug.com/38721): Change this to an error.
if (nativeType is TypeParameterType) {
// Do not rewire generic invocations.
return node;
}
_ensureNativeTypeValid(nativeType, node);
Expression inlineSizeOf = _inlineSizeOf(nativeType);
if (inlineSizeOf != null) {
@ -541,22 +534,6 @@ class _FfiUseSiteTransformer extends FfiTransformer {
}
}
void _warningNativeTypeValid(DartType nativeType, Expression node,
{bool allowHandle: false, bool allowStructItself = true}) {
if (!_nativeTypeValid(nativeType,
allowStructs: true,
allowStructItself: allowStructItself,
allowHandle: allowHandle)) {
diagnosticReporter.report(
templateFfiNonConstantTypeArgumentWarning.withArguments(
nativeType, currentLibrary.isNonNullableByDefault),
node.fileOffset,
1,
node.location.file);
throw _FfiStaticTypeError();
}
}
void _ensureNoEmptyStructs(DartType nativeType, Expression node) {
// Error on structs with no fields.
if (nativeType is InterfaceType) {

View file

@ -12,6 +12,7 @@ extension AllocatorAlloc on Allocator {
// TODO(http://dartbug.com/39964): Add `alignmentOf<T>()` call.
@patch
Pointer<T> call<T extends NativeType>([int count = 1]) {
return this.allocate(sizeOf<T>() * count);
// This case should have been rewritten in pre-processing.
throw UnimplementedError("Pointer<$T>");
}
}

View file

@ -26,19 +26,10 @@ int get _intPtrSize => (const [8, 4, 4])[_abi()];
@patch
int sizeOf<T extends NativeType>() {
// This is not super fast, but it is faster than a runtime entry.
// Hot loops with elementAt().load() do not use this sizeOf, elementAt is
// optimized per NativeType statically to prevent use of sizeOf at runtime.
final int? knownSize = _knownSizes[T];
if (knownSize != null) return knownSize;
if (T == IntPtr) return _intPtrSize;
if (T == Pointer) return _intPtrSize;
// For structs we fall back to a runtime entry.
return _sizeOf<T>();
// This case should have been rewritten in pre-processing.
throw UnimplementedError("$T");
}
int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
@pragma("vm:recognized", "other")
Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
@ -98,11 +89,13 @@ class Pointer<T extends NativeType> {
@pragma("vm:recognized", "other")
int get address native "Ffi_address";
// For statically known types, this is rewired.
// (Method sizeOf is slow, see notes above.)
// For statically known types, this is rewritten.
@patch
Pointer<T> elementAt(int index) =>
Pointer.fromAddress(address + sizeOf<T>() * index);
Pointer<T> elementAt(int index) {
// This case should have been rewritten in pre-processing.
// Only dynamic invocations are not rewritten in pre-processing.
throw UnsupportedError("Pointer.elementAt cannot be called dynamically.");
}
@patch
Pointer<T> _offsetBy(int offsetInBytes) =>

View file

@ -24,9 +24,7 @@ part "struct.dart";
///
/// Includes padding and alignment of structs.
///
/// Support for invoking this function with non-constant [T] will be removed in
/// the next stable version of Dart and it will become mandatory to invoke it
/// with a compile-time constant [T].
/// This function must be invoked with a compile-time constant [T].
external int sizeOf<T extends NativeType>();
/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
@ -65,9 +63,10 @@ class Pointer<T extends NativeType> extends NativeType {
/// Pointer arithmetic (takes element size into account).
///
/// Support for invoking this method with non-constant [T] will be removed in
/// the next stable version of Dart and it will become mandatory to invoke it
/// with a compile-time constant [T].
/// This method must be invoked with a compile-time constant [T].
///
/// Does not accept dynamic invocations -- where the type of the receiver is
/// [dynamic].
external Pointer<T> elementAt(int index);
/// Cast Pointer<T> to a Pointer<V>.

View file

@ -449,7 +449,7 @@ void testDynamicInvocation() {
final int i = p.value;
});
Expect.throws(() => p.value = 1);
p.elementAt(5); // Works, but is slow.
Expect.throws(() => p.elementAt(5));
final int addr = p.address;
final Pointer<Int16> p2 = p.cast<Int16>();
calloc.free(p);

View file

@ -625,7 +625,7 @@ T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: compile-time error
void testSizeOfGeneric() {
int generic<T extends Pointer>() {
int size = sizeOf<IntPtr>();
size = sizeOf<T>(); //# 1300: ok
size = sizeOf<T>(); //# 1300: compile-time error
return size;
}
@ -634,7 +634,7 @@ void testSizeOfGeneric() {
void testSizeOfNativeType() {
try {
sizeOf(); //# 1301: ok
sizeOf(); //# 1301: compile-time error
} catch (e) {
print(e);
}
@ -643,7 +643,7 @@ void testSizeOfNativeType() {
void testElementAtGeneric() {
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
Pointer<T> returnValue = pointer;
returnValue = returnValue.elementAt(1); //# 1310: ok
returnValue = returnValue.elementAt(1); //# 1310: compile-time error
return returnValue;
}
@ -657,6 +657,6 @@ void testElementAtNativeType() {
Pointer<Int8> p = calloc();
p.elementAt(1);
Pointer<NativeType> p2 = p;
p2.elementAt(1); //# 1311: ok
p2.elementAt(1); //# 1311: compile-time error
calloc.free(p);
}

View file

@ -449,7 +449,7 @@ void testDynamicInvocation() {
final int i = p.value;
});
Expect.throws(() => p.value = 1);
p.elementAt(5); // Works, but is slow.
Expect.throws(() => p.elementAt(5));
final int addr = p.address;
final Pointer<Int16> p2 = p.cast<Int16>();
calloc.free(p);

View file

@ -623,7 +623,7 @@ T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: compile-time error
void testSizeOfGeneric() {
int generic<T extends Pointer>() {
int size = sizeOf<IntPtr>();
size = sizeOf<T>(); //# 1300: ok
size = sizeOf<T>(); //# 1300: compile-time error
return size;
}
@ -632,7 +632,7 @@ void testSizeOfGeneric() {
void testSizeOfNativeType() {
try {
sizeOf(); //# 1301: ok
sizeOf(); //# 1301: compile-time error
} catch (e) {
print(e);
}
@ -641,7 +641,7 @@ void testSizeOfNativeType() {
void testElementAtGeneric() {
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
Pointer<T> returnValue = pointer;
returnValue = returnValue.elementAt(1); //# 1310: ok
returnValue = returnValue.elementAt(1); //# 1310: compile-time error
return returnValue;
}
@ -655,6 +655,6 @@ void testElementAtNativeType() {
Pointer<Int8> p = calloc();
p.elementAt(1);
Pointer<NativeType> p2 = p;
p2.elementAt(1); //# 1311: ok
p2.elementAt(1); //# 1311: compile-time error
calloc.free(p);
}