mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 11:11:05 +00:00
[cfe/ffi] Support missing Abi
s in NativeTypeCfe
When ABI-specific integers are introduced, their mappings can be partial. We need to account for this in the transformation and the code we generate. In the transformation, all sizes and offsets become nullable. In the generated code we add `null` constants and a call to check whether the value is not-null at runtime. Note that with only this CL we can not generate nulls yet, because all size and offset mappings are still complete. TEST=pkg/front_end/testcases/nnbd/ffi* TEST=tests/ffi* Bug: https://github.com/dart-lang/sdk/issues/42563 Change-Id: I80d45f3f52001670bc0679a033f7daa22198d55e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221631 Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
eea0e48f6b
commit
734eb8e891
|
@ -234,6 +234,7 @@ class FfiTransformer extends Transformer {
|
|||
final Procedure lookupFunctionTearoff;
|
||||
final Procedure getNativeFieldFunction;
|
||||
final Procedure reachabilityFenceFunction;
|
||||
final Procedure checkAbiSpecificIntegerMappingFunction;
|
||||
|
||||
late final InterfaceType nativeFieldWrapperClass1Type;
|
||||
late final InterfaceType voidType;
|
||||
|
@ -417,7 +418,9 @@ class FfiTransformer extends Transformer {
|
|||
getNativeFieldFunction = index.getTopLevelProcedure(
|
||||
'dart:nativewrappers', '_getNativeField'),
|
||||
reachabilityFenceFunction =
|
||||
index.getTopLevelProcedure('dart:_internal', 'reachabilityFence') {
|
||||
index.getTopLevelProcedure('dart:_internal', 'reachabilityFence'),
|
||||
checkAbiSpecificIntegerMappingFunction = index.getTopLevelProcedure(
|
||||
'dart:ffi', "_checkAbiSpecificIntegerMapping") {
|
||||
nativeFieldWrapperClass1Type = nativeFieldWrapperClass1Class.getThisType(
|
||||
coreTypes, Nullability.nonNullable);
|
||||
voidType = nativeTypesClasses[NativeType.kVoid]!
|
||||
|
@ -453,7 +456,7 @@ class FfiTransformer extends Transformer {
|
|||
/// [Bool] -> [bool]
|
||||
/// [Void] -> [void]
|
||||
/// [Pointer]<T> -> [Pointer]<T>
|
||||
/// T extends [Pointer] -> T
|
||||
/// T extends [Compound] -> T
|
||||
/// [Handle] -> [Object]
|
||||
/// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
|
||||
/// where DartRepresentationOf(Tn) -> Sn
|
||||
|
@ -535,27 +538,42 @@ class FfiTransformer extends Transformer {
|
|||
InterfaceType _listOfIntType() => InterfaceType(
|
||||
listClass, Nullability.legacy, [coreTypes.intLegacyRawType]);
|
||||
|
||||
ConstantExpression intListConstantExpression(List<int> values) =>
|
||||
ConstantExpression intListConstantExpression(List<int?> values) =>
|
||||
ConstantExpression(
|
||||
ListConstant(coreTypes.intLegacyRawType,
|
||||
[for (var v in values) IntConstant(v)]),
|
||||
ListConstant(coreTypes.intLegacyRawType, [
|
||||
for (var v in values)
|
||||
if (v != null) IntConstant(v) else NullConstant()
|
||||
]),
|
||||
_listOfIntType());
|
||||
|
||||
/// Expression that queries VM internals at runtime to figure out on which ABI
|
||||
/// we are.
|
||||
Expression runtimeBranchOnLayout(Map<Abi, int> values) {
|
||||
return InstanceInvocation(
|
||||
Expression runtimeBranchOnLayout(Map<Abi, int?> values) {
|
||||
final result = InstanceInvocation(
|
||||
InstanceAccessKind.Instance,
|
||||
intListConstantExpression([
|
||||
for (final abi in Abi.values) values[abi]!,
|
||||
for (final abi in Abi.values) values[abi],
|
||||
]),
|
||||
listElementAt.name,
|
||||
Arguments([StaticInvocation(abiMethod, Arguments([]))]),
|
||||
interfaceTarget: listElementAt,
|
||||
functionType: Substitution.fromInterfaceType(_listOfIntType())
|
||||
.substituteType(listElementAt.getterType) as FunctionType);
|
||||
if (values.isPartial) {
|
||||
return checkAbiSpecificIntegerMapping(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Expression checkAbiSpecificIntegerMapping(Expression nullableExpression) =>
|
||||
StaticInvocation(
|
||||
checkAbiSpecificIntegerMappingFunction,
|
||||
Arguments(
|
||||
[nullableExpression],
|
||||
types: [InterfaceType(intClass, Nullability.nonNullable)],
|
||||
),
|
||||
);
|
||||
|
||||
/// Generates an expression that returns a new `Pointer<dartType>` offset
|
||||
/// by [offset] from [pointer].
|
||||
///
|
||||
|
@ -819,3 +837,8 @@ bool importsFfi(Component component, List<Library> libraries) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extension on Map<Abi, Object?> {
|
||||
bool get isPartial =>
|
||||
[for (final abi in Abi.values) this[abi]].contains(null);
|
||||
}
|
||||
|
|
|
@ -448,9 +448,8 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
|||
// This class is invalid, but continue reporting other errors on it.
|
||||
success = false;
|
||||
} else {
|
||||
final DartType nativeType = InterfaceType(
|
||||
nativeTypesClasses[_getFieldType(nativeTypeAnnos.first)!]!,
|
||||
Nullability.legacy);
|
||||
final DartType nativeType =
|
||||
InterfaceType(nativeTypeAnnos.first, Nullability.legacy);
|
||||
final DartType? shouldBeDartType = convertNativeTypeToDartType(
|
||||
nativeType,
|
||||
allowCompounds: true,
|
||||
|
@ -704,7 +703,6 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
|||
|
||||
static const vmFfiStructFields = "vm:ffi:struct-fields";
|
||||
|
||||
// return value is nullable.
|
||||
InstanceConstant? _compoundAnnotatedFields(Class node) {
|
||||
for (final annotation in node.annotations) {
|
||||
if (annotation is ConstantExpression) {
|
||||
|
@ -774,7 +772,6 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
|||
return UnionNativeTypeCfe(compoundClass, members);
|
||||
}
|
||||
|
||||
// packing is `int?`.
|
||||
void _annoteCompoundWithFields(
|
||||
Class node, List<NativeTypeCfe> types, int? packing) {
|
||||
List<Constant> constants =
|
||||
|
@ -794,8 +791,13 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
|||
InterfaceType(pragmaClass, Nullability.nonNullable, [])));
|
||||
}
|
||||
|
||||
void _generateMethodsForField(Class node, Field field, NativeTypeCfe type,
|
||||
Map<Abi, int> offsets, bool unalignedAccess, IndexedClass? indexedClass) {
|
||||
void _generateMethodsForField(
|
||||
Class node,
|
||||
Field field,
|
||||
NativeTypeCfe type,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
IndexedClass? indexedClass) {
|
||||
// TODO(johnniwinther): Avoid passing [indexedClass]. When compiling
|
||||
// incrementally, [field] should already carry the references from
|
||||
// [indexedClass].
|
||||
|
@ -846,7 +848,7 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
|||
/// If sizes are not supplied still emits a field so that the use site
|
||||
/// transformer can still rewrite to it.
|
||||
void _addSizeOfField(Class compound, IndexedClass? indexedClass,
|
||||
[Map<Abi, int>? sizes = null]) {
|
||||
[Map<Abi, int?>? sizes = null]) {
|
||||
if (sizes == null) {
|
||||
sizes = {for (var abi in Abi.values) abi: 0};
|
||||
}
|
||||
|
|
|
@ -52,12 +52,12 @@ abstract class NativeTypeCfe {
|
|||
}
|
||||
|
||||
/// The size in bytes per [Abi].
|
||||
Map<Abi, int> get size;
|
||||
Map<Abi, int?> get size;
|
||||
|
||||
/// The alignment inside structs in bytes per [Abi].
|
||||
///
|
||||
/// This is not the alignment on stack, this is only calculated in the VM.
|
||||
Map<Abi, int> get alignment;
|
||||
Map<Abi, int?> get alignment;
|
||||
|
||||
/// Generates a Constant representing the type which is consumed by the VM.
|
||||
///
|
||||
|
@ -70,7 +70,7 @@ abstract class NativeTypeCfe {
|
|||
///
|
||||
/// Takes [transformer] to be able to lookup classes and methods.
|
||||
ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
|
||||
Map<Abi, int> offsets, bool unalignedAccess, FfiTransformer transformer);
|
||||
Map<Abi, int?> offsets, bool unalignedAccess, FfiTransformer transformer);
|
||||
|
||||
/// Generates the return statement for a compound field setter with this type.
|
||||
///
|
||||
|
@ -78,7 +78,7 @@ abstract class NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer);
|
||||
|
@ -90,7 +90,7 @@ class InvalidNativeTypeCfe implements NativeTypeCfe {
|
|||
InvalidNativeTypeCfe(this.reason);
|
||||
|
||||
@override
|
||||
Map<Abi, int> get alignment => throw reason;
|
||||
Map<Abi, int?> get alignment => throw reason;
|
||||
|
||||
@override
|
||||
Constant generateConstant(FfiTransformer transformer) => throw reason;
|
||||
|
@ -99,7 +99,7 @@ class InvalidNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateGetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
FfiTransformer transformer) =>
|
||||
throw reason;
|
||||
|
@ -108,14 +108,14 @@ class InvalidNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer) =>
|
||||
throw reason;
|
||||
|
||||
@override
|
||||
Map<Abi, int> get size => throw reason;
|
||||
Map<Abi, int?> get size => throw reason;
|
||||
}
|
||||
|
||||
class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
||||
|
@ -126,7 +126,7 @@ class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
|||
PrimitiveNativeTypeCfe(this.nativeType, this.clazz);
|
||||
|
||||
@override
|
||||
Map<Abi, int> get size {
|
||||
Map<Abi, int?> get size {
|
||||
final int size = nativeTypeSizes[nativeType]!;
|
||||
if (size == WORD_SIZE) {
|
||||
return wordSize;
|
||||
|
@ -147,7 +147,7 @@ class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
|||
bool get isFloat =>
|
||||
nativeType == NativeType.kFloat || nativeType == NativeType.kDouble;
|
||||
|
||||
bool isUnaligned(Map<Abi, int> offsets) {
|
||||
bool isUnaligned(Map<Abi, int?> offsets) {
|
||||
final alignments = alignment;
|
||||
for (final abi in offsets.keys) {
|
||||
final offset = offsets[abi]!;
|
||||
|
@ -168,7 +168,7 @@ class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateGetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
FfiTransformer transformer) =>
|
||||
ReturnStatement(StaticInvocation(
|
||||
|
@ -191,7 +191,7 @@ class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer) =>
|
||||
|
@ -210,10 +210,10 @@ class PrimitiveNativeTypeCfe implements NativeTypeCfe {
|
|||
|
||||
class PointerNativeTypeCfe implements NativeTypeCfe {
|
||||
@override
|
||||
Map<Abi, int> get size => wordSize;
|
||||
Map<Abi, int?> get size => wordSize;
|
||||
|
||||
@override
|
||||
Map<Abi, int> get alignment => wordSize;
|
||||
Map<Abi, int?> get alignment => wordSize;
|
||||
|
||||
@override
|
||||
Constant generateConstant(FfiTransformer transformer) => TypeLiteralConstant(
|
||||
|
@ -231,7 +231,7 @@ class PointerNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateGetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
FfiTransformer transformer) =>
|
||||
ReturnStatement(StaticInvocation(
|
||||
|
@ -259,7 +259,7 @@ class PointerNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer) =>
|
||||
|
@ -281,15 +281,15 @@ class PointerNativeTypeCfe implements NativeTypeCfe {
|
|||
/// The layout of a `Struct` or `Union` in one [Abi].
|
||||
class CompoundLayout {
|
||||
/// Size of the entire struct or union.
|
||||
final int size;
|
||||
final int? size;
|
||||
|
||||
/// Alignment of struct or union when nested in a struct.
|
||||
final int alignment;
|
||||
final int? alignment;
|
||||
|
||||
/// Offset in bytes for each field, indexed by field number.
|
||||
///
|
||||
/// Always 0 for unions.
|
||||
final List<int> offsets;
|
||||
final List<int?> offsets;
|
||||
|
||||
CompoundLayout(this.size, this.alignment, this.offsets);
|
||||
}
|
||||
|
@ -304,11 +304,11 @@ abstract class CompoundNativeTypeCfe implements NativeTypeCfe {
|
|||
CompoundNativeTypeCfe._(this.clazz, this.members, this.layout);
|
||||
|
||||
@override
|
||||
Map<Abi, int> get size =>
|
||||
Map<Abi, int?> get size =>
|
||||
layout.map((abi, layout) => MapEntry(abi, layout.size));
|
||||
|
||||
@override
|
||||
Map<Abi, int> get alignment =>
|
||||
Map<Abi, int?> get alignment =>
|
||||
layout.map((abi, layout) => MapEntry(abi, layout.alignment));
|
||||
|
||||
@override
|
||||
|
@ -323,8 +323,12 @@ abstract class CompoundNativeTypeCfe implements NativeTypeCfe {
|
|||
/// );
|
||||
/// ```
|
||||
@override
|
||||
ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
|
||||
Map<Abi, int> offsets, bool unalignedAccess, FfiTransformer transformer) {
|
||||
ReturnStatement generateGetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
FfiTransformer transformer) {
|
||||
final constructor = clazz.constructors
|
||||
.firstWhere((c) => c.name == Name("#fromTypedDataBase"));
|
||||
|
||||
|
@ -351,7 +355,7 @@ abstract class CompoundNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer) =>
|
||||
|
@ -389,23 +393,23 @@ class StructNativeTypeCfe extends CompoundNativeTypeCfe {
|
|||
// NativeStructType::FromNativeTypes.
|
||||
static CompoundLayout _calculateLayout(
|
||||
List<NativeTypeCfe> types, int? packing, Abi abi) {
|
||||
int offset = 0;
|
||||
final offsets = <int>[];
|
||||
int structAlignment = 1;
|
||||
int? offset = 0;
|
||||
final offsets = <int?>[];
|
||||
int? structAlignment = 1;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
final int size = types[i].size[abi]!;
|
||||
int alignment = types[i].alignment[abi]!;
|
||||
if (packing != null && packing < alignment) {
|
||||
alignment = packing;
|
||||
final int? size = types[i].size[abi];
|
||||
int? alignment = types[i].alignment[abi];
|
||||
if (packing != null) {
|
||||
alignment = min(packing, alignment);
|
||||
}
|
||||
if (alignment > 0) {
|
||||
offset = _alignOffset(offset, alignment);
|
||||
if (alignment != null && alignment > 0) {
|
||||
offset = offset.align(alignment);
|
||||
}
|
||||
offsets.add(offset);
|
||||
offset += size;
|
||||
structAlignment = math.max(structAlignment, alignment);
|
||||
structAlignment = max(structAlignment, alignment);
|
||||
}
|
||||
final int size = _alignOffset(offset, structAlignment);
|
||||
final int? size = offset.align(structAlignment);
|
||||
return CompoundLayout(size, structAlignment, offsets);
|
||||
}
|
||||
}
|
||||
|
@ -425,15 +429,15 @@ class UnionNativeTypeCfe extends CompoundNativeTypeCfe {
|
|||
// Keep consistent with runtime/vm/compiler/ffi/native_type.cc
|
||||
// NativeUnionType::FromNativeTypes.
|
||||
static CompoundLayout _calculateLayout(List<NativeTypeCfe> types, Abi abi) {
|
||||
int unionSize = 1;
|
||||
int unionAlignment = 1;
|
||||
int? unionSize = 1;
|
||||
int? unionAlignment = 1;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
final int size = types[i].size[abi]!;
|
||||
int alignment = types[i].alignment[abi]!;
|
||||
unionSize = math.max(unionSize, size);
|
||||
unionAlignment = math.max(unionAlignment, alignment);
|
||||
final int? size = types[i].size[abi];
|
||||
int? alignment = types[i].alignment[abi];
|
||||
unionSize = max(unionSize, size);
|
||||
unionAlignment = max(unionAlignment, alignment);
|
||||
}
|
||||
final int size = _alignOffset(unionSize, unionAlignment);
|
||||
final int? size = unionSize.align(unionAlignment);
|
||||
return CompoundLayout(size, unionAlignment, List.filled(types.length, 0));
|
||||
}
|
||||
}
|
||||
|
@ -476,11 +480,11 @@ class ArrayNativeTypeCfe implements NativeTypeCfe {
|
|||
}
|
||||
|
||||
@override
|
||||
Map<Abi, int> get size =>
|
||||
Map<Abi, int?> get size =>
|
||||
elementType.size.map((abi, size) => MapEntry(abi, size * length));
|
||||
|
||||
@override
|
||||
Map<Abi, int> get alignment => elementType.alignment;
|
||||
Map<Abi, int?> get alignment => elementType.alignment;
|
||||
|
||||
// Note that we flatten multi dimensional arrays.
|
||||
@override
|
||||
|
@ -500,8 +504,12 @@ class ArrayNativeTypeCfe implements NativeTypeCfe {
|
|||
/// );
|
||||
/// ```
|
||||
@override
|
||||
ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
|
||||
Map<Abi, int> offsets, bool unalignedAccess, FfiTransformer transformer) {
|
||||
ReturnStatement generateGetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
FfiTransformer transformer) {
|
||||
InterfaceType typeArgument =
|
||||
(dartType as InterfaceType).typeArguments.single as InterfaceType;
|
||||
return ReturnStatement(ConstructorInvocation(
|
||||
|
@ -531,7 +539,7 @@ class ArrayNativeTypeCfe implements NativeTypeCfe {
|
|||
ReturnStatement generateSetterStatement(
|
||||
DartType dartType,
|
||||
int fileOffset,
|
||||
Map<Abi, int> offsets,
|
||||
Map<Abi, int?> offsets,
|
||||
bool unalignedAccess,
|
||||
VariableDeclaration argument,
|
||||
FfiTransformer transformer) =>
|
||||
|
@ -549,5 +557,71 @@ class ArrayNativeTypeCfe implements NativeTypeCfe {
|
|||
..fileOffset = fileOffset);
|
||||
}
|
||||
|
||||
int _alignOffset(int offset, int alignment) =>
|
||||
((offset + alignment - 1) ~/ alignment) * alignment;
|
||||
extension on int? {
|
||||
int? align(int? alignment) =>
|
||||
((this + alignment - 1) ~/ alignment) * alignment;
|
||||
|
||||
int? operator *(int? other) {
|
||||
final this_ = this;
|
||||
if (this_ == null) {
|
||||
return null;
|
||||
}
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
return this_ * other;
|
||||
}
|
||||
|
||||
int? operator +(int? other) {
|
||||
final this_ = this;
|
||||
if (this_ == null) {
|
||||
return null;
|
||||
}
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
return this_ + other;
|
||||
}
|
||||
|
||||
int? operator -(int? other) {
|
||||
final this_ = this;
|
||||
if (this_ == null) {
|
||||
return null;
|
||||
}
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
return this_ - other;
|
||||
}
|
||||
|
||||
int? operator ~/(int? other) {
|
||||
final this_ = this;
|
||||
if (this_ == null) {
|
||||
return null;
|
||||
}
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
return this_ ~/ other;
|
||||
}
|
||||
}
|
||||
|
||||
int? max(int? a, int? b) {
|
||||
if (a == null) {
|
||||
return null;
|
||||
}
|
||||
if (b == null) {
|
||||
return null;
|
||||
}
|
||||
return math.max(a, b);
|
||||
}
|
||||
|
||||
int? min(int? a, int? b) {
|
||||
if (a == null) {
|
||||
return null;
|
||||
}
|
||||
if (b == null) {
|
||||
return null;
|
||||
}
|
||||
return math.min(a, b);
|
||||
}
|
||||
|
|
|
@ -448,6 +448,16 @@ Pointer<Pointer<S>> _elementAtPointer<S extends NativeType>(
|
|||
Pointer<Pointer<S>> pointer, int index) =>
|
||||
Pointer.fromAddress(pointer.address + _intPtrSize * index);
|
||||
|
||||
@pragma("vm:prefer-inline")
|
||||
@pragma("vm:entry-point")
|
||||
T _checkAbiSpecificIntegerMapping<T>(T? object) {
|
||||
if (object == null) {
|
||||
throw ArgumentError(
|
||||
'AbiSpecificInteger is missing mapping for "${Abi.current()}".');
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
extension NativeFunctionPointer<NF extends Function>
|
||||
on Pointer<NativeFunction<NF>> {
|
||||
@patch
|
||||
|
|
Loading…
Reference in a new issue