mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[ffi] Convert ABI-specific integers to fixed-width integers when doing wasm FfiNative transformation.
It's a bug if a class has more than one `@AbiSpecificIntegerMapping` annotation. Reflect this in the return type of method for getting the annotation and issue a diagnostic if the invariant doesn't hold. The invariant is checked by `_FfiDefinitionTransformer`. Change-Id: Iadf4636090c6ec814f623c9245b3a1fe8b466b4b Tested: Unit tests written with all ABI specific integer types. Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268105 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Jackson Gardner <jacksongardner@google.com> Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
parent
89a74663b5
commit
81a63dafe5
8
pkg/dart2wasm/lib/abi.dart
Normal file
8
pkg/dart2wasm/lib/abi.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// The ABI type sizes are the same for 32-bit Wasm as for 32-bit ARM, so we
|
||||
// can just use an ABI enum index corresponding to a 32-bit ARM platform.
|
||||
|
||||
const int kWasmAbiEnumIndex = 0; // androidArm
|
|
@ -8,8 +8,10 @@ import 'package:kernel/core_types.dart';
|
|||
import 'package:kernel/library_index.dart' show LibraryIndex;
|
||||
import 'package:kernel/reference_from_index.dart' show ReferenceFromIndex;
|
||||
import 'package:kernel/target/targets.dart' show DiagnosticReporter;
|
||||
import 'package:vm/transformations/ffi/abi.dart' show Abi;
|
||||
import 'package:vm/transformations/ffi/common.dart' show NativeType;
|
||||
import 'package:vm/transformations/ffi/native.dart' show FfiNativeTransformer;
|
||||
import 'abi.dart' show kWasmAbiEnumIndex;
|
||||
|
||||
/// Transform `@FfiNative`-annotated functions to convert Dart arguments to
|
||||
/// Wasm arguments expected by the FFI functions, and convert the Wasm function
|
||||
|
@ -236,7 +238,8 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
|
|||
///
|
||||
/// Returns `null` for [Void] values.
|
||||
Expression? _dartValueToFfiValue(DartType ffiType, Expression expr) {
|
||||
final InterfaceType abiType_ = ffiType as InterfaceType;
|
||||
final InterfaceType abiType_ =
|
||||
_getFixedWidthIntegerFromAbiSpecificInteger(ffiType as InterfaceType);
|
||||
final NativeType abiTypeNativeType = getType(abiType_.classNode)!;
|
||||
|
||||
switch (abiTypeNativeType) {
|
||||
|
@ -292,7 +295,8 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
|
|||
/// For example, converts an `Bool` native type to Dart bool by checking the
|
||||
/// Wasm I32 value for the bool: 0 means `false`, non-0 means `true`.
|
||||
Expression _ffiValueToDartValue(DartType ffiType, Expression expr) {
|
||||
final InterfaceType ffiType_ = ffiType as InterfaceType;
|
||||
final InterfaceType ffiType_ =
|
||||
_getFixedWidthIntegerFromAbiSpecificInteger(ffiType as InterfaceType);
|
||||
final NativeType nativeType = getType(ffiType_.classNode)!;
|
||||
|
||||
Expression instanceInvocation(Procedure converter, Expression receiver) =>
|
||||
|
@ -344,6 +348,22 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
InterfaceType _getFixedWidthIntegerFromAbiSpecificInteger(
|
||||
InterfaceType ffiType) {
|
||||
final MapConstant? abiIntegerMapping =
|
||||
getAbiSpecificIntegerMappingAnnotation(ffiType.classNode);
|
||||
if (abiIntegerMapping == null) {
|
||||
// This isn't an ABI specific integer. Just return the type itself
|
||||
return ffiType;
|
||||
}
|
||||
final Abi wasmAbi = Abi.values[kWasmAbiEnumIndex];
|
||||
final entry = abiIntegerMapping.entries
|
||||
.firstWhere((e) => constantAbis[e.key] == wasmAbi);
|
||||
return (entry.value as InstanceConstant)
|
||||
.classNode
|
||||
.getThisType(coreTypes, Nullability.nonNullable);
|
||||
}
|
||||
|
||||
/// Converts an FFI type like `InterfaceType(Int8)` to the corresponding Wasm
|
||||
/// type (`InterfaceType(WasmI32)`) according to emscripten Wasm ABI.
|
||||
///
|
||||
|
@ -353,8 +373,8 @@ class WasmFfiNativeTransformer extends FfiNativeTransformer {
|
|||
if (ffiType is! InterfaceType) {
|
||||
throw 'Native type is not an interface type: $ffiType';
|
||||
}
|
||||
final Class nativeClass = ffiType.classNode;
|
||||
final NativeType nativeType_ = getType(nativeClass)!;
|
||||
ffiType = _getFixedWidthIntegerFromAbiSpecificInteger(ffiType);
|
||||
final NativeType nativeType_ = getType(ffiType.classNode)!;
|
||||
|
||||
switch (nativeType_) {
|
||||
case NativeType.kInt8:
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:dart2wasm/translator.dart';
|
|||
import 'package:kernel/ast.dart';
|
||||
|
||||
import 'package:wasm_builder/wasm_builder.dart' as w;
|
||||
import 'abi.dart' show kWasmAbiEnumIndex;
|
||||
|
||||
typedef CodeGenCallback = void Function(w.Instructions);
|
||||
|
||||
|
@ -19,10 +20,6 @@ typedef CodeGenCallback = void Function(w.Instructions);
|
|||
class Intrinsifier {
|
||||
final CodeGenerator codeGen;
|
||||
|
||||
// The ABI type sizes are the same for 32-bit Wasm as for 32-bit ARM, so we
|
||||
// can just use an ABI enum index corresponding to a 32-bit ARM platform.
|
||||
static const int abiEnumIndex = 0; // androidArm
|
||||
|
||||
static const w.ValueType boolType = w.NumType.i32;
|
||||
static const w.ValueType intType = w.NumType.i64;
|
||||
static const w.ValueType doubleType = w.NumType.f64;
|
||||
|
@ -487,7 +484,7 @@ class Intrinsifier {
|
|||
} else if (arg is StaticInvocation) {
|
||||
if (arg.target.enclosingLibrary.name == "dart.ffi" &&
|
||||
arg.name.text == "_abi") {
|
||||
constIndex = abiEnumIndex;
|
||||
constIndex = kWasmAbiEnumIndex;
|
||||
}
|
||||
}
|
||||
if (constIndex != null) {
|
||||
|
|
|
@ -924,14 +924,21 @@ class FfiTransformer extends Transformer {
|
|||
functionType: numMultiplication.getterType as FunctionType);
|
||||
}
|
||||
|
||||
Iterable<MapConstant> getAbiSpecificIntegerMappingAnnotations(Class node) {
|
||||
return node.annotations
|
||||
MapConstant? getAbiSpecificIntegerMappingAnnotation(Class node) {
|
||||
final annotations = node.annotations
|
||||
.whereType<ConstantExpression>()
|
||||
.map((e) => e.constant)
|
||||
.whereType<InstanceConstant>()
|
||||
.where((e) => e.classNode == abiSpecificIntegerMappingClass)
|
||||
.map((instanceConstant) =>
|
||||
instanceConstant.fieldValues.values.single as MapConstant);
|
||||
instanceConstant.fieldValues.values.single as MapConstant)
|
||||
.toList();
|
||||
|
||||
// There can be at most one annotation (checked by `_FfiDefinitionTransformer`)
|
||||
if (annotations.length == 1) {
|
||||
return annotations[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Generates an expression performing an Abi specific integer load or store.
|
||||
|
|
|
@ -51,14 +51,14 @@ abstract class NativeTypeCfe {
|
|||
}
|
||||
if (transformer.isAbiSpecificIntegerSubtype(dartType)) {
|
||||
final clazz = (dartType as InterfaceType).classNode;
|
||||
final mappingConstants =
|
||||
transformer.getAbiSpecificIntegerMappingAnnotations(clazz);
|
||||
if (alreadyInAbiSpecificType || mappingConstants.length != 1) {
|
||||
final mappingConstant =
|
||||
transformer.getAbiSpecificIntegerMappingAnnotation(clazz);
|
||||
if (alreadyInAbiSpecificType || mappingConstant == null) {
|
||||
// Unsupported mapping.
|
||||
return AbiSpecificNativeTypeCfe({}, clazz);
|
||||
}
|
||||
final mapping =
|
||||
Map.fromEntries(mappingConstants.first.entries.map((e) => MapEntry(
|
||||
Map.fromEntries(mappingConstant.entries.map((e) => MapEntry(
|
||||
transformer.constantAbis[e.key]!,
|
||||
NativeTypeCfe(
|
||||
transformer,
|
||||
|
|
|
@ -39,7 +39,7 @@ external int addUint64(int a, int b);
|
|||
@FfiNative<Bool Function(Bool)>("ffi.negateBool")
|
||||
external bool negateBool(bool b);
|
||||
|
||||
@FfiNative<Bool Function(Int32)>("ffi.boolReturn")
|
||||
@FfiNative<Bool Function(Int)>("ffi.boolReturn")
|
||||
external bool boolReturn(int b);
|
||||
|
||||
@FfiNative<Void Function()>("ffi.toggleBool")
|
||||
|
@ -48,6 +48,52 @@ external void toggleBool();
|
|||
@FfiNative<Double Function(Double)>("ffi.sqrt")
|
||||
external double sqrt(double d);
|
||||
|
||||
@FfiNative<Char Function(Char)>("ffi.incrementChar")
|
||||
external int incrementChar(int a);
|
||||
|
||||
@FfiNative<UnsignedChar Function(UnsignedChar)>("ffi.incrementUnsignedChar")
|
||||
external int incrementUnsignedChar(int a);
|
||||
|
||||
@FfiNative<SignedChar Function(SignedChar)>("ffi.incrementSignedChar")
|
||||
external int incrementSignedChar(int a);
|
||||
|
||||
@FfiNative<Short Function(Short)>("ffi.incrementShort")
|
||||
external int incrementShort(int a);
|
||||
|
||||
@FfiNative<UnsignedShort Function(UnsignedShort)>("ffi.incrementUnsignedShort")
|
||||
external int incrementUnsignedShort(int a);
|
||||
|
||||
@FfiNative<Int Function(Int)>("ffi.incrementInt")
|
||||
external int incrementInt(int a);
|
||||
|
||||
@FfiNative<UnsignedInt Function(UnsignedInt)>("ffi.incrementUnsignedInt")
|
||||
external int incrementUnsignedInt(int a);
|
||||
|
||||
@FfiNative<Long Function(Long)>("ffi.incrementLong")
|
||||
external int incrementLong(int a);
|
||||
|
||||
@FfiNative<UnsignedLong Function(UnsignedLong)>("ffi.incrementUnsignedLong")
|
||||
external int incrementUnsignedLong(int a);
|
||||
|
||||
@FfiNative<LongLong Function(LongLong)>("ffi.incrementLongLong")
|
||||
external int incrementLongLong(int a);
|
||||
|
||||
@FfiNative<UnsignedLongLong Function(UnsignedLongLong)>(
|
||||
"ffi.incrementUnsignedLongLong")
|
||||
external int incrementUnsignedLongLong(int a);
|
||||
|
||||
@FfiNative<IntPtr Function(IntPtr)>("ffi.incrementIntPtr")
|
||||
external int incrementIntPtr(int a);
|
||||
|
||||
@FfiNative<UintPtr Function(UintPtr)>("ffi.incrementUintPtr")
|
||||
external int incrementUintPtr(int a);
|
||||
|
||||
@FfiNative<Size Function(Size)>("ffi.incrementSize")
|
||||
external int incrementSize(int a);
|
||||
|
||||
@FfiNative<WChar Function(WChar)>("ffi.incrementWchar")
|
||||
external int incrementWchar(int a);
|
||||
|
||||
class MyStruct extends Struct implements NativeFieldWrapperClass1 {
|
||||
@Double()
|
||||
external double x;
|
||||
|
@ -104,4 +150,20 @@ void main() {
|
|||
clearStruct(struct_);
|
||||
Expect.equals(struct_.ref.x, 0.0);
|
||||
Expect.equals(struct_.ref.y, 0);
|
||||
|
||||
Expect.equals(incrementChar(1), 2);
|
||||
Expect.equals(incrementUnsignedChar(3), 4);
|
||||
Expect.equals(incrementSignedChar(5), 6);
|
||||
Expect.equals(incrementShort(7), 8);
|
||||
Expect.equals(incrementUnsignedShort(9), 10);
|
||||
Expect.equals(incrementInt(11), 12);
|
||||
Expect.equals(incrementUnsignedInt(13), 14);
|
||||
Expect.equals(incrementLong(15), 16);
|
||||
Expect.equals(incrementUnsignedLong(17), 18);
|
||||
Expect.equals(incrementLongLong(19), 20);
|
||||
Expect.equals(incrementUnsignedLongLong(21), 22);
|
||||
Expect.equals(incrementIntPtr(23), 24);
|
||||
Expect.equals(incrementUintPtr(25), 26);
|
||||
Expect.equals(incrementSize(27), 28);
|
||||
Expect.equals(incrementWchar(29), 30);
|
||||
}
|
||||
|
|
|
@ -88,3 +88,78 @@ bool boolReturn(int a) {
|
|||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
char incrementChar(char a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
unsigned char incrementUnsignedChar(unsigned char a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
signed char incrementSignedChar(signed char a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
short incrementShort(short a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
unsigned short incrementUnsignedShort(unsigned short a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int incrementInt(int a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
unsigned int incrementUnsignedInt(unsigned int a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
long incrementLong(long a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
unsigned long incrementUnsignedLong(unsigned long a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
long long incrementLongLong(long long a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
unsigned long long incrementUnsignedLongLong(unsigned long long a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
intptr_t incrementIntPtr(intptr_t a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
uintptr_t incrementUintPtr(uintptr_t a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
size_t incrementSize(size_t a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
wchar_t incrementWchar(wchar_t a) {
|
||||
return a + 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue