mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 17:40:04 +00:00
Revert "[vm/ffi] Optimize @Native
calls"
This reverts commit e16bb210d2
.
Reason for revert: Indication this caused engine test
failures of the kind:
```
[0;32m[ RUN ] [mEmbedderA11yTest.A11yTreeIsConsistentUsingV1Callbacks
../../flutter/shell/platform/embedder/tests/embedder_a11y_unittests.cc:639: Failure
Expected equality of these values:
std::strncmp(kTooltip, node->tooltip, sizeof(kTooltip) - 1)
Which is: 116
0
```
Original change's description:
> [vm/ffi] Optimize `@Native` calls
>
> This CL removes static fields for storing the `@Native`'s function
> addresses. Instead, the function addresses are stored in the object
> pool for all archs except for ia32. ia32 has no AOT and no AppJit
> snapshots, so the addresses are directly embedded in the code.
>
> This CL removes the closure wrapping for `@Native`s. Instead of
> `pointer.asFunctionInternal()()` where `asFunction` returns a closure
> which contains the trampoline, the function is compiled to a body
> which contains the trampoline `Native()`. This is possible for
> `@Native`s because the dylib and symbol names are known statically.
>
> Doing the compilation in kernel_to_il instead of a CFE transform
> enables supporting static linking later. (The alternative would have
> been to transform in the cfe to a `@pragma('vm:cachable-idempotent')`
> instead of constructing the IL in kernel_to_il.
>
> To enable running resolution in ia32 in kernel_to_il.cc, the
> resolution function has been made available via
> `runtime/lib/ffi_dynamic_library.h`.
>
> Because the new calls are simply static calls, the TFA can figure
> out const arguments flowing to these calls. This leads to constant
> locations in the parameters to FfiCalls. So, this CL also introduces
> logic to move constants into `NativeLocation`s.
>
> TEST=runtime/vm/compiler/backend/il_test.cc
> TEST=tests/ffi/function_*_native_(leaf_)test.dart
> TEST=pkg/vm/testcases/transformations/ffi/ffinative_compound_return.dart
>
> Closes: https://github.com/dart-lang/sdk/issues/47625
> Closes: https://github.com/dart-lang/sdk/issues/51618
> Change-Id: Ic5d017005dedcedea40c455c4d24dbe774f91603
> CoreLibraryReviewExempt: Internal FFI implementation changes
> Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284300
> Commit-Queue: Daco Harkes <dacoharkes@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>
Change-Id: Icc87a6ca33bffecabb15c6b168a06ccc38c2fe5b
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333840
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
85e1bbf45c
commit
96921245f9
|
@ -1160,31 +1160,19 @@ class FfiTransformer extends Transformer {
|
|||
]))
|
||||
..fileOffset = fileOffset;
|
||||
|
||||
final possibleCompoundReturn = findCompoundReturnType(dartSignature);
|
||||
if (possibleCompoundReturn != null) {
|
||||
return invokeCompoundConstructor(
|
||||
asFunctionInternalInvocation, possibleCompoundReturn);
|
||||
if (dartSignature is FunctionType) {
|
||||
final returnType = dartSignature.returnType;
|
||||
if (returnType is InterfaceType) {
|
||||
final clazz = returnType.classNode;
|
||||
if (clazz.superclass == structClass || clazz.superclass == unionClass) {
|
||||
return invokeCompoundConstructor(asFunctionInternalInvocation, clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return asFunctionInternalInvocation;
|
||||
}
|
||||
|
||||
/// Returns the compound [Class] if a compound is returned, otherwise `null`.
|
||||
Class? findCompoundReturnType(DartType dartSignature) {
|
||||
if (dartSignature is! FunctionType) {
|
||||
return null;
|
||||
}
|
||||
final returnType = dartSignature.returnType;
|
||||
if (returnType is! InterfaceType) {
|
||||
return null;
|
||||
}
|
||||
final clazz = returnType.classNode;
|
||||
if (clazz.superclass == structClass || clazz.superclass == unionClass) {
|
||||
return clazz;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns
|
||||
/// - `true` if leaf
|
||||
/// - `false` if not leaf
|
||||
|
|
|
@ -183,6 +183,81 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
);
|
||||
}
|
||||
|
||||
// Create field holding the resolved native function pointer.
|
||||
//
|
||||
// For:
|
||||
// @FfiNative<IntPtr Function(Pointer<Void>)>('DoXYZ', isLeaf:true)
|
||||
// external int doXyz(NativeFieldWrapperClass1 obj);
|
||||
//
|
||||
// Create:
|
||||
// static final _doXyz$FfiNative$ptr =
|
||||
// Pointer<NativeFunction<IntPtr Function(Pointer<Void>)>>
|
||||
// .fromAddress(_ffi_resolver('..', 'DoXYZ', 1))
|
||||
// .asFunction<int Function(Pointer<Void>)>(isLeaf:true);
|
||||
Field _createResolvedFfiNativeField(
|
||||
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(
|
||||
assetName ?? StringConstant(currentLibrary.importUri.toString())),
|
||||
ConstantExpression(nativeFunctionName),
|
||||
ConstantExpression(IntConstant(numberNativeArgs)),
|
||||
]),
|
||||
functionType: resolverField.type as FunctionType)
|
||||
..fileOffset = fileOffset;
|
||||
|
||||
// _fromAddress<NativeFunction<Double Function(Double)>>(...)
|
||||
final functionPointerExpression = StaticInvocation(
|
||||
fromAddressInternal,
|
||||
Arguments(
|
||||
<Expression>[resolverInvocation],
|
||||
types: [nativeFunctionType],
|
||||
))
|
||||
..fileOffset = fileOffset;
|
||||
|
||||
final asFunctionInvocation = buildAsFunctionInternal(
|
||||
functionPointer: functionPointerExpression,
|
||||
dartSignature: dartFunctionType,
|
||||
nativeSignature: ffiFunctionType,
|
||||
isLeaf: isLeaf,
|
||||
fileOffset: fileOffset,
|
||||
);
|
||||
|
||||
// static final _doXyz$FfiNative$Ptr = ...
|
||||
final fieldName =
|
||||
Name('_$dartFunctionName\$FfiNative\$Ptr', currentLibrary);
|
||||
final functionPointerField = Field.immutable(fieldName,
|
||||
type: dartFunctionType,
|
||||
initializer: asFunctionInvocation,
|
||||
isStatic: true,
|
||||
isFinal: true,
|
||||
fileUri: fileUri,
|
||||
getterReference: currentLibraryIndex?.lookupGetterReference(fieldName))
|
||||
..fileOffset = fileOffset;
|
||||
|
||||
return functionPointerField;
|
||||
}
|
||||
|
||||
// Whether a parameter of [dartParameterType], passed as [ffiParameterType],
|
||||
// needs to be converted to Pointer.
|
||||
bool _requiresPointerConversion(
|
||||
|
@ -275,7 +350,7 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
// reachabilityFence(#t0);
|
||||
// } => #t1
|
||||
Expression _wrapArgumentsAndReturn({
|
||||
required StaticInvocation invocation,
|
||||
required FunctionInvocation invocation,
|
||||
required FunctionType dartFunctionType,
|
||||
required FunctionType ffiFunctionType,
|
||||
bool checkReceiverForNullptr = false,
|
||||
|
@ -412,8 +487,6 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
return validSignature;
|
||||
}
|
||||
|
||||
static const vmFfiNative = 'vm:ffi:native';
|
||||
|
||||
Procedure _transformProcedure(
|
||||
Procedure node,
|
||||
StringConstant nativeFunctionName,
|
||||
|
@ -435,135 +508,74 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
return node;
|
||||
}
|
||||
|
||||
final pragmaConstant = ConstantExpression(
|
||||
InstanceConstant(pragmaClass.reference, [], {
|
||||
pragmaName.fieldReference: StringConstant(vmFfiNative),
|
||||
pragmaOptions.fieldReference: InstanceConstant(
|
||||
nativeClass.reference,
|
||||
[ffiFunctionType],
|
||||
{
|
||||
nativeSymbolField.fieldReference: nativeFunctionName,
|
||||
nativeAssetField.fieldReference: assetName ??
|
||||
StringConstant(currentLibrary.importUri.toString()),
|
||||
nativeIsLeafField.fieldReference: BoolConstant(isLeaf),
|
||||
},
|
||||
)
|
||||
}),
|
||||
InterfaceType(
|
||||
pragmaClass,
|
||||
Nullability.nonNullable,
|
||||
[],
|
||||
),
|
||||
final parent = node.parent;
|
||||
|
||||
// static final _myMethod$FfiNative$Ptr = ..
|
||||
final resolvedField = _createResolvedFfiNativeField(
|
||||
'${node.name.text}\$${node.kind.name}',
|
||||
nativeFunctionName,
|
||||
assetName,
|
||||
isLeaf,
|
||||
wrappedDartFunctionType,
|
||||
ffiFunctionType,
|
||||
node.fileOffset,
|
||||
node.fileUri,
|
||||
);
|
||||
|
||||
final possibleCompoundReturn = findCompoundReturnType(dartFunctionType);
|
||||
if (dartFunctionType == wrappedDartFunctionType &&
|
||||
node.isStatic &&
|
||||
possibleCompoundReturn == null) {
|
||||
// We are not wrapping/unwrapping arguments or return value.
|
||||
node.addAnnotation(pragmaConstant);
|
||||
return node;
|
||||
}
|
||||
|
||||
// Introduce a new function as external with the annotation and give the
|
||||
// current function a body that does the wrapping/unwrapping.
|
||||
node.isExternal = false;
|
||||
|
||||
node.addAnnotation(ConstantExpression(
|
||||
InstanceConstant(pragmaClass.reference, [], {
|
||||
pragmaName.fieldReference: StringConstant("vm:prefer-inline"),
|
||||
pragmaOptions.fieldReference: NullConstant(),
|
||||
}),
|
||||
));
|
||||
|
||||
final parent = node.parent;
|
||||
var fileUri = currentLibrary.fileUri;
|
||||
// Add field to the parent the FfiNative function belongs to.
|
||||
if (parent is Class) {
|
||||
fileUri = parent.fileUri;
|
||||
parent.addField(resolvedField);
|
||||
} else if (parent is Library) {
|
||||
fileUri = parent.fileUri;
|
||||
}
|
||||
|
||||
int varCounter = 0;
|
||||
final nonWrappedFfiNative = Procedure(
|
||||
Name('_${node.name.text}\$${node.kind.name}\$FfiNative', currentLibrary),
|
||||
ProcedureKind.Method,
|
||||
FunctionNode(
|
||||
/*body=*/ null,
|
||||
requiredParameterCount: wrappedDartFunctionType.requiredParameterCount,
|
||||
positionalParameters: [
|
||||
for (final positionalParameter
|
||||
in wrappedDartFunctionType.positionalParameters)
|
||||
VariableDeclaration(
|
||||
/*name=*/ '#t${varCounter++}',
|
||||
type: positionalParameter,
|
||||
)..fileOffset = node.fileOffset,
|
||||
],
|
||||
returnType: wrappedDartFunctionType.returnType,
|
||||
)..fileOffset = node.fileOffset,
|
||||
fileUri: fileUri,
|
||||
isStatic: true,
|
||||
isExternal: true,
|
||||
)
|
||||
..isNonNullableByDefault = node.isNonNullableByDefault
|
||||
..fileOffset = node.fileOffset;
|
||||
nonWrappedFfiNative.addAnnotation(pragmaConstant);
|
||||
|
||||
// Add procedure to the parent the FfiNative function belongs to.
|
||||
if (parent is Class) {
|
||||
parent.addProcedure(nonWrappedFfiNative);
|
||||
} else if (parent is Library) {
|
||||
parent.addProcedure(nonWrappedFfiNative);
|
||||
parent.addField(resolvedField);
|
||||
} else {
|
||||
throw 'Unexpected parent of @Native function. '
|
||||
throw 'Unexpected parent of @FfiNative function. '
|
||||
'Expected Class or Library, but found ${parent}.';
|
||||
}
|
||||
|
||||
final nonWrappedInvocation = StaticInvocation(
|
||||
nonWrappedFfiNative,
|
||||
Arguments(argumentList),
|
||||
)..fileOffset = node.fileOffset;
|
||||
// _myFunction$FfiNative$Ptr(obj, x)
|
||||
final functionPointerInvocation = FunctionInvocation(
|
||||
FunctionAccessKind.FunctionType,
|
||||
StaticGet(resolvedField),
|
||||
Arguments(argumentList),
|
||||
functionType: wrappedDartFunctionType)
|
||||
..fileOffset = node.fileOffset;
|
||||
|
||||
Expression result = (wrappedDartFunctionType == dartFunctionType
|
||||
? nonWrappedInvocation
|
||||
? functionPointerInvocation
|
||||
: _wrapArgumentsAndReturn(
|
||||
invocation: nonWrappedInvocation,
|
||||
invocation: functionPointerInvocation,
|
||||
dartFunctionType: dartFunctionType,
|
||||
ffiFunctionType: ffiFunctionType,
|
||||
checkReceiverForNullptr: checkReceiverForNullptr,
|
||||
));
|
||||
if (possibleCompoundReturn != null) {
|
||||
result = invokeCompoundConstructor(result, possibleCompoundReturn);
|
||||
}
|
||||
|
||||
// => _myFunction$FfiNative$Ptr(
|
||||
// Pointer<Void>.fromAddress(_getNativeField(obj)), x)
|
||||
node.function.body = ReturnStatement(result)..parent = node.function;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Transform FfiNative instance methods.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// class MyNativeClass extends NativeFieldWrapperClass1 {
|
||||
// @Native<IntPtr Function(Pointer<Void>, IntPtr)>(symbol: 'MyClass_MyMethod')
|
||||
// @FfiNative<IntPtr Function(Pointer<Void>, IntPtr)>('MyClass_MyMethod')
|
||||
// external int myMethod(int x);
|
||||
// }
|
||||
//
|
||||
// Becomes, roughly:
|
||||
// ... {
|
||||
// static final _myMethod$FfiNative$Ptr = ...
|
||||
// static _myMethod$FfiNative(MyNativeClass self, int x)
|
||||
// => _myMethod$FfiNative$Ptr(
|
||||
// Pointer<Void>.fromAddress(_getNativeField(self)), x);
|
||||
// int myMethod(int x) => _myMethod$FfiNative(this, x);
|
||||
// }
|
||||
//
|
||||
// ... {
|
||||
// @pragma(
|
||||
// 'vm:ffi:native',
|
||||
// Native<IntPtr Function(Pointer<Void>, IntPtr)>(
|
||||
// symbol: 'MyClass_MyMethod',
|
||||
// assetId: '<library uri>',
|
||||
// ),
|
||||
// )
|
||||
// external int _myFunction$FfiNative(Pointer<Void> self, int x);
|
||||
//
|
||||
// @pragma('vm:prefer-inline')
|
||||
// int myMethod(int x) => _myMethod$FfiNative(_getNativeField(this), x);
|
||||
// static final _myMethod$FfiNative$Ptr = ...
|
||||
// int myMethod(int x)
|
||||
// => _myMethod$FfiNative$Ptr(
|
||||
// Pointer<Void>.fromAddress(_getNativeField(this)), x);
|
||||
// }
|
||||
Procedure _transformInstanceMethod(
|
||||
Procedure node,
|
||||
|
@ -597,26 +609,13 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
}
|
||||
|
||||
// Transform FfiNative static functions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// @Native<IntPtr Function(Pointer<Void>, IntPtr)>(symbol: 'MyFunction')
|
||||
// @FfiNative<IntPtr Function(Pointer<Void>, IntPtr)>('MyFunction')
|
||||
// external int myFunction(MyNativeClass obj, int x);
|
||||
//
|
||||
// Becomes, roughly:
|
||||
//
|
||||
// @pragma(
|
||||
// 'vm:ffi:native',
|
||||
// Native<IntPtr Function(Pointer<Void>, IntPtr)>(
|
||||
// symbol: 'MyFunction',
|
||||
// assetId: '<library uri>',
|
||||
// ),
|
||||
// )
|
||||
// external int _myFunction$FfiNative(Pointer<Void> self, int x);
|
||||
//
|
||||
// @pragma('vm:prefer-inline')
|
||||
// static final _myFunction$FfiNative$Ptr = ...
|
||||
// int myFunction(MyNativeClass obj, int x)
|
||||
// => _myFunction$FfiNative(
|
||||
// => myFunction$FfiNative$Ptr(
|
||||
// Pointer<Void>.fromAddress(_getNativeField(obj)), x);
|
||||
Procedure _transformStaticFunction(
|
||||
Procedure node,
|
||||
|
@ -649,7 +648,7 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
@override
|
||||
visitProcedure(Procedure node) {
|
||||
// Only transform functions that are external and have FfiNative annotation:
|
||||
// @Native<Double Function(Double)>(symbol: 'Math_sqrt')
|
||||
// @FfiNative<Double Function(Double)>('Math_sqrt')
|
||||
// external double _square_root(double x);
|
||||
final ffiNativeAnnotation =
|
||||
tryGetNativeAnnotation(node) ?? tryGetFfiNativeAnnotation(node);
|
||||
|
@ -662,6 +661,7 @@ class FfiNativeTransformer extends FfiTransformer {
|
|||
1, node.location?.file);
|
||||
return node;
|
||||
}
|
||||
node.isExternal = false;
|
||||
|
||||
node.annotations.remove(ffiNativeAnnotation);
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
|
|||
.where((c) =>
|
||||
c.superclass == structClass || c.superclass == unionClass)
|
||||
.toList();
|
||||
return invokeCompoundConstructors(replacement, compoundClasses);
|
||||
return _invokeCompoundConstructors(replacement, compoundClasses);
|
||||
} else if (target == allocateMethod) {
|
||||
final DartType nativeType = node.arguments.types[0];
|
||||
|
||||
|
@ -387,7 +387,7 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
|
|||
return node;
|
||||
}
|
||||
|
||||
Expression invokeCompoundConstructors(
|
||||
Expression _invokeCompoundConstructors(
|
||||
Expression nestedExpression, List<Class> compoundClasses) =>
|
||||
compoundClasses
|
||||
.distinct()
|
||||
|
@ -748,7 +748,7 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
|
|||
.map((t) => t.classNode)
|
||||
.where((c) => c.superclass == structClass || c.superclass == unionClass)
|
||||
.toList();
|
||||
return invokeCompoundConstructors(replacement, compoundClasses);
|
||||
return _invokeCompoundConstructors(replacement, compoundClasses);
|
||||
}
|
||||
|
||||
Expression _replaceGetRef(StaticInvocation node) {
|
||||
|
|
|
@ -1,144 +1,129 @@
|
|||
library #lib;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:nativewrappers" as nat;
|
||||
import "dart:ffi" as ffi;
|
||||
import "dart:nativewrappers" as nat;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:ffi";
|
||||
import "dart:nativewrappers";
|
||||
|
||||
abstract class Classy extends core::Object {
|
||||
[@vm.unboxing-info.metadata=(i)->i] @#C6
|
||||
external static method returnIntPtrStatic([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 222)] core::int x) → core::int;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (core::int) → core::int _returnIntPtrStatic$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.unboxing-info.metadata=()->i] static method returnIntPtrStatic() → core::int
|
||||
return self::Classy::_returnIntPtrStatic$Method$FfiNative$Ptr(#C4){(core::int) → core::int};
|
||||
}
|
||||
class NativeClassy extends nat::NativeFieldWrapperClass1 {
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>, core::int) → void _goodHasReceiverPointer$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::int) → void, (ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (self::NativeClassy, core::int) → void _goodHasReceiverHandle$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(self::NativeClassy, core::int) → void, (ffi::Handle, ffi::IntPtr) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::IntPtr) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (self::NativeClassy, ffi::Pointer<ffi::Void>) → void _goodHasReceiverHandleAndPtr$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(self::NativeClassy, ffi::Pointer<ffi::Void>) → void, (ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (self::NativeClassy, self::NativeClassy) → void _goodHasReceiverHandleAndHandle$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(self::NativeClassy, self::NativeClassy) → void, (ffi::Handle, ffi::Handle) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::Handle) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>, self::NativeClassy) → void _goodHasReceiverPtrAndHandle$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, self::NativeClassy) → void, (ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>, core::bool) → core::Object? _meh$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → core::Object?, (ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>) → core::bool _blah$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void>) → ffi::Bool>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>) → ffi::Bool>*>(ffi::_ffi_resolver(#C1, #C5, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>) → core::bool _myField$Getter$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void>) → ffi::Bool>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>) → ffi::Bool>*>(ffi::_ffi_resolver(#C1, #C5, #C3){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure] static final field (ffi::Pointer<ffi::Void>, core::bool) → void _myField$Setter$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → void, (ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C5, #C6){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
synthetic constructor •() → self::NativeClassy
|
||||
: super nat::NativeFieldWrapperClass1::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] @#C9
|
||||
method goodHasReceiverPointer() → void
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] method goodHasReceiverPointer() → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t1 = this;
|
||||
final core::int #t2 = #C10;
|
||||
final void #t3 = self::NativeClassy::_goodHasReceiverPointer$Method$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::int #t2 = #C7;
|
||||
final void #t3 = self::NativeClassy::_goodHasReceiverPointer$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t1);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t2);
|
||||
} =>#pointerAddress), #t2){(ffi::Pointer<ffi::Void>, core::int) → void};
|
||||
_in::reachabilityFence(#t1);
|
||||
} =>#t3;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] @#C9
|
||||
method goodHasReceiverHandle() → void
|
||||
return self::NativeClassy::_goodHasReceiverHandle$Method$FfiNative(this, #C10);
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] @#C9
|
||||
method goodHasReceiverHandleAndPtr([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] method goodHasReceiverHandle() → void
|
||||
return self::NativeClassy::_goodHasReceiverHandle$Method$FfiNative$Ptr(this, #C7){(self::NativeClassy, core::int) → void};
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] method goodHasReceiverHandleAndPtr([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
return block {
|
||||
final self::NativeClassy #t4 = this;
|
||||
final nat::NativeFieldWrapperClass1 #t5 = v;
|
||||
final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$Method$FfiNative(#t4, [@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>([@vm.inferred-type.metadata=int] nat::_getNativeField(#t5)));
|
||||
final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$Method$FfiNative$Ptr(#t4, ffi::_fromAddress<ffi::Void>([@vm.inferred-type.metadata=int] nat::_getNativeField(#t5))){(self::NativeClassy, ffi::Pointer<ffi::Void>) → void};
|
||||
_in::reachabilityFence(#t5);
|
||||
} =>#t6;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] @#C9
|
||||
method goodHasReceiverHandleAndHandle([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
return self::NativeClassy::_goodHasReceiverHandleAndHandle$Method$FfiNative(this, v);
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10] @#C9
|
||||
method goodHasReceiverPtrAndHandle([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] method goodHasReceiverHandleAndHandle([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
return self::NativeClassy::_goodHasReceiverHandleAndHandle$Method$FfiNative$Ptr(this, v){(self::NativeClassy, self::NativeClassy) → void};
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10] method goodHasReceiverPtrAndHandle([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy v) → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t7 = this;
|
||||
final self::NativeClassy #t8 = v;
|
||||
final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$Method$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t7);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t8);
|
||||
} =>#pointerAddress), #t8){(ffi::Pointer<ffi::Void>, self::NativeClassy) → void};
|
||||
_in::reachabilityFence(#t7);
|
||||
} =>#t9;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12] @#C9
|
||||
method meh() → core::String?
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12] method meh() → core::String?
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t10 = this;
|
||||
final core::bool #t11 = #C13;
|
||||
final core::String? #t12 = _in::unsafeCast<core::String?>(self::NativeClassy::_meh$Method$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::bool #t11 = #C10;
|
||||
final core::String? #t12 = _in::unsafeCast<core::String?>(self::NativeClassy::_meh$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t10);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t11));
|
||||
} =>#pointerAddress), #t11){(ffi::Pointer<ffi::Void>, core::bool) → core::Object?});
|
||||
_in::reachabilityFence(#t10);
|
||||
} =>#t12;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:13,getterSelectorId:14] @#C9
|
||||
method blah() → core::bool
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:13,getterSelectorId:14] method blah() → core::bool
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t13 = this;
|
||||
final core::bool #t14 = [@vm.inferred-type.metadata=dart.core::bool] self::NativeClassy::_blah$Method$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::bool #t14 = self::NativeClassy::_blah$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t13);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress));
|
||||
} =>#pointerAddress)){(ffi::Pointer<ffi::Void>) → core::bool};
|
||||
_in::reachabilityFence(#t13);
|
||||
} =>#t14;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:15,getterSelectorId:16] @#C9
|
||||
get myField() → core::bool
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:15,getterSelectorId:16] get myField() → core::bool
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t15 = this;
|
||||
final core::bool #t16 = [@vm.inferred-type.metadata=dart.core::bool] self::NativeClassy::_myField$Getter$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::bool #t16 = self::NativeClassy::_myField$Getter$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t15);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress));
|
||||
} =>#pointerAddress)){(ffi::Pointer<ffi::Void>) → core::bool};
|
||||
_in::reachabilityFence(#t15);
|
||||
} =>#t16;
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:15,getterSelectorId:16] @#C9
|
||||
set myField([@vm.inferred-arg-type.metadata=dart.core::bool] core::bool value) → void
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:15,getterSelectorId:16] set myField([@vm.inferred-arg-type.metadata=dart.core::bool] core::bool value) → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t17 = this;
|
||||
final core::bool #t18 = value;
|
||||
final void #t19 = self::NativeClassy::_myField$Setter$FfiNative([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::Void>( block {
|
||||
final void #t19 = self::NativeClassy::_myField$Setter$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = [@vm.inferred-type.metadata=int] nat::_getNativeField(#t17);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C11){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C12);
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] #pointerAddress.{core::Object::==}(#C8){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C9);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t18);
|
||||
} =>#pointerAddress), #t18){(ffi::Pointer<ffi::Void>, core::bool) → void};
|
||||
_in::reachabilityFence(#t17);
|
||||
} =>#t19;
|
||||
[@vm.unboxing-info.metadata=(b,i)->b] @#C16
|
||||
external static method _goodHasReceiverPointer$Method$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0, [@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 175)] core::int #t1) → void;
|
||||
[@vm.unboxing-info.metadata=(b,i)->b] @#C18
|
||||
external static method _goodHasReceiverHandle$Method$FfiNative([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy #t0, [@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 175)] core::int #t1) → void;
|
||||
@#C20
|
||||
external static method _goodHasReceiverHandleAndPtr$Method$FfiNative([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy #t0, [@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t1) → void;
|
||||
@#C22
|
||||
external static method _goodHasReceiverHandleAndHandle$Method$FfiNative([@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy #t0, [@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy #t1) → void;
|
||||
@#C24
|
||||
external static method _goodHasReceiverPtrAndHandle$Method$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0, [@vm.inferred-arg-type.metadata=#lib::NativeClassy] self::NativeClassy #t1) → void;
|
||||
@#C26
|
||||
external static method _meh$Method$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0, [@vm.inferred-arg-type.metadata=dart.core::bool (value: true)] core::bool #t1) → core::Object?;
|
||||
@#C28
|
||||
external static method _blah$Method$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0) → core::bool;
|
||||
@#C30
|
||||
external static method _myField$Getter$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0) → core::bool;
|
||||
@#C32
|
||||
external static method _myField$Setter$FfiNative([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] ffi::Pointer<ffi::Void> #t0, [@vm.inferred-arg-type.metadata=dart.core::bool] core::bool #t1) → void;
|
||||
}
|
||||
[@vm.unboxing-info.metadata=(i)->i]@#C6
|
||||
external static method returnIntPtr([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 13)] core::int x) → core::int;
|
||||
[@vm.unboxing-info.metadata=(i)->i]@#C34
|
||||
external static method returnIntPtrLeaf([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 37)] core::int x) → core::int;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure]static final field (core::int) → core::int _returnIntPtr$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure]static final field (core::int) → core::int _returnIntPtrLeaf$Method$FfiNative$Ptr = [@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
[@vm.unboxing-info.metadata=()->i]static method returnIntPtr() → core::int
|
||||
return self::_returnIntPtr$Method$FfiNative$Ptr(#C11){(core::int) → core::int};
|
||||
[@vm.unboxing-info.metadata=()->i]static method returnIntPtrLeaf() → core::int
|
||||
return self::_returnIntPtrLeaf$Method$FfiNative$Ptr(#C12){(core::int) → core::int};
|
||||
static method main() → void {
|
||||
self::returnIntPtr(13);
|
||||
self::returnIntPtrLeaf(37);
|
||||
self::Classy::returnIntPtrStatic(222);
|
||||
self::returnIntPtr();
|
||||
self::returnIntPtrLeaf();
|
||||
self::Classy::returnIntPtrStatic();
|
||||
[@vm.direct-call.metadata=#lib::NativeClassy.goodHasReceiverPointer] [@vm.inferred-type.metadata=!? (skip check)] new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverPointer}(){(core::int) → void};
|
||||
[@vm.direct-call.metadata=#lib::NativeClassy.goodHasReceiverHandle] [@vm.inferred-type.metadata=!? (skip check)] new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverHandle}(){(core::int) → void};
|
||||
[@vm.direct-call.metadata=#lib::NativeClassy.goodHasReceiverHandleAndPtr] [@vm.inferred-type.metadata=!? (skip check)] new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverHandleAndPtr}(new self::NativeClassy::•()){(self::NativeClassy) → void};
|
||||
|
@ -150,38 +135,16 @@ static method main() → void {
|
|||
[@vm.direct-call.metadata=#lib::NativeClassy.myField] [@vm.inferred-type.metadata=!? (skip check)] new self::NativeClassy::•().{self::NativeClassy::myField} = !b;
|
||||
}
|
||||
constants {
|
||||
#C1 = "vm:ffi:native"
|
||||
#C1 = "#lib"
|
||||
#C2 = "ReturnIntPtr"
|
||||
#C3 = "#lib"
|
||||
#C4 = false
|
||||
#C5 = ffi::Native<(ffi::IntPtr) → ffi::IntPtr> {symbol:#C2, assetId:#C3, isLeaf:#C4}
|
||||
#C6 = core::pragma {name:#C1, options:#C5}
|
||||
#C7 = "vm:prefer-inline"
|
||||
#C8 = null
|
||||
#C9 = core::pragma {name:#C7, options:#C8}
|
||||
#C10 = 175
|
||||
#C11 = 0
|
||||
#C12 = "A Dart object attempted to access a native peer, but the native peer has been collected (nullptr). This is usually the result of calling methods on a native-backed object when the native resources have already been disposed."
|
||||
#C13 = true
|
||||
#C14 = "doesntmatter"
|
||||
#C15 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C16 = core::pragma {name:#C1, options:#C15}
|
||||
#C17 = ffi::Native<(ffi::Handle, ffi::IntPtr) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C18 = core::pragma {name:#C1, options:#C17}
|
||||
#C19 = ffi::Native<(ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C20 = core::pragma {name:#C1, options:#C19}
|
||||
#C21 = ffi::Native<(ffi::Handle, ffi::Handle) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C22 = core::pragma {name:#C1, options:#C21}
|
||||
#C23 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C24 = core::pragma {name:#C1, options:#C23}
|
||||
#C25 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C26 = core::pragma {name:#C1, options:#C25}
|
||||
#C27 = ffi::Native<(ffi::Pointer<ffi::Void>) → ffi::Bool> {symbol:#C14, assetId:#C3, isLeaf:#C4}
|
||||
#C28 = core::pragma {name:#C1, options:#C27}
|
||||
#C29 = ffi::Native<(ffi::Pointer<ffi::Void>) → ffi::Bool> {symbol:#C14, assetId:#C3, isLeaf:#C13}
|
||||
#C30 = core::pragma {name:#C1, options:#C29}
|
||||
#C31 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void> {symbol:#C14, assetId:#C3, isLeaf:#C13}
|
||||
#C32 = core::pragma {name:#C1, options:#C31}
|
||||
#C33 = ffi::Native<(ffi::IntPtr) → ffi::IntPtr> {symbol:#C2, assetId:#C3, isLeaf:#C13}
|
||||
#C34 = core::pragma {name:#C1, options:#C33}
|
||||
#C3 = 1
|
||||
#C4 = 222
|
||||
#C5 = "doesntmatter"
|
||||
#C6 = 2
|
||||
#C7 = 175
|
||||
#C8 = 0
|
||||
#C9 = "A Dart object attempted to access a native peer, but the native peer has been collected (nullptr). This is usually the result of calling methods on a native-backed object when the native resources have already been disposed."
|
||||
#C10 = true
|
||||
#C11 = 13
|
||||
#C12 = 37
|
||||
}
|
||||
|
|
|
@ -1,143 +1,128 @@
|
|||
library #lib;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:nativewrappers" as nat;
|
||||
import "dart:ffi" as ffi;
|
||||
import "dart:nativewrappers" as nat;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
import "dart:ffi";
|
||||
import "dart:nativewrappers";
|
||||
|
||||
class Classy extends core::Object {
|
||||
static final field (core::int) → core::int _returnIntPtrStatic$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>(ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
synthetic constructor •() → self::Classy
|
||||
: super core::Object::•()
|
||||
;
|
||||
@#C6
|
||||
external static method returnIntPtrStatic(core::int x) → core::int;
|
||||
static method returnIntPtrStatic(core::int x) → core::int
|
||||
return self::Classy::_returnIntPtrStatic$Method$FfiNative$Ptr(x){(core::int) → core::int};
|
||||
}
|
||||
class NativeClassy extends nat::NativeFieldWrapperClass1 {
|
||||
static final field (ffi::Pointer<ffi::Void>, core::int) → void _goodHasReceiverPointer$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::int) → void, (ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (self::NativeClassy, core::int) → void _goodHasReceiverHandle$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, core::int) → void, (ffi::Handle, ffi::IntPtr) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::IntPtr) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (self::NativeClassy, ffi::Pointer<ffi::Void>) → void _goodHasReceiverHandleAndPtr$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, ffi::Pointer<ffi::Void>) → void, (ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (self::NativeClassy, self::NativeClassy) → void _goodHasReceiverHandleAndHandle$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, self::NativeClassy) → void, (ffi::Handle, ffi::Handle) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle, ffi::Handle) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (ffi::Pointer<ffi::Void>, self::NativeClassy) → void _goodHasReceiverPtrAndHandle$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, self::NativeClassy) → void, (ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (ffi::Pointer<ffi::Void>, core::bool) → core::Object? _meh$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → core::Object?, (ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (ffi::Pointer<ffi::Void>) → core::bool _blah$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void>) → ffi::Bool>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>) → ffi::Bool>*>(ffi::_ffi_resolver(#C1, #C4, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (ffi::Pointer<ffi::Void>) → core::bool _myField$Getter$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void>) → ffi::Bool>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>) → ffi::Bool>*>(ffi::_ffi_resolver(#C1, #C4, #C3){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
static final field (ffi::Pointer<ffi::Void>, core::bool) → void _myField$Setter$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → void, (ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
synthetic constructor •() → self::NativeClassy
|
||||
: super nat::NativeFieldWrapperClass1::•()
|
||||
;
|
||||
@#C9
|
||||
method goodHasReceiverPointer(core::int v) → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t1 = this;
|
||||
final core::int #t2 = v;
|
||||
final void #t3 = self::NativeClassy::_goodHasReceiverPointer$Method$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final void #t3 = self::NativeClassy::_goodHasReceiverPointer$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t1);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t2);
|
||||
} =>#pointerAddress), #t2){(ffi::Pointer<ffi::Void>, core::int) → void};
|
||||
_in::reachabilityFence(#t1);
|
||||
} =>#t3;
|
||||
@#C9
|
||||
method goodHasReceiverHandle(core::int v) → void
|
||||
return self::NativeClassy::_goodHasReceiverHandle$Method$FfiNative(this, v);
|
||||
@#C9
|
||||
return self::NativeClassy::_goodHasReceiverHandle$Method$FfiNative$Ptr(this, v){(self::NativeClassy, core::int) → void};
|
||||
method goodHasReceiverHandleAndPtr(self::NativeClassy v) → void
|
||||
return block {
|
||||
final self::NativeClassy #t4 = this;
|
||||
final nat::NativeFieldWrapperClass1 #t5 = v;
|
||||
final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$Method$FfiNative(#t4, ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t5)));
|
||||
final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$Method$FfiNative$Ptr(#t4, ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t5))){(self::NativeClassy, ffi::Pointer<ffi::Void>) → void};
|
||||
_in::reachabilityFence(#t5);
|
||||
} =>#t6;
|
||||
@#C9
|
||||
method goodHasReceiverHandleAndHandle(self::NativeClassy v) → void
|
||||
return self::NativeClassy::_goodHasReceiverHandleAndHandle$Method$FfiNative(this, v);
|
||||
@#C9
|
||||
return self::NativeClassy::_goodHasReceiverHandleAndHandle$Method$FfiNative$Ptr(this, v){(self::NativeClassy, self::NativeClassy) → void};
|
||||
method goodHasReceiverPtrAndHandle(self::NativeClassy v) → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t7 = this;
|
||||
final self::NativeClassy #t8 = v;
|
||||
final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$Method$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t7);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t8);
|
||||
} =>#pointerAddress), #t8){(ffi::Pointer<ffi::Void>, self::NativeClassy) → void};
|
||||
_in::reachabilityFence(#t7);
|
||||
} =>#t9;
|
||||
@#C9
|
||||
method meh(core::bool blah) → core::String?
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t10 = this;
|
||||
final core::bool #t11 = blah;
|
||||
final core::String? #t12 = _in::unsafeCast<core::String?>(self::NativeClassy::_meh$Method$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::String? #t12 = _in::unsafeCast<core::String?>(self::NativeClassy::_meh$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t10);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t11));
|
||||
} =>#pointerAddress), #t11){(ffi::Pointer<ffi::Void>, core::bool) → core::Object?});
|
||||
_in::reachabilityFence(#t10);
|
||||
} =>#t12;
|
||||
@#C9
|
||||
method blah() → core::bool
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t13 = this;
|
||||
final core::bool #t14 = self::NativeClassy::_blah$Method$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::bool #t14 = self::NativeClassy::_blah$Method$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t13);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress));
|
||||
} =>#pointerAddress)){(ffi::Pointer<ffi::Void>) → core::bool};
|
||||
_in::reachabilityFence(#t13);
|
||||
} =>#t14;
|
||||
@#C9
|
||||
get myField() → core::bool
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t15 = this;
|
||||
final core::bool #t16 = self::NativeClassy::_myField$Getter$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final core::bool #t16 = self::NativeClassy::_myField$Getter$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t15);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress));
|
||||
} =>#pointerAddress)){(ffi::Pointer<ffi::Void>) → core::bool};
|
||||
_in::reachabilityFence(#t15);
|
||||
} =>#t16;
|
||||
@#C9
|
||||
set myField(core::bool value) → void
|
||||
return block {
|
||||
final nat::NativeFieldWrapperClass1 #t17 = this;
|
||||
final core::bool #t18 = value;
|
||||
final void #t19 = self::NativeClassy::_myField$Setter$FfiNative(ffi::_fromAddress<ffi::Void>( block {
|
||||
final void #t19 = self::NativeClassy::_myField$Setter$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>( block {
|
||||
synthesized core::int #pointerAddress = nat::_getNativeField(#t17);
|
||||
if(#pointerAddress.{core::Object::==}(#C10){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C11);
|
||||
if(#pointerAddress.{core::Object::==}(#C6){(core::Object) → core::bool})
|
||||
core::StateError::_throwNew(#C7);
|
||||
else
|
||||
;
|
||||
} =>#pointerAddress), #t18);
|
||||
} =>#pointerAddress), #t18){(ffi::Pointer<ffi::Void>, core::bool) → void};
|
||||
_in::reachabilityFence(#t17);
|
||||
} =>#t19;
|
||||
@#C14
|
||||
external static method _goodHasReceiverPointer$Method$FfiNative(ffi::Pointer<ffi::Void> #t0, core::int #t1) → void;
|
||||
@#C16
|
||||
external static method _goodHasReceiverHandle$Method$FfiNative(self::NativeClassy #t0, core::int #t1) → void;
|
||||
@#C18
|
||||
external static method _goodHasReceiverHandleAndPtr$Method$FfiNative(self::NativeClassy #t0, ffi::Pointer<ffi::Void> #t1) → void;
|
||||
@#C20
|
||||
external static method _goodHasReceiverHandleAndHandle$Method$FfiNative(self::NativeClassy #t0, self::NativeClassy #t1) → void;
|
||||
@#C22
|
||||
external static method _goodHasReceiverPtrAndHandle$Method$FfiNative(ffi::Pointer<ffi::Void> #t0, self::NativeClassy #t1) → void;
|
||||
@#C24
|
||||
external static method _meh$Method$FfiNative(ffi::Pointer<ffi::Void> #t0, core::bool #t1) → core::Object?;
|
||||
@#C26
|
||||
external static method _blah$Method$FfiNative(ffi::Pointer<ffi::Void> #t0) → core::bool;
|
||||
@#C29
|
||||
external static method _myField$Getter$FfiNative(ffi::Pointer<ffi::Void> #t0) → core::bool;
|
||||
@#C31
|
||||
external static method _myField$Setter$FfiNative(ffi::Pointer<ffi::Void> #t0, core::bool #t1) → void;
|
||||
}
|
||||
@#C6
|
||||
external static method returnIntPtr(core::int x) → core::int;
|
||||
@#C33
|
||||
external static method returnIntPtrLeaf(core::int x) → core::int;
|
||||
static final field (core::int) → core::int _returnIntPtr$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>(ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static final field (core::int) → core::int _returnIntPtrLeaf$Method$FfiNative$Ptr = ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr) → ffi::IntPtr>(ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr) → ffi::IntPtr>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
|
||||
static method returnIntPtr(core::int x) → core::int
|
||||
return self::_returnIntPtr$Method$FfiNative$Ptr(x){(core::int) → core::int};
|
||||
static method returnIntPtrLeaf(core::int x) → core::int
|
||||
return self::_returnIntPtrLeaf$Method$FfiNative$Ptr(x){(core::int) → core::int};
|
||||
static method main() → void {
|
||||
self::returnIntPtr(13);
|
||||
self::returnIntPtrLeaf(37);
|
||||
|
@ -153,37 +138,11 @@ static method main() → void {
|
|||
new self::NativeClassy::•().{self::NativeClassy::myField} = !b;
|
||||
}
|
||||
constants {
|
||||
#C1 = "vm:ffi:native"
|
||||
#C1 = "#lib"
|
||||
#C2 = "ReturnIntPtr"
|
||||
#C3 = "#lib"
|
||||
#C4 = false
|
||||
#C5 = ffi::Native<(ffi::IntPtr) → ffi::IntPtr> {symbol:#C2, assetId:#C3, isLeaf:#C4}
|
||||
#C6 = core::pragma {name:#C1, options:#C5}
|
||||
#C7 = "vm:prefer-inline"
|
||||
#C8 = null
|
||||
#C9 = core::pragma {name:#C7, options:#C8}
|
||||
#C10 = 0
|
||||
#C11 = "A Dart object attempted to access a native peer, but the native peer has been collected (nullptr). This is usually the result of calling methods on a native-backed object when the native resources have already been disposed."
|
||||
#C12 = "doesntmatter"
|
||||
#C13 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::IntPtr) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C14 = core::pragma {name:#C1, options:#C13}
|
||||
#C15 = ffi::Native<(ffi::Handle, ffi::IntPtr) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C16 = core::pragma {name:#C1, options:#C15}
|
||||
#C17 = ffi::Native<(ffi::Handle, ffi::Pointer<ffi::Void>) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C18 = core::pragma {name:#C1, options:#C17}
|
||||
#C19 = ffi::Native<(ffi::Handle, ffi::Handle) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C20 = core::pragma {name:#C1, options:#C19}
|
||||
#C21 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Handle) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C22 = core::pragma {name:#C1, options:#C21}
|
||||
#C23 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Handle> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C24 = core::pragma {name:#C1, options:#C23}
|
||||
#C25 = ffi::Native<(ffi::Pointer<ffi::Void>) → ffi::Bool> {symbol:#C12, assetId:#C3, isLeaf:#C4}
|
||||
#C26 = core::pragma {name:#C1, options:#C25}
|
||||
#C27 = true
|
||||
#C28 = ffi::Native<(ffi::Pointer<ffi::Void>) → ffi::Bool> {symbol:#C12, assetId:#C3, isLeaf:#C27}
|
||||
#C29 = core::pragma {name:#C1, options:#C28}
|
||||
#C30 = ffi::Native<(ffi::Pointer<ffi::Void>, ffi::Bool) → ffi::Void> {symbol:#C12, assetId:#C3, isLeaf:#C27}
|
||||
#C31 = core::pragma {name:#C1, options:#C30}
|
||||
#C32 = ffi::Native<(ffi::IntPtr) → ffi::IntPtr> {symbol:#C2, assetId:#C3, isLeaf:#C27}
|
||||
#C33 = core::pragma {name:#C1, options:#C32}
|
||||
#C3 = 1
|
||||
#C4 = "doesntmatter"
|
||||
#C5 = 2
|
||||
#C6 = 0
|
||||
#C7 = "A Dart object attempted to access a native peer, but the native peer has been collected (nullptr). This is usually the result of calling methods on a native-backed object when the native resources have already been disposed."
|
||||
}
|
||||
|
|
|
@ -17,17 +17,15 @@ final class Struct1ByteInt extends ffi::Struct {
|
|||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:2,getterSelectorId:3] method toString() → core::String
|
||||
return "(${[@vm.direct-call.metadata=#lib::Struct1ByteInt.a0] this.{self::Struct1ByteInt::a0}{core::int}})";
|
||||
}
|
||||
[@vm.inferred-type.metadata=dart.core::_Closure]static final field (core::int) → self::Struct1ByteInt _returnStruct1ByteIntNative$Method$FfiNative$Ptr = block {
|
||||
_in::_nativeEffect(new self::Struct1ByteInt::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C9)));
|
||||
} =>[@vm.inferred-type.metadata=dart.core::_Closure] ffi::_asFunctionInternal<(core::int) → self::Struct1ByteInt, (ffi::Int8) → self::Struct1ByteInt>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_fromAddress<ffi::NativeFunction<(ffi::Int8) → self::Struct1ByteInt>*>(ffi::_ffi_resolver(#C10, #C11, #C9){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static method main() → void {
|
||||
final self::Struct1ByteInt result = self::returnStruct1ByteIntNative([@vm.direct-call.metadata=dart.core::_IntegerImplementation.unary-] [@vm.inferred-type.metadata=int (skip check)] 1.{core::int::unary-}(){() → core::int});
|
||||
core::print("result = ${result}");
|
||||
}
|
||||
[@vm.unboxing-info.metadata=(i)->b]@#C10
|
||||
static method returnStruct1ByteIntNative([@vm.inferred-arg-type.metadata=int] core::int a0) → self::Struct1ByteInt
|
||||
return block {
|
||||
_in::_nativeEffect(new self::Struct1ByteInt::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C11)));
|
||||
} =>[@vm.inferred-type.metadata=#lib::Struct1ByteInt] self::_returnStruct1ByteIntNative$Method$FfiNative(a0);
|
||||
[@vm.unboxing-info.metadata=(i)->b]@#C17
|
||||
external static method _returnStruct1ByteIntNative$Method$FfiNative([@vm.inferred-arg-type.metadata=int] core::int #t0) → self::Struct1ByteInt;
|
||||
[@vm.unboxing-info.metadata=(i)->b]static method returnStruct1ByteIntNative([@vm.inferred-arg-type.metadata=int] core::int a0) → self::Struct1ByteInt
|
||||
return self::_returnStruct1ByteIntNative$Method$FfiNative$Ptr(a0){(core::int) → self::Struct1ByteInt};
|
||||
constants {
|
||||
#C1 = "vm:ffi:struct-fields"
|
||||
#C2 = TypeLiteralConstant(ffi::Int8)
|
||||
|
@ -37,13 +35,7 @@ constants {
|
|||
#C6 = core::pragma {name:#C1, options:#C5}
|
||||
#C7 = 0
|
||||
#C8 = <core::int*>[#C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7, #C7]
|
||||
#C9 = "vm:prefer-inline"
|
||||
#C10 = core::pragma {name:#C9, options:#C4}
|
||||
#C11 = 1
|
||||
#C12 = "vm:ffi:native"
|
||||
#C13 = "ReturnStruct1ByteInt"
|
||||
#C14 = "#lib"
|
||||
#C15 = false
|
||||
#C16 = ffi::Native<(ffi::Int8) → self::Struct1ByteInt> {symbol:#C13, assetId:#C14, isLeaf:#C15}
|
||||
#C17 = core::pragma {name:#C12, options:#C16}
|
||||
#C9 = 1
|
||||
#C10 = "#lib"
|
||||
#C11 = "ReturnStruct1ByteInt"
|
||||
}
|
||||
|
|
|
@ -27,17 +27,15 @@ final class Struct1ByteInt extends ffi::Struct {
|
|||
static get #sizeOf() → core::int*
|
||||
return #C13.{core::List::[]}(ffi::_abi()){(core::int) → core::int*};
|
||||
}
|
||||
static final field (core::int) → self::Struct1ByteInt _returnStruct1ByteIntNative$Method$FfiNative$Ptr = block {
|
||||
_in::_nativeEffect(new self::Struct1ByteInt::#fromTypedDataBase(typ::Uint8List::•(#C12)));
|
||||
} =>ffi::_asFunctionInternal<(core::int) → self::Struct1ByteInt, (ffi::Int8) → self::Struct1ByteInt>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Int8) → self::Struct1ByteInt>*>(ffi::_ffi_resolver(#C14, #C15, #C12){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
|
||||
static method main() → void {
|
||||
final self::Struct1ByteInt result = self::returnStruct1ByteIntNative(1.{core::int::unary-}(){() → core::int});
|
||||
core::print("result = ${result}");
|
||||
}
|
||||
@#C11
|
||||
static method returnStruct1ByteIntNative(core::int a0) → self::Struct1ByteInt
|
||||
return block {
|
||||
_in::_nativeEffect(new self::Struct1ByteInt::#fromTypedDataBase(typ::Uint8List::•(#C12)));
|
||||
} =>self::_returnStruct1ByteIntNative$Method$FfiNative(a0);
|
||||
@#C19
|
||||
external static method _returnStruct1ByteIntNative$Method$FfiNative(core::int #t0) → self::Struct1ByteInt;
|
||||
return self::_returnStruct1ByteIntNative$Method$FfiNative$Ptr(a0){(core::int) → self::Struct1ByteInt};
|
||||
constants {
|
||||
#C1 = "vm:ffi:struct-fields"
|
||||
#C2 = TypeLiteralConstant(ffi::Int8)
|
||||
|
@ -52,10 +50,6 @@ constants {
|
|||
#C11 = core::pragma {name:#C10, options:#C4}
|
||||
#C12 = 1
|
||||
#C13 = <core::int*>[#C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12]
|
||||
#C14 = "vm:ffi:native"
|
||||
#C14 = "#lib"
|
||||
#C15 = "ReturnStruct1ByteInt"
|
||||
#C16 = "#lib"
|
||||
#C17 = false
|
||||
#C18 = ffi::Native<(ffi::Int8) → self::Struct1ByteInt> {symbol:#C15, assetId:#C16, isLeaf:#C17}
|
||||
#C19 = core::pragma {name:#C14, options:#C18}
|
||||
}
|
||||
|
|
|
@ -22,26 +22,3 @@ Related files:
|
|||
* [pkg/vm/test/native_assets_validator_test.dart](../../../pkg/vm/test/native_assets_validator_test.dart)
|
||||
* [runtime/lib/ffi_dynamic_library.cc](../../../runtime/lib/ffi_dynamic_library.cc)
|
||||
* [runtime/vm/ffi/native_assets.cc](../../../runtime/vm/ffi/native_assets.cc)
|
||||
|
||||
## Native
|
||||
|
||||
The fully expanded version of `@Native` passed to the VM.
|
||||
|
||||
```
|
||||
@pragma(
|
||||
'vm:ffi:native',
|
||||
Native<IntPtr Function(Pointer<Void>, IntPtr)>(
|
||||
symbol: 'MyClass_MyMethod',
|
||||
assetId: '<library uri>',
|
||||
),
|
||||
)
|
||||
external int _myFunction$FfiNative(Pointer<Void> self, int x);
|
||||
```
|
||||
|
||||
This is passed as a pragma so it is treated consistently with other pragmas.
|
||||
|
||||
Related files:
|
||||
|
||||
* [runtime/vm/kernel_loader.cc](../../../runtime/vm/kernel_loader.cc)
|
||||
* [runtime/vm/object.cc](../../../runtime/vm/object.cc)
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ These pragma's are only used on AST nodes synthesized by us, so users defining t
|
|||
| Pragma | Meaning |
|
||||
| --- | --- |
|
||||
| `vm:ffi:native-assets` | [Passing a native assets mapping to the VM](compiler/ffi_pragmas.md) |
|
||||
| `vm:ffi:native`| [Passing a native arguments to the VM](compiler/ffi_pragmas.md) |
|
||||
|
||||
## Pragmas for internal testing
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
#include "lib/ffi_dynamic_library.h"
|
||||
|
||||
#include "platform/globals.h"
|
||||
#if defined(DART_HOST_OS_WINDOWS)
|
||||
#include <Psapi.h>
|
||||
|
@ -440,39 +438,6 @@ static void ThrowFfiResolveError(const String& symbol,
|
|||
Exceptions::ThrowArgumentError(error_message);
|
||||
}
|
||||
|
||||
intptr_t FfiResolveInternal(const String& asset,
|
||||
const String& symbol,
|
||||
uintptr_t args_n,
|
||||
char** error) {
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
|
||||
// Resolver resolution.
|
||||
auto resolver = GetFfiNativeResolver(thread, asset);
|
||||
if (resolver != nullptr) {
|
||||
void* ffi_native_result = FfiResolveWithFfiNativeResolver(
|
||||
thread, resolver, symbol, args_n, error);
|
||||
return reinterpret_cast<intptr_t>(ffi_native_result);
|
||||
}
|
||||
|
||||
// Native assets resolution.
|
||||
const auto& asset_location =
|
||||
Array::Handle(zone, GetAssetLocation(thread, asset));
|
||||
if (!asset_location.IsNull()) {
|
||||
void* asset_result = FfiResolveAsset(thread, asset_location, symbol, error);
|
||||
return reinterpret_cast<intptr_t>(asset_result);
|
||||
}
|
||||
|
||||
// Resolution in current process.
|
||||
#if !defined(DART_HOST_OS_WINDOWS)
|
||||
void* const result = Utils::ResolveSymbolInDynamicLibrary(
|
||||
RTLD_DEFAULT, symbol.ToCString(), error);
|
||||
#else
|
||||
void* const result = LookupSymbolInProcess(symbol.ToCString(), error);
|
||||
#endif
|
||||
return reinterpret_cast<intptr_t>(result);
|
||||
}
|
||||
|
||||
// FFI native C function pointer resolver.
|
||||
static intptr_t FfiResolve(Dart_Handle asset_handle,
|
||||
Dart_Handle symbol_handle,
|
||||
|
@ -484,12 +449,40 @@ static intptr_t FfiResolve(Dart_Handle asset_handle,
|
|||
const String& symbol = Api::UnwrapStringHandle(zone, symbol_handle);
|
||||
char* error = nullptr;
|
||||
|
||||
const intptr_t result = FfiResolveInternal(asset, symbol, args_n, &error);
|
||||
// Resolver resolution.
|
||||
auto resolver = GetFfiNativeResolver(thread, asset);
|
||||
if (resolver != nullptr) {
|
||||
void* ffi_native_result = FfiResolveWithFfiNativeResolver(
|
||||
thread, resolver, symbol, args_n, &error);
|
||||
if (error != nullptr) {
|
||||
ThrowFfiResolveError(symbol, asset, error);
|
||||
}
|
||||
return reinterpret_cast<intptr_t>(ffi_native_result);
|
||||
}
|
||||
|
||||
// Native assets resolution.
|
||||
const auto& asset_location =
|
||||
Array::Handle(zone, GetAssetLocation(thread, asset));
|
||||
if (!asset_location.IsNull()) {
|
||||
void* asset_result =
|
||||
FfiResolveAsset(thread, asset_location, symbol, &error);
|
||||
if (error != nullptr) {
|
||||
ThrowFfiResolveError(symbol, asset, error);
|
||||
}
|
||||
return reinterpret_cast<intptr_t>(asset_result);
|
||||
}
|
||||
|
||||
// Resolution in current process.
|
||||
#if !defined(DART_HOST_OS_WINDOWS)
|
||||
void* const result = Utils::ResolveSymbolInDynamicLibrary(
|
||||
RTLD_DEFAULT, symbol.ToCString(), &error);
|
||||
#else
|
||||
void* const result = LookupSymbolInProcess(symbol.ToCString(), &error);
|
||||
#endif
|
||||
if (error != nullptr) {
|
||||
ThrowFfiResolveError(symbol, asset, error);
|
||||
}
|
||||
ASSERT(result != 0x0);
|
||||
return result;
|
||||
return reinterpret_cast<intptr_t>(result);
|
||||
}
|
||||
|
||||
// Bootstrap to get the FFI Native resolver through a `native` call.
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
|
||||
#ifndef RUNTIME_LIB_FFI_DYNAMIC_LIBRARY_H_
|
||||
#define RUNTIME_LIB_FFI_DYNAMIC_LIBRARY_H_
|
||||
|
||||
#include "platform/globals.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
intptr_t FfiResolveInternal(const String& asset,
|
||||
const String& symbol,
|
||||
uintptr_t args_n,
|
||||
char** error);
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_LIB_FFI_DYNAMIC_LIBRARY_H_
|
|
@ -1377,7 +1377,7 @@ const char* Precompiler::MustRetainFunction(const Function& function) {
|
|||
// * Selector matches a symbol used in Resolver::ResolveDynamic calls
|
||||
// in dart_entry.cc or dart_api_impl.cc.
|
||||
// * _Closure.call (used in async stack handling)
|
||||
if (function.is_old_native()) {
|
||||
if (function.is_native()) {
|
||||
return "native function";
|
||||
}
|
||||
|
||||
|
@ -1648,7 +1648,7 @@ void Precompiler::AddAnnotatedRoots() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (function.is_old_native()) {
|
||||
if (function.is_native()) {
|
||||
// The embedder will need to lookup this library to provide the native
|
||||
// resolver, even if there are no embedder calls into the library.
|
||||
AddApiUse(lib);
|
||||
|
@ -2193,7 +2193,7 @@ void Precompiler::DropFunctions() {
|
|||
// FFI trampolines may be dynamically called.
|
||||
return AddRetainReason(sig, RetainReasons::kFfiTrampolineSignature);
|
||||
}
|
||||
if (function.is_old_native()) {
|
||||
if (function.is_native()) {
|
||||
return AddRetainReason(sig, RetainReasons::kNativeSignature);
|
||||
}
|
||||
if (function.HasRequiredNamedParameters()) {
|
||||
|
@ -2983,7 +2983,7 @@ void Precompiler::DiscardCodeObjects() {
|
|||
if (functions_to_retain_.ContainsKey(function_)) {
|
||||
// Retain Code objects corresponding to native functions
|
||||
// (to find native implementation).
|
||||
if (function_.is_old_native()) {
|
||||
if (function_.is_native()) {
|
||||
++codes_with_native_function_;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3427,66 +3427,6 @@ void FlowGraphCompiler::EmitMoveFromNative(
|
|||
}
|
||||
}
|
||||
|
||||
void FlowGraphCompiler::EmitMoveConst(const compiler::ffi::NativeLocation& dst,
|
||||
Location src,
|
||||
Representation src_type,
|
||||
TemporaryRegisterAllocator* temp) {
|
||||
ASSERT(src.IsConstant() || src.IsPairLocation());
|
||||
const auto& dst_type = dst.payload_type();
|
||||
Register scratch = kNoRegister;
|
||||
if (dst.IsExpressibleAsLocation() &&
|
||||
dst_type.IsExpressibleAsRepresentation() &&
|
||||
dst_type.AsRepresentationOverApprox(zone_) == src_type) {
|
||||
// We can directly emit the const in the right place and representation.
|
||||
const Location dst_loc = dst.AsLocation();
|
||||
assembler()->Comment("dst.IsExpressibleAsLocation() %s",
|
||||
dst_loc.ToCString());
|
||||
EmitMove(dst_loc, src, temp);
|
||||
} else {
|
||||
// We need an intermediate location.
|
||||
Location intermediate;
|
||||
if (dst_type.IsInt()) {
|
||||
if (TMP == kNoRegister) {
|
||||
scratch = temp->AllocateTemporary();
|
||||
Location::RegisterLocation(scratch);
|
||||
} else {
|
||||
intermediate = Location::RegisterLocation(TMP);
|
||||
}
|
||||
} else {
|
||||
ASSERT(dst_type.IsFloat());
|
||||
intermediate = Location::FpuRegisterLocation(FpuTMP);
|
||||
}
|
||||
assembler()->Comment("constant using intermediate: %s",
|
||||
intermediate.ToCString());
|
||||
|
||||
if (src.IsPairLocation()) {
|
||||
for (intptr_t i : {0, 1}) {
|
||||
const Representation src_type_split =
|
||||
compiler::ffi::NativeType::FromUnboxedRepresentation(zone_,
|
||||
src_type)
|
||||
.Split(zone_, i)
|
||||
.AsRepresentation();
|
||||
const auto& intermediate_native =
|
||||
compiler::ffi::NativeLocation::FromLocation(zone_, intermediate,
|
||||
src_type_split);
|
||||
EmitMove(intermediate, src.AsPairLocation()->At(i), temp);
|
||||
EmitNativeMove(dst.Split(zone_, 2, i), intermediate_native, temp);
|
||||
}
|
||||
} else {
|
||||
const auto& intermediate_native =
|
||||
compiler::ffi::NativeLocation::FromLocation(zone_, intermediate,
|
||||
src_type);
|
||||
EmitMove(intermediate, src, temp);
|
||||
EmitNativeMove(dst, intermediate_native, temp);
|
||||
}
|
||||
|
||||
if (scratch != kNoRegister) {
|
||||
temp->ReleaseTemporary();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool FlowGraphCompiler::CanPcRelativeCall(const Function& target) const {
|
||||
return FLAG_precompiled_mode && (LoadingUnit::LoadingUnitOf(function()) ==
|
||||
LoadingUnit::LoadingUnitOf(target));
|
||||
|
|
|
@ -520,12 +520,6 @@ class FlowGraphCompiler : public ValueObject {
|
|||
const compiler::ffi::NativeLocation& src,
|
||||
TemporaryRegisterAllocator* temp);
|
||||
|
||||
// Helper method to move a Dart const to a native location.
|
||||
void EmitMoveConst(const compiler::ffi::NativeLocation& dst,
|
||||
Location src,
|
||||
Representation src_type,
|
||||
TemporaryRegisterAllocator* temp);
|
||||
|
||||
bool CheckAssertAssignableTypeTestingABILocations(
|
||||
const LocationSummary& locs);
|
||||
|
||||
|
|
|
@ -7407,18 +7407,15 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler,
|
|||
|
||||
ConstantTemporaryAllocator temp_alloc(temp0);
|
||||
if (origin.IsConstant()) {
|
||||
__ Comment("origin.IsConstant()");
|
||||
compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
|
||||
} else if (origin.IsPairLocation() &&
|
||||
(origin.AsPairLocation()->At(0).IsConstant() ||
|
||||
origin.AsPairLocation()->At(1).IsConstant())) {
|
||||
// Note: half of the pair can be constant.
|
||||
__ Comment("origin.IsPairLocation() and constant");
|
||||
compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
|
||||
} else if (marshaller_.IsHandle(arg_index)) {
|
||||
__ Comment("marshaller_.IsHandle(arg_index)");
|
||||
// Handles are passed into FfiCalls as Tagged values on the stack, and
|
||||
// then we pass pointers to these handles to the native function here.
|
||||
// Can't occur because we currently don't inline FFI trampolines (see
|
||||
// http://dartbug.com/45055), which means all incoming arguments
|
||||
// originate from parameters and thus are non-constant.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Handles are passed into FfiCalls as Tagged values on the stack, and
|
||||
// then we pass pointers to these handles to the native function here.
|
||||
if (marshaller_.IsHandle(arg_index)) {
|
||||
ASSERT(compiler::target::LocalHandle::ptr_offset() == 0);
|
||||
ASSERT(compiler::target::LocalHandle::InstanceSize() ==
|
||||
compiler::target::kWordSize);
|
||||
|
|
|
@ -259,7 +259,6 @@ template <>
|
|||
void FlowGraphSerializer::WriteTrait<const compiler::ffi::CallMarshaller&>::
|
||||
Write(FlowGraphSerializer* s, const compiler::ffi::CallMarshaller& x) {
|
||||
s->Write<const Function&>(x.dart_signature());
|
||||
s->Write<const FunctionType&>(x.c_signature());
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -267,10 +266,9 @@ const compiler::ffi::CallMarshaller&
|
|||
FlowGraphDeserializer::ReadTrait<const compiler::ffi::CallMarshaller&>::Read(
|
||||
FlowGraphDeserializer* d) {
|
||||
const Function& dart_signature = d->Read<const Function&>();
|
||||
const FunctionType& c_signature = d->Read<const FunctionType&>();
|
||||
const char* error = nullptr;
|
||||
return *compiler::ffi::CallMarshaller::FromFunction(d->zone(), dart_signature,
|
||||
c_signature, &error);
|
||||
&error);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
|
@ -1209,11 +1209,8 @@ ISOLATE_UNIT_TEST_CASE(IRTest_FfiCallInstrLeafDoesntSpill) {
|
|||
// Construct the FFICallInstr from the trampoline matching our native
|
||||
// function.
|
||||
const char* error = nullptr;
|
||||
auto* const zone = thread->zone();
|
||||
const auto& c_signature =
|
||||
FunctionType::ZoneHandle(zone, ffi_trampoline.FfiCSignature());
|
||||
const auto marshaller_ptr = compiler::ffi::CallMarshaller::FromFunction(
|
||||
zone, ffi_trampoline, c_signature, &error);
|
||||
thread->zone(), ffi_trampoline, &error);
|
||||
RELEASE_ASSERT(error == nullptr);
|
||||
RELEASE_ASSERT(marshaller_ptr != nullptr);
|
||||
const auto& marshaller = *marshaller_ptr;
|
||||
|
|
|
@ -87,10 +87,10 @@ const NativeFunctionType* NativeFunctionTypeFromFunctionType(
|
|||
|
||||
CallMarshaller* CallMarshaller::FromFunction(Zone* zone,
|
||||
const Function& function,
|
||||
const FunctionType& c_signature,
|
||||
const char** error) {
|
||||
DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
|
||||
DEBUG_ASSERT(c_signature.IsNotTemporaryScopedHandle());
|
||||
const auto& c_signature =
|
||||
FunctionType::ZoneHandle(zone, function.FfiCSignature());
|
||||
const auto native_function_signature =
|
||||
NativeFunctionTypeFromFunctionType(zone, c_signature, error);
|
||||
if (*error != nullptr) {
|
||||
|
@ -169,7 +169,7 @@ bool BaseMarshaller::IsCompound(intptr_t arg_index) const {
|
|||
}
|
||||
|
||||
bool BaseMarshaller::ContainsHandles() const {
|
||||
return c_signature_.ContainsHandles();
|
||||
return dart_signature_.FfiCSignatureContainsHandles();
|
||||
}
|
||||
|
||||
intptr_t BaseMarshaller::NumDefinitions() const {
|
||||
|
|
|
@ -138,7 +138,6 @@ class BaseMarshaller : public ZoneAllocated {
|
|||
}
|
||||
|
||||
const Function& dart_signature() const { return dart_signature_; }
|
||||
const FunctionType& c_signature() const { return c_signature_; }
|
||||
StringPtr function_name() const { return dart_signature_.name(); }
|
||||
|
||||
protected:
|
||||
|
@ -165,7 +164,6 @@ class CallMarshaller : public BaseMarshaller {
|
|||
public:
|
||||
static CallMarshaller* FromFunction(Zone* zone,
|
||||
const Function& function,
|
||||
const FunctionType& c_signature,
|
||||
const char** error);
|
||||
|
||||
CallMarshaller(Zone* zone,
|
||||
|
|
|
@ -678,10 +678,8 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionBody(
|
|||
|
||||
const bool has_body = ReadTag() == kSomething; // read first part of body.
|
||||
|
||||
if (dart_function.is_old_native()) {
|
||||
if (dart_function.is_native()) {
|
||||
body += B->NativeFunctionBody(dart_function, first_parameter);
|
||||
} else if (dart_function.is_ffi_native()) {
|
||||
body += B->FfiNativeFunctionBody(dart_function);
|
||||
} else if (dart_function.is_external()) {
|
||||
body += ThrowNoSuchMethodError(TokenPosition::kNoSource, dart_function,
|
||||
/*incompatible_arguments=*/false);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
#include "lib/ffi_dynamic_library.h"
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
#include "vm/class_id.h"
|
||||
|
@ -594,7 +593,7 @@ Fragment FlowGraphBuilder::Return(TokenPosition position,
|
|||
|
||||
// Emit a type check of the return type in checked mode for all functions
|
||||
// and in strong mode for native functions.
|
||||
if (!omit_result_type_check && function.is_old_native()) {
|
||||
if (!omit_result_type_check && function.is_native()) {
|
||||
const AbstractType& return_type =
|
||||
AbstractType::Handle(Z, function.result_type());
|
||||
instructions += CheckAssignable(return_type, Symbols::FunctionResult());
|
||||
|
@ -858,7 +857,7 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
|
|||
|
||||
Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
|
||||
LocalVariable* first_parameter) {
|
||||
ASSERT(function.is_old_native());
|
||||
ASSERT(function.is_native());
|
||||
ASSERT(!IsRecognizedMethodForFlowGraph(function));
|
||||
|
||||
Fragment body;
|
||||
|
@ -4985,133 +4984,33 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiTrampoline(
|
|||
case FfiFunctionKind::kAsyncCallback:
|
||||
return BuildGraphOfAsyncFfiCallback(function);
|
||||
case FfiFunctionKind::kCall:
|
||||
return BuildGraphOfFfiCall(function);
|
||||
return BuildGraphOfFfiNative(function);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Fragment FlowGraphBuilder::FfiNativeLookupAddress(const Function& function) {
|
||||
ASSERT(function.is_ffi_native());
|
||||
ASSERT(!IsRecognizedMethodForFlowGraph(function));
|
||||
auto const& native_instance =
|
||||
Instance::Handle(function.GetNativeAnnotation());
|
||||
const auto& native_class = Class::Handle(Z, native_instance.clazz());
|
||||
ASSERT(String::Handle(Z, native_class.UserVisibleName())
|
||||
.Equals(Symbols::FfiNative()));
|
||||
const auto& native_class_fields = Array::Handle(Z, native_class.fields());
|
||||
ASSERT(native_class_fields.Length() == 3);
|
||||
const auto& symbol_field =
|
||||
Field::Handle(Z, Field::RawCast(native_class_fields.At(0)));
|
||||
const auto& asset_id_field =
|
||||
Field::Handle(Z, Field::RawCast(native_class_fields.At(1)));
|
||||
const auto& symbol = String::ZoneHandle(
|
||||
Z, String::RawCast(native_instance.GetField(symbol_field)));
|
||||
const auto& asset_id = String::ZoneHandle(
|
||||
Z, String::RawCast(native_instance.GetField(asset_id_field)));
|
||||
const auto& type_args =
|
||||
TypeArguments::Handle(Z, native_instance.GetTypeArguments());
|
||||
ASSERT(type_args.Length() == 1);
|
||||
const auto& native_type =
|
||||
FunctionType::Cast(AbstractType::ZoneHandle(Z, type_args.TypeAt(0)));
|
||||
const intptr_t arg_n =
|
||||
native_type.NumParameters() - native_type.num_implicit_parameters();
|
||||
const auto& ffi_resolver =
|
||||
Function::ZoneHandle(Z, IG->object_store()->ffi_resolver_function());
|
||||
|
||||
#if !defined(TARGET_ARCH_IA32)
|
||||
// Access to the pool, use cacheable static call.
|
||||
Fragment body;
|
||||
body += Constant(asset_id);
|
||||
body += Constant(symbol);
|
||||
body += Constant(Smi::ZoneHandle(Smi::New(arg_n)));
|
||||
body += CachableIdempotentCall(TokenPosition::kNoSource, ffi_resolver,
|
||||
/*argument_count=*/3,
|
||||
/*argument_names=*/Array::null_array(),
|
||||
/*type_args_count=*/0);
|
||||
return body;
|
||||
#else
|
||||
// IA32 only has JIT and no pool. This function will only be compiled if
|
||||
// immediately run afterwards, so do the lookup here.
|
||||
char* error = nullptr;
|
||||
#if !defined(DART_PRECOMPILER) || defined(TESTING)
|
||||
const uintptr_t function_address =
|
||||
FfiResolveInternal(asset_id, symbol, arg_n, &error);
|
||||
#else
|
||||
const uintptr_t function_address = 0;
|
||||
UNREACHABLE(); // JIT runtime should not contain AOT code
|
||||
#endif
|
||||
if (error == nullptr) {
|
||||
Fragment body;
|
||||
body += UnboxedIntConstant(function_address, kUnboxedFfiIntPtr);
|
||||
return body;
|
||||
} else {
|
||||
free(error);
|
||||
// Lookup failed, we want to throw an error consistent with AOT, just
|
||||
// compile into a lookup so that we can throw the error from the same
|
||||
// error path.
|
||||
Fragment body;
|
||||
body += Constant(asset_id);
|
||||
body += Constant(symbol);
|
||||
body += Constant(Smi::ZoneHandle(Smi::New(arg_n)));
|
||||
// Non-cacheable call, this is IA32.
|
||||
body += StaticCall(TokenPosition::kNoSource, ffi_resolver,
|
||||
/*argument_count=*/3, ICData::kStatic);
|
||||
body += UnboxTruncate(kUnboxedFfiIntPtr);
|
||||
return body;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Fragment FlowGraphBuilder::FfiCallLookupAddress(const Function& function) {
|
||||
ASSERT(function.IsFfiTrampoline());
|
||||
FlowGraph* FlowGraphBuilder::BuildGraphOfFfiNative(const Function& function) {
|
||||
const intptr_t kClosureParameterOffset = 0;
|
||||
Fragment body;
|
||||
// Push the function pointer, which is stored (as Pointer object) in the
|
||||
// first slot of the context.
|
||||
body +=
|
||||
LoadLocal(parsed_function_->ParameterVariable(kClosureParameterOffset));
|
||||
body += LoadNativeField(Slot::Closure_context());
|
||||
body += LoadNativeField(Slot::GetContextVariableSlotFor(
|
||||
thread_, *MakeImplicitClosureScope(
|
||||
Z, Class::Handle(IG->object_store()->ffi_pointer_class()))
|
||||
->context_variables()[0]));
|
||||
const intptr_t kFirstArgumentParameterOffset = kClosureParameterOffset + 1;
|
||||
|
||||
// This can only be Pointer, so it is always safe to LoadUntagged.
|
||||
body += LoadUntagged(compiler::target::PointerBase::data_offset());
|
||||
body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
|
||||
return body;
|
||||
}
|
||||
graph_entry_ =
|
||||
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
|
||||
|
||||
Fragment FlowGraphBuilder::FfiNativeFunctionBody(const Function& function) {
|
||||
ASSERT(function.is_ffi_native());
|
||||
ASSERT(!IsRecognizedMethodForFlowGraph(function));
|
||||
auto normal_entry = BuildFunctionEntry(graph_entry_);
|
||||
graph_entry_->set_normal_entry(normal_entry);
|
||||
|
||||
const auto& c_signature =
|
||||
FunctionType::ZoneHandle(Z, function.FfiCSignature());
|
||||
PrologueInfo prologue_info(-1, -1);
|
||||
|
||||
Fragment body;
|
||||
body += FfiNativeLookupAddress(function);
|
||||
body += FfiCallFunctionBody(function, c_signature);
|
||||
return body;
|
||||
}
|
||||
BlockEntryInstr* instruction_cursor =
|
||||
BuildPrologue(normal_entry, &prologue_info);
|
||||
|
||||
Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
||||
const Function& function,
|
||||
const FunctionType& c_signature) {
|
||||
ASSERT(function.is_ffi_native() || function.IsFfiTrampoline());
|
||||
const bool is_ffi_native = function.is_ffi_native();
|
||||
const intptr_t kClosureParameterOffset = 0;
|
||||
const intptr_t first_argument_parameter_offset =
|
||||
is_ffi_native ? 0 : kClosureParameterOffset + 1;
|
||||
|
||||
LocalVariable* address = MakeTemporary("address");
|
||||
|
||||
Fragment body;
|
||||
Fragment function_body(instruction_cursor);
|
||||
function_body += CheckStackOverflowInPrologue(function.token_pos());
|
||||
|
||||
const char* error = nullptr;
|
||||
const auto marshaller_ptr = compiler::ffi::CallMarshaller::FromFunction(
|
||||
Z, function, c_signature, &error);
|
||||
const auto marshaller_ptr =
|
||||
compiler::ffi::CallMarshaller::FromFunction(Z, function, &error);
|
||||
// AbiSpecific integers can be incomplete causing us to not know the calling
|
||||
// convention. However, this is caught in asFunction in both JIT/AOT.
|
||||
RELEASE_ASSERT(error == nullptr);
|
||||
|
@ -5131,20 +5030,21 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
if (marshaller.IsHandle(i)) {
|
||||
continue;
|
||||
}
|
||||
body += LoadLocal(parsed_function_->ParameterVariable(
|
||||
first_argument_parameter_offset + i));
|
||||
function_body += LoadLocal(
|
||||
parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
|
||||
// TODO(http://dartbug.com/47486): Support entry without checking for null.
|
||||
// Check for 'null'.
|
||||
body += CheckNullOptimized(
|
||||
function_body += CheckNullOptimized(
|
||||
String::ZoneHandle(
|
||||
Z, function.ParameterNameAt(first_argument_parameter_offset + i)),
|
||||
Z, function.ParameterNameAt(kFirstArgumentParameterOffset + i)),
|
||||
CheckNullInstr::kArgumentError);
|
||||
body += StoreLocal(TokenPosition::kNoSource,
|
||||
parsed_function_->ParameterVariable(
|
||||
first_argument_parameter_offset + i));
|
||||
body += Drop();
|
||||
function_body += StoreLocal(
|
||||
TokenPosition::kNoSource,
|
||||
parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
|
||||
function_body += Drop();
|
||||
}
|
||||
|
||||
Fragment body;
|
||||
intptr_t try_handler_index = -1;
|
||||
if (signature_contains_handles) {
|
||||
// Wrap in Try catch to transition from Native to Generated on a throw from
|
||||
|
@ -5172,12 +5072,12 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
for (intptr_t i = 0; i < marshaller.num_args(); i++) {
|
||||
if (marshaller.IsCompound(i)) {
|
||||
body += FfiCallConvertCompoundArgumentToNative(
|
||||
parsed_function_->ParameterVariable(first_argument_parameter_offset +
|
||||
parsed_function_->ParameterVariable(kFirstArgumentParameterOffset +
|
||||
i),
|
||||
marshaller, i);
|
||||
} else {
|
||||
body += LoadLocal(parsed_function_->ParameterVariable(
|
||||
first_argument_parameter_offset + i));
|
||||
kFirstArgumentParameterOffset + i));
|
||||
// FfiCallInstr specifies all handle locations as Stack, and will pass a
|
||||
// pointer to the stack slot as the native handle argument.
|
||||
// Therefore we do not need to wrap handles.
|
||||
|
@ -5187,7 +5087,20 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
}
|
||||
}
|
||||
|
||||
body += LoadLocal(address);
|
||||
// Push the function pointer, which is stored (as Pointer object) in the
|
||||
// first slot of the context.
|
||||
body +=
|
||||
LoadLocal(parsed_function_->ParameterVariable(kClosureParameterOffset));
|
||||
body += LoadNativeField(Slot::Closure_context());
|
||||
body += LoadNativeField(Slot::GetContextVariableSlotFor(
|
||||
thread_, *MakeImplicitClosureScope(
|
||||
Z, Class::Handle(IG->object_store()->ffi_pointer_class()))
|
||||
->context_variables()[0]));
|
||||
|
||||
// This can only be Pointer, so it is safe to load the data field.
|
||||
body += LoadNativeField(Slot::PointerBase_data(),
|
||||
InnerPointerAccess::kCannotBeInnerPointer);
|
||||
body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
|
||||
|
||||
if (marshaller.PassTypedData()) {
|
||||
body += LoadLocal(typed_data);
|
||||
|
@ -5198,7 +5111,7 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
for (intptr_t i = 0; i < marshaller.num_args(); i++) {
|
||||
if (marshaller.IsPointer(i)) {
|
||||
body += LoadLocal(parsed_function_->ParameterVariable(
|
||||
first_argument_parameter_offset + i));
|
||||
kFirstArgumentParameterOffset + i));
|
||||
body += ReachabilityFence();
|
||||
}
|
||||
}
|
||||
|
@ -5206,12 +5119,12 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
const intptr_t num_defs = marshaller.NumReturnDefinitions();
|
||||
ASSERT(num_defs >= 1);
|
||||
auto defs = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_defs);
|
||||
LocalVariable* def = MakeTemporary("ffi call result");
|
||||
LocalVariable* def = MakeTemporary();
|
||||
defs->Add(def);
|
||||
|
||||
if (marshaller.PassTypedData()) {
|
||||
// Drop call result, typed data with contents is already on the stack.
|
||||
body += DropTemporary(&def);
|
||||
body += Drop();
|
||||
}
|
||||
|
||||
if (marshaller.IsCompound(compiler::ffi::kResultIndex)) {
|
||||
|
@ -5228,13 +5141,14 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
body += ExitHandleScope();
|
||||
}
|
||||
|
||||
body += DropTempsPreserveTop(1); // Drop address.
|
||||
body += Return(TokenPosition::kNoSource);
|
||||
|
||||
if (signature_contains_handles) {
|
||||
--try_depth_;
|
||||
}
|
||||
|
||||
function_body += body;
|
||||
|
||||
if (signature_contains_handles) {
|
||||
++catch_depth_;
|
||||
Fragment catch_body =
|
||||
|
@ -5253,30 +5167,6 @@ Fragment FlowGraphBuilder::FfiCallFunctionBody(
|
|||
--catch_depth_;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCall(const Function& function) {
|
||||
graph_entry_ =
|
||||
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
|
||||
|
||||
auto normal_entry = BuildFunctionEntry(graph_entry_);
|
||||
graph_entry_->set_normal_entry(normal_entry);
|
||||
|
||||
PrologueInfo prologue_info(-1, -1);
|
||||
|
||||
BlockEntryInstr* instruction_cursor =
|
||||
BuildPrologue(normal_entry, &prologue_info);
|
||||
|
||||
Fragment function_body(instruction_cursor);
|
||||
function_body += CheckStackOverflowInPrologue(function.token_pos());
|
||||
|
||||
const auto& c_signature =
|
||||
FunctionType::ZoneHandle(Z, function.FfiCSignature());
|
||||
|
||||
function_body += FfiCallLookupAddress(function);
|
||||
function_body += FfiCallFunctionBody(function, c_signature);
|
||||
|
||||
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
|
||||
prologue_info);
|
||||
}
|
||||
|
|
|
@ -137,14 +137,8 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
|
|||
FlowGraph* BuildGraphOfFfiTrampoline(const Function& function);
|
||||
FlowGraph* BuildGraphOfSyncFfiCallback(const Function& function);
|
||||
FlowGraph* BuildGraphOfAsyncFfiCallback(const Function& function);
|
||||
FlowGraph* BuildGraphOfFfiCall(const Function& function);
|
||||
FlowGraph* BuildGraphOfFfiNative(const Function& function);
|
||||
|
||||
Fragment FfiCallLookupAddress(const Function& function);
|
||||
Fragment FfiNativeLookupAddress(const Function& function);
|
||||
// Expects target address on stack.
|
||||
Fragment FfiCallFunctionBody(const Function& function,
|
||||
const FunctionType& c_signature);
|
||||
Fragment FfiNativeFunctionBody(const Function& function);
|
||||
Fragment NativeFunctionBody(const Function& function,
|
||||
LocalVariable* first_parameter);
|
||||
Fragment LoadNativeArg(const compiler::ffi::CallbackMarshaller& marshaller,
|
||||
|
|
|
@ -155,19 +155,7 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
|
|||
// NOTE: FunctionNode is read further below the if.
|
||||
|
||||
intptr_t pos = 0;
|
||||
if (function.is_ffi_native()) {
|
||||
needs_expr_temp_ = true;
|
||||
// Calls with handles need try/catch variables.
|
||||
if (function.FfiCSignatureContainsHandles()) {
|
||||
++depth_.try_;
|
||||
AddTryVariables();
|
||||
--depth_.try_;
|
||||
++depth_.catch_;
|
||||
AddCatchVariables();
|
||||
FinalizeCatchVariables();
|
||||
--depth_.catch_;
|
||||
}
|
||||
} else if (function.IsClosureFunction()) {
|
||||
if (function.IsClosureFunction()) {
|
||||
LocalVariable* closure_parameter = MakeVariable(
|
||||
TokenPosition::kNoSource, TokenPosition::kNoSource,
|
||||
Symbols::ClosureParameter(), AbstractType::dynamic_type());
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1749,9 +1749,6 @@ void KernelLoader::ReadVMAnnotations(const Library& library,
|
|||
"vm:isolate-unsendable")) {
|
||||
*pragma_bits = IsolateUnsendablePragma::update(true, *pragma_bits);
|
||||
}
|
||||
if (constant_reader.IsStringConstant(name_index, "vm:ffi:native")) {
|
||||
*pragma_bits = FfiNativePragma::update(true, *pragma_bits);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
helper_.SkipExpression();
|
||||
|
@ -1801,14 +1798,13 @@ void KernelLoader::LoadProcedure(const Library& library,
|
|||
// they are not reachable anymore and we never look them up by name.
|
||||
const bool register_function = !name.Equals(Symbols::DebugProcedureName());
|
||||
|
||||
const bool is_ffi_native = FfiNativePragma::decode(pragma_bits);
|
||||
const FunctionType& signature = FunctionType::Handle(Z, FunctionType::New());
|
||||
const Function& function = Function::ZoneHandle(
|
||||
Z, Function::New(signature, name, kind,
|
||||
!is_method, // is_static
|
||||
false, // is_const
|
||||
is_abstract, is_external,
|
||||
!native_name.IsNull() || is_ffi_native, // is_native
|
||||
!native_name.IsNull(), // is_native
|
||||
script_class, procedure_helper.start_position_));
|
||||
function.set_has_pragma(HasPragma::decode(pragma_bits));
|
||||
function.set_end_token_pos(procedure_helper.end_position_);
|
||||
|
|
|
@ -220,8 +220,6 @@ class KernelLoader : public ValueObject {
|
|||
BitField<uint32_t, bool, ExternalNamePragma::kNextBit, 1>;
|
||||
using IsolateUnsendablePragma =
|
||||
BitField<uint32_t, bool, InvisibleFunctionPragma::kNextBit, 1>;
|
||||
using FfiNativePragma =
|
||||
BitField<uint32_t, bool, IsolateUnsendablePragma::kNextBit, 1>;
|
||||
|
||||
void FinishTopLevelClassLoading(const Class& toplevel_class,
|
||||
const Library& library,
|
||||
|
|
|
@ -175,7 +175,7 @@ class NativeArguments {
|
|||
}
|
||||
|
||||
static intptr_t ParameterCountForResolution(const Function& function) {
|
||||
ASSERT(function.is_old_native());
|
||||
ASSERT(function.is_native());
|
||||
ASSERT(!function.IsGenerativeConstructor()); // Not supported.
|
||||
intptr_t count = function.NumParameters();
|
||||
if (function.is_static() && function.IsClosureFunction()) {
|
||||
|
@ -189,7 +189,7 @@ class NativeArguments {
|
|||
}
|
||||
|
||||
static int ComputeArgcTag(const Function& function) {
|
||||
ASSERT(function.is_old_native());
|
||||
ASSERT(function.is_native());
|
||||
ASSERT(!function.IsGenerativeConstructor()); // Not supported.
|
||||
int argc = function.NumParameters();
|
||||
int function_bits = 0;
|
||||
|
|
|
@ -8358,7 +8358,7 @@ void Function::set_implicit_closure_function(const Function& value) const {
|
|||
IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
|
||||
ASSERT(!IsClosureFunction());
|
||||
const Object& old_data = Object::Handle(data());
|
||||
if (is_old_native()) {
|
||||
if (is_native()) {
|
||||
ASSERT(old_data.IsArray());
|
||||
const auto& pair = Array::Cast(old_data);
|
||||
ASSERT(pair.AtAcquire(NativeFunctionData::kTearOff) == Object::null() ||
|
||||
|
@ -8378,38 +8378,26 @@ void Function::SetFfiCSignature(const FunctionType& sig) const {
|
|||
}
|
||||
|
||||
FunctionTypePtr Function::FfiCSignature() const {
|
||||
auto* const zone = Thread::Current()->zone();
|
||||
if (IsFfiTrampoline()) {
|
||||
const Object& obj = Object::Handle(zone, data());
|
||||
ASSERT(!obj.IsNull());
|
||||
return FfiTrampolineData::Cast(obj).c_signature();
|
||||
}
|
||||
ASSERT(is_ffi_native());
|
||||
auto const& native_instance = Instance::Handle(GetNativeAnnotation());
|
||||
const auto& type_args =
|
||||
TypeArguments::Handle(zone, native_instance.GetTypeArguments());
|
||||
ASSERT(type_args.Length() == 1);
|
||||
const auto& native_type =
|
||||
FunctionType::Cast(AbstractType::ZoneHandle(zone, type_args.TypeAt(0)));
|
||||
return native_type.ptr();
|
||||
ASSERT(IsFfiTrampoline());
|
||||
const Object& obj = Object::Handle(data());
|
||||
ASSERT(!obj.IsNull());
|
||||
return FfiTrampolineData::Cast(obj).c_signature();
|
||||
}
|
||||
|
||||
bool Function::FfiCSignatureContainsHandles() const {
|
||||
ASSERT(IsFfiTrampoline());
|
||||
const FunctionType& c_signature = FunctionType::Handle(FfiCSignature());
|
||||
return c_signature.ContainsHandles();
|
||||
}
|
||||
|
||||
bool FunctionType::ContainsHandles() const {
|
||||
const intptr_t num_params = num_fixed_parameters();
|
||||
const intptr_t num_params = c_signature.num_fixed_parameters();
|
||||
for (intptr_t i = 0; i < num_params; i++) {
|
||||
const bool is_handle =
|
||||
AbstractType::Handle(ParameterTypeAt(i)).type_class_id() ==
|
||||
AbstractType::Handle(c_signature.ParameterTypeAt(i)).type_class_id() ==
|
||||
kFfiHandleCid;
|
||||
if (is_handle) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return AbstractType::Handle(result_type()).type_class_id() == kFfiHandleCid;
|
||||
return AbstractType::Handle(c_signature.result_type()).type_class_id() ==
|
||||
kFfiHandleCid;
|
||||
}
|
||||
|
||||
// Keep consistent with BaseMarshaller::IsCompound.
|
||||
|
@ -8465,22 +8453,10 @@ void Function::AssignFfiCallbackId(int32_t callback_id) const {
|
|||
}
|
||||
|
||||
bool Function::FfiIsLeaf() const {
|
||||
if (IsFfiTrampoline()) {
|
||||
const Object& obj = Object::Handle(untag()->data());
|
||||
ASSERT(!obj.IsNull());
|
||||
return FfiTrampolineData::Cast(obj).is_leaf();
|
||||
}
|
||||
ASSERT(is_ffi_native());
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
auto const& native_instance = Instance::Handle(GetNativeAnnotation());
|
||||
const auto& native_class = Class::Handle(zone, native_instance.clazz());
|
||||
const auto& native_class_fields = Array::Handle(zone, native_class.fields());
|
||||
ASSERT(native_class_fields.Length() == 3);
|
||||
const auto& is_leaf_field =
|
||||
Field::Handle(zone, Field::RawCast(native_class_fields.At(2)));
|
||||
return Bool::Handle(zone,
|
||||
Bool::RawCast(native_instance.GetField(is_leaf_field)))
|
||||
.value();
|
||||
ASSERT(IsFfiTrampoline());
|
||||
const Object& obj = Object::Handle(untag()->data());
|
||||
ASSERT(!obj.IsNull());
|
||||
return FfiTrampolineData::Cast(obj).is_leaf();
|
||||
}
|
||||
|
||||
void Function::SetFfiIsLeaf(bool is_leaf) const {
|
||||
|
@ -8633,32 +8609,6 @@ void Function::set_native_name(const String& value) const {
|
|||
pair.SetAt(NativeFunctionData::kNativeName, value);
|
||||
}
|
||||
|
||||
InstancePtr Function::GetNativeAnnotation() const {
|
||||
ASSERT(is_ffi_native());
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
auto& pragma_value = Object::Handle(zone);
|
||||
Library::FindPragma(dart::Thread::Current(), /*only_core=*/false,
|
||||
Object::Handle(zone, ptr()),
|
||||
String::Handle(zone, Symbols::vm_ffi_native().ptr()),
|
||||
/*multiple=*/false, &pragma_value);
|
||||
auto const& native_instance = Instance::Cast(pragma_value);
|
||||
ASSERT(!native_instance.IsNull());
|
||||
#if defined(DEBUG)
|
||||
const auto& native_class = Class::Handle(zone, native_instance.clazz());
|
||||
ASSERT(String::Handle(zone, native_class.UserVisibleName())
|
||||
.Equals(Symbols::FfiNative()));
|
||||
#endif
|
||||
return native_instance.ptr();
|
||||
}
|
||||
|
||||
bool Function::is_old_native() const {
|
||||
return is_native() && !is_external();
|
||||
}
|
||||
|
||||
bool Function::is_ffi_native() const {
|
||||
return is_native() && is_external();
|
||||
}
|
||||
|
||||
void Function::SetSignature(const FunctionType& value) const {
|
||||
set_signature(value);
|
||||
ASSERT(NumImplicitParameters() == value.num_implicit_parameters());
|
||||
|
@ -9048,7 +8998,7 @@ bool Function::IsOptimizable() const {
|
|||
return true;
|
||||
}
|
||||
if (ForceOptimize()) return true;
|
||||
if (is_old_native()) {
|
||||
if (is_native()) {
|
||||
// Native methods don't need to be optimized.
|
||||
return false;
|
||||
}
|
||||
|
@ -9131,7 +9081,7 @@ static bool InVmTests(const Function& function) {
|
|||
}
|
||||
|
||||
bool Function::ForceOptimize() const {
|
||||
if (RecognizedKindForceOptimize() || IsFfiTrampoline() || is_ffi_native() ||
|
||||
if (RecognizedKindForceOptimize() || IsFfiTrampoline() ||
|
||||
IsTypedDataViewFactory() || IsUnmodifiableTypedDataViewFactory()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -9246,7 +9196,7 @@ bool Function::RecognizedKindForceOptimize() const {
|
|||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
bool Function::CanBeInlined() const {
|
||||
if (ForceOptimize()) {
|
||||
if (IsFfiTrampoline() || is_ffi_native()) {
|
||||
if (IsFfiTrampoline()) {
|
||||
// We currently don't support inlining FFI trampolines. Some of them
|
||||
// are naturally non-inlinable because they contain a try/catch block,
|
||||
// but this condition is broader than strictly necessary.
|
||||
|
@ -10345,7 +10295,7 @@ FunctionPtr Function::New(const FunctionType& signature,
|
|||
const FfiTrampolineData& data =
|
||||
FfiTrampolineData::Handle(FfiTrampolineData::New());
|
||||
result.set_data(data);
|
||||
} else if (result.is_old_native()) {
|
||||
} else if (is_native) {
|
||||
const auto& data =
|
||||
Array::Handle(Array::New(NativeFunctionData::kLength, Heap::kOld));
|
||||
result.set_data(data);
|
||||
|
|
|
@ -2979,7 +2979,8 @@ class Function : public Object {
|
|||
// Can only be used on FFI trampolines.
|
||||
void SetFfiCSignature(const FunctionType& sig) const;
|
||||
|
||||
// Retrieves the "C signature" for an FFI trampoline or FFI native.
|
||||
// Retrieves the "C signature" for an FFI trampoline.
|
||||
// Can only be used on FFI trampolines.
|
||||
FunctionTypePtr FfiCSignature() const;
|
||||
|
||||
bool FfiCSignatureContainsHandles() const;
|
||||
|
@ -3072,10 +3073,6 @@ class Function : public Object {
|
|||
StringPtr native_name() const;
|
||||
void set_native_name(const String& name) const;
|
||||
|
||||
InstancePtr GetNativeAnnotation() const;
|
||||
bool is_ffi_native() const;
|
||||
bool is_old_native() const;
|
||||
|
||||
AbstractTypePtr result_type() const {
|
||||
return signature()->untag()->result_type();
|
||||
}
|
||||
|
@ -9666,8 +9663,6 @@ class FunctionType : public AbstractType {
|
|||
|
||||
static FunctionTypePtr Clone(const FunctionType& orig, Heap::Space space);
|
||||
|
||||
bool ContainsHandles() const;
|
||||
|
||||
private:
|
||||
static FunctionTypePtr New(Heap::Space space);
|
||||
|
||||
|
|
|
@ -543,16 +543,6 @@ void ObjectStore::LazyInitFfiMembers() {
|
|||
ASSERT(!function.IsNull());
|
||||
handle_native_finalizer_message_function_.store(function.ptr());
|
||||
|
||||
const auto& lib = Library::Handle(zone, Library::FfiLibrary());
|
||||
const Class& klass = Class::ZoneHandle(zone, lib.toplevel_class());
|
||||
ASSERT(!klass.IsNull());
|
||||
error = klass.EnsureIsFinalized(thread);
|
||||
ASSERT(error.IsNull());
|
||||
function = klass.LookupStaticFunctionAllowPrivate(
|
||||
Symbols::_ffi_resolver_function());
|
||||
ASSERT(!function.IsNull());
|
||||
ffi_resolver_function_.store(function.ptr());
|
||||
|
||||
cls = ffi_lib.LookupClass(Symbols::VarArgs());
|
||||
ASSERT(!cls.IsNull());
|
||||
varargs_class_.store(cls.ptr());
|
||||
|
|
|
@ -58,7 +58,6 @@ class ObjectPointerVisitor;
|
|||
LAZY_INTERNAL(Class, symbol_class) \
|
||||
LAZY_INTERNAL(Field, symbol_name_field) \
|
||||
LAZY_FFI(Class, varargs_class) \
|
||||
LAZY_FFI(Function, ffi_resolver_function) \
|
||||
LAZY_FFI(Function, handle_finalizer_message_function) \
|
||||
LAZY_FFI(Function, handle_native_finalizer_message_function) \
|
||||
LAZY_ASYNC(Type, non_nullable_future_never_type) \
|
||||
|
|
|
@ -116,7 +116,6 @@ class ObjectPointerVisitor;
|
|||
V(FfiInt8, "Int8") \
|
||||
V(FfiIntPtr, "IntPtr") \
|
||||
V(FfiIsolateLocalCallback, "_FfiIsolateLocalCallback") \
|
||||
V(FfiNative, "Native") \
|
||||
V(FfiNativeFunction, "NativeFunction") \
|
||||
V(FfiNativeType, "NativeType") \
|
||||
V(FfiNativeTypes, "nativeTypes") \
|
||||
|
@ -427,7 +426,6 @@ class ObjectPointerVisitor;
|
|||
V(_checkSetRangeArguments, "_checkSetRangeArguments") \
|
||||
V(_current, "_current") \
|
||||
V(_ensureScheduleImmediate, "_ensureScheduleImmediate") \
|
||||
V(_ffi_resolver_function, "_ffi_resolver_function") \
|
||||
V(future, "future") \
|
||||
V(_future, "_future") \
|
||||
V(_getRegisters, "_getRegisters") \
|
||||
|
@ -527,7 +525,6 @@ class ObjectPointerVisitor;
|
|||
V(vm_exact_result_type, "vm:exact-result-type") \
|
||||
V(vm_external_name, "vm:external-name") \
|
||||
V(vm_ffi_abi_specific_mapping, "vm:ffi:abi-specific-mapping") \
|
||||
V(vm_ffi_native, "vm:ffi:native") \
|
||||
V(vm_ffi_native_assets, "vm:ffi:native-assets") \
|
||||
V(vm_ffi_struct_fields, "vm:ffi:struct-fields") \
|
||||
V(vm_force_optimize, "vm:force-optimize") \
|
||||
|
|
|
@ -1355,11 +1355,3 @@ final class _ArraySize<T extends NativeType> implements Array<T> {
|
|||
Object get _typedDataBase =>
|
||||
throw UnsupportedError('_ArraySize._typedDataBase');
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma("vm:entry-point")
|
||||
class FfiNative<T> {}
|
||||
|
||||
@patch
|
||||
@pragma("vm:entry-point")
|
||||
class Native<T> {}
|
||||
|
|
|
@ -1347,6 +1347,3 @@ external Pointer<NativeFunction<IntPtr Function(Handle, Handle, IntPtr)>>
|
|||
final _ffi_resolver = _get_ffi_native_resolver<
|
||||
NativeFunction<IntPtr Function(Handle, Handle, IntPtr)>>()
|
||||
.asFunction<int Function(Object, Object, int)>();
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
int _ffi_resolver_function(Object a, Object s, int n) => _ffi_resolver(a, s, n);
|
||||
|
|
Loading…
Reference in a new issue