From 7efefec16509ed38544a8af999b9e85694586bc7 Mon Sep 17 00:00:00 2001 From: Hossein Yousefi Date: Tue, 23 Jul 2024 12:37:30 +0200 Subject: [PATCH] Make Some JNI functions leaf and remove `Jni.accessors` (#1355) * Make some functions leaf, refactor array construction * Remove Jni.accessors --- pkgs/jni/CHANGELOG.md | 5 + pkgs/jni/lib/jni.dart | 1 - pkgs/jni/lib/src/accessors.dart | 19 +- pkgs/jni/lib/src/jarray.dart | 116 ++--- pkgs/jni/lib/src/jclass.dart | 35 +- pkgs/jni/lib/src/jni.dart | 24 +- pkgs/jni/lib/src/jobject.dart | 3 +- pkgs/jni/lib/src/jprimitives.dart | 101 +++- pkgs/jni/lib/src/method_invocation.dart | 2 +- pkgs/jni/lib/src/nio/jbyte_buffer.dart | 1 - .../third_party/global_env_extensions.dart | 408 ++++++++-------- .../third_party/jni_bindings_generated.dart | 366 ++++++--------- pkgs/jni/lib/src/types.dart | 33 +- pkgs/jni/pubspec.yaml | 2 +- pkgs/jni/src/dartjni.c | 437 +----------------- pkgs/jni/src/dartjni.h | 51 +- pkgs/jni/src/third_party/global_jni_env.c | 119 +++++ pkgs/jni/src/third_party/global_jni_env.h | 30 ++ .../generate_c_extensions.dart | 72 +-- .../generate_dart_extensions.dart | 141 +++++- .../generate_helper_functions.dart | 121 +++++ 21 files changed, 1009 insertions(+), 1078 deletions(-) create mode 100644 pkgs/jni/tool/wrapper_generators/generate_helper_functions.dart diff --git a/pkgs/jni/CHANGELOG.md b/pkgs/jni/CHANGELOG.md index d1704ffce..ce24bdb77 100644 --- a/pkgs/jni/CHANGELOG.md +++ b/pkgs/jni/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.11.0-wip + +- **Breaking Change** Removed `Jni.accessors`. +- Made most `Jni.env` methods into leaf functions to speed up their execution. + ## 0.10.1 - Fixed an issue with `JObject.castTo` where the type checking could fail in diff --git a/pkgs/jni/lib/jni.dart b/pkgs/jni/lib/jni.dart index 89672b00f..1d2f51a5b 100644 --- a/pkgs/jni/lib/jni.dart +++ b/pkgs/jni/lib/jni.dart @@ -65,7 +65,6 @@ export 'dart:ffi' show nullptr; export 'package:ffi/ffi.dart' show Arena, using; export 'src/errors.dart'; -export 'src/jarray.dart'; export 'src/jni.dart' hide ProtectedJniExtensions; export 'src/jobject.dart'; export 'src/jreference.dart'; diff --git a/pkgs/jni/lib/src/accessors.dart b/pkgs/jni/lib/src/accessors.dart index ad688637d..69729df2b 100644 --- a/pkgs/jni/lib/src/accessors.dart +++ b/pkgs/jni/lib/src/accessors.dart @@ -8,7 +8,7 @@ import '../jni.dart'; void _check(JThrowablePtr exception) { if (exception != nullptr) { - Jni.accessors.throwException(exception); + Jni.throwException(exception); } } @@ -102,20 +102,3 @@ extension JThrowableCheckMethod on JThrowablePtr { _check(this); } } - -extension JniAccessorWrappers on JniAccessors { - /// Rethrows Java exception in Dart as [JniException]. - /// - /// The original exception object is deleted by this method. The message - /// and Java stack trace are included in the exception. - void throwException(JThrowablePtr exception) { - final details = getExceptionDetails(exception); - final env = Jni.env; - final message = env.toDartString(details.message); - final stacktrace = env.toDartString(details.stacktrace); - env.DeleteGlobalRef(exception); - env.DeleteGlobalRef(details.message); - env.DeleteGlobalRef(details.stacktrace); - throw JniException(message, stacktrace); - } -} diff --git a/pkgs/jni/lib/src/jarray.dart b/pkgs/jni/lib/src/jarray.dart index c07ca23ae..bf42937c7 100644 --- a/pkgs/jni/lib/src/jarray.dart +++ b/pkgs/jni/lib/src/jarray.dart @@ -4,20 +4,10 @@ // ignore_for_file: unnecessary_cast, overridden_fields -import 'dart:ffi'; -import 'dart:typed_data'; - -import 'package:collection/collection.dart'; -import 'package:ffi/ffi.dart'; - -import '../internal_helpers_for_jnigen.dart'; -import 'jni.dart'; -import 'jobject.dart'; -import 'third_party/generated_bindings.dart'; -import 'types.dart'; +part of 'types.dart'; final class JArrayType extends JObjType> { - final JType elementType; + final JArrayElementType elementType; const JArrayType(this.elementType); @@ -46,13 +36,13 @@ final class JArrayType extends JObjType> { } class JArray extends JObject { - final JType elementType; + final JArrayElementType elementType; @override late final JArrayType $type = type(elementType) as JArrayType; /// The type which includes information such as the signature of this class. - static JObjType> type(JType innerType) => + static JObjType> type(JArrayElementType innerType) => JArrayType(innerType); /// Construct a new [JArray] with [reference] as its underlying reference. @@ -62,40 +52,8 @@ class JArray extends JObject { /// Creates a [JArray] of the given length from the given [elementType]. /// /// The [length] must be a non-negative integer. - factory JArray(JType elementType, int length) { - const primitiveCallTypes = { - 'B': JniCallType.byteType, - 'Z': JniCallType.booleanType, - 'C': JniCallType.charType, - 'S': JniCallType.shortType, - 'I': JniCallType.intType, - 'J': JniCallType.longType, - 'F': JniCallType.floatType, - 'D': JniCallType.doubleType, - }; - if (!primitiveCallTypes.containsKey(elementType.signature) && - elementType is JObjType) { - final clazz = (elementType as JObjType).jClass; - final array = JArray.fromReference( - elementType, - JGlobalReference( - Jni.accessors - .newObjectArray(length, clazz.reference.pointer, nullptr) - .objectPointer, - ), - ); - clazz.release(); - return array; - } - return JArray.fromReference( - elementType, - JGlobalReference( - Jni.accessors - .newPrimitiveArray( - length, primitiveCallTypes[elementType.signature]!) - .objectPointer, - ), - ); + factory JArray(JArrayElementType elementType, int length) { + return elementType._newArray(length); } /// Creates a [JArray] of the given length with [fill] at each position. @@ -105,25 +63,11 @@ class JArray extends JObject { {JObjType<$E>? E}) { RangeError.checkNotNegative(length); E ??= fill.$type as JObjType<$E>; - final clazz = E.jClass; - final array = JArray<$E>.fromReference( - E, - JGlobalReference(Jni.accessors - .newObjectArray( - length, clazz.reference.pointer, fill.reference.pointer) - .objectPointer), - ); - clazz.release(); - return array; + return E._newArray(length, fill); } int? _length; - JniResult _elementAt(int index, int type) { - RangeError.checkValidIndex(index, this); - return Jni.accessors.getArrayElement(reference.pointer, index, type); - } - /// The number of elements in this array. int get length { return _length ??= Jni.env.GetArrayLength(reference.pointer); @@ -154,13 +98,13 @@ extension on Allocator { extension BoolArray on JArray { bool operator [](int index) { - return _elementAt(index, JniCallType.booleanType).boolean; + RangeError.checkValidIndex(index, this); + return Jni.env.GetBooleanArrayElement(reference.pointer, index); } void operator []=(int index, bool value) { RangeError.checkValidIndex(index, this); - Jni.accessors - .setBooleanArrayElement(reference.pointer, index, value ? 1 : 0); + Jni.env.SetBooleanArrayElement(reference.pointer, index, value); } Uint8List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -187,12 +131,13 @@ extension BoolArray on JArray { extension ByteArray on JArray { int operator [](int index) { - return _elementAt(index, JniCallType.byteType).byte; + RangeError.checkValidIndex(index, this); + return Jni.env.GetByteArrayElement(reference.pointer, index); } void operator []=(int index, int value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setByteArrayElement(reference.pointer, index, value).check(); + Jni.env.SetByteArrayElement(reference.pointer, index, value); } Int8List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -222,12 +167,13 @@ extension ByteArray on JArray { /// the number of characters. extension CharArray on JArray { int operator [](int index) { - return _elementAt(index, JniCallType.charType).char; + RangeError.checkValidIndex(index, this); + return Jni.env.GetCharArrayElement(reference.pointer, index); } void operator []=(int index, int value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setCharArrayElement(reference.pointer, index, value).check(); + Jni.env.SetCharArrayElement(reference.pointer, index, value); } Uint16List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -253,12 +199,13 @@ extension CharArray on JArray { extension ShortArray on JArray { int operator [](int index) { - return _elementAt(index, JniCallType.shortType).short; + RangeError.checkValidIndex(index, this); + return Jni.env.GetShortArrayElement(reference.pointer, index); } void operator []=(int index, int value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setShortArrayElement(reference.pointer, index, value).check(); + Jni.env.SetShortArrayElement(reference.pointer, index, value); } Int16List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -284,12 +231,13 @@ extension ShortArray on JArray { extension IntArray on JArray { int operator [](int index) { - return _elementAt(index, JniCallType.intType).integer; + RangeError.checkValidIndex(index, this); + return Jni.env.GetIntArrayElement(reference.pointer, index); } void operator []=(int index, int value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setIntArrayElement(reference.pointer, index, value).check(); + Jni.env.SetIntArrayElement(reference.pointer, index, value); } Int32List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -315,12 +263,13 @@ extension IntArray on JArray { extension LongArray on JArray { int operator [](int index) { - return _elementAt(index, JniCallType.longType).long; + RangeError.checkValidIndex(index, this); + return Jni.env.GetLongArrayElement(reference.pointer, index); } void operator []=(int index, int value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setLongArrayElement(reference.pointer, index, value).check(); + Jni.env.SetLongArrayElement(reference.pointer, index, value); } Int64List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -346,12 +295,13 @@ extension LongArray on JArray { extension FloatArray on JArray { double operator [](int index) { - return _elementAt(index, JniCallType.floatType).float; + RangeError.checkValidIndex(index, this); + return Jni.env.GetFloatArrayElement(reference.pointer, index); } void operator []=(int index, double value) { RangeError.checkValidIndex(index, this); - Jni.accessors.setFloatArrayElement(reference.pointer, index, value).check(); + Jni.env.SetFloatArrayElement(reference.pointer, index, value); } Float32List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -377,14 +327,13 @@ extension FloatArray on JArray { extension DoubleArray on JArray { double operator [](int index) { - return _elementAt(index, JniCallType.doubleType).doubleFloat; + RangeError.checkValidIndex(index, this); + return Jni.env.GetDoubleArrayElement(reference.pointer, index); } void operator []=(int index, double value) { RangeError.checkValidIndex(index, this); - Jni.accessors - .setDoubleArrayElement(reference.pointer, index, value) - .check(); + Jni.env.SetDoubleArrayElement(reference.pointer, index, value); } Float64List getRange(int start, int end, {Allocator allocator = malloc}) { @@ -410,8 +359,9 @@ extension DoubleArray on JArray { extension ObjectArray on JArray { T operator [](int index) { + RangeError.checkValidIndex(index, this); return (elementType as JObjType).fromReference(JGlobalReference( - _elementAt(index, JniCallType.objectType).objectPointer)); + Jni.env.GetObjectArrayElement(reference.pointer, index))); } void operator []=(int index, T value) { diff --git a/pkgs/jni/lib/src/jclass.dart b/pkgs/jni/lib/src/jclass.dart index 62957e9cc..7f9bb4dfc 100644 --- a/pkgs/jni/lib/src/jclass.dart +++ b/pkgs/jni/lib/src/jclass.dart @@ -14,10 +14,7 @@ class JClass extends JObject { /// Constructs a [JClass] associated with the class or interface with /// the given string name. JClass.forName(String name) - : super.fromReference(using((arena) { - final cls = Jni.accessors.getClass(name.toNativeChars(arena)); - return JGlobalReference(cls.checkedClassRef); - })); + : super.fromReference(JGlobalReference(Jni.findClass(name))); JConstructorId constructorId(String signature) { return JConstructorId._(this, signature); @@ -43,13 +40,11 @@ class JClass extends JObject { /// A thin wrapper over a [JFieldIDPtr] of an instance field. extension type JInstanceFieldId._fromPointer(JFieldIDPtr pointer) { JInstanceFieldId._(JClass jClass, String name, String signature) - : pointer = using((arena) => Jni.accessors - .getFieldID( + : pointer = using((arena) => Jni.env.GetFieldID( jClass.reference.pointer, name.toNativeChars(arena), signature.toNativeChars(arena), - ) - .fieldID); + )); DartT get(JObject object, JAccessible type) { return type._instanceGet(object.reference.pointer, this as JFieldIDPtr); @@ -64,13 +59,11 @@ extension type JInstanceFieldId._fromPointer(JFieldIDPtr pointer) { /// A thin wrapper over a [JFieldIDPtr] of an static field. extension type JStaticFieldId._fromPointer(JFieldIDPtr pointer) { JStaticFieldId._(JClass jClass, String name, String signature) - : pointer = using((arena) => Jni.accessors - .getStaticFieldID( + : pointer = using((arena) => Jni.env.GetStaticFieldID( jClass.reference.pointer, name.toNativeChars(arena), signature.toNativeChars(arena), - ) - .fieldID); + )); DartT get(JClass jClass, JAccessible type) { return type._staticGet(jClass.reference.pointer, this as JFieldIDPtr); @@ -88,13 +81,11 @@ extension type JInstanceMethodId._fromPointer(JMethodIDPtr pointer) { JClass jClass, String name, String signature, - ) : pointer = using((arena) => Jni.accessors - .getMethodID( + ) : pointer = using((arena) => Jni.env.GetMethodID( jClass.reference.pointer, name.toNativeChars(arena), signature.toNativeChars(arena), - ) - .methodID); + )); /// Calls the instance method on [object] with the given arguments. DartT call( @@ -113,13 +104,11 @@ extension type JStaticMethodId._fromPointer(JMethodIDPtr pointer) { JClass jClass, String name, String signature, - ) : pointer = using((arena) => Jni.accessors - .getStaticMethodID( + ) : pointer = using((arena) => Jni.env.GetStaticMethodID( jClass.reference.pointer, name.toNativeChars(arena), signature.toNativeChars(arena), - ) - .methodID); + )); /// Calls the static method on [jClass] with the given arguments. DartT call( @@ -137,13 +126,11 @@ extension type JConstructorId._fromPointer(JMethodIDPtr pointer) { JConstructorId._( JClass jClass, String signature, - ) : pointer = using((arena) => Jni.accessors - .getMethodID( + ) : pointer = using((arena) => Jni.env.GetMethodID( jClass.reference.pointer, ''.toNativeChars(arena), signature.toNativeChars(arena), - ) - .methodID); + )); /// Constructs an instance of [jClass] with the given arguments. DartT call(JClass jClass, diff --git a/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart index 9f5eed541..4fa609cbd 100644 --- a/pkgs/jni/lib/src/jni.dart +++ b/pkgs/jni/lib/src/jni.dart @@ -179,6 +179,28 @@ abstract final class Jni { return _bindings.GetJavaVM(); } + /// Finds the class from its [name]. + /// + /// Uses the correct class loader on Android. + /// Prefer this over `Jni.env.FindClass`. + static JClassPtr findClass(String name) { + return using((arena) => _bindings.FindClass(name.toNativeChars(arena))) + .checkedClassRef; + } + + /// Throws an exception. + // TODO(#561): Throw an actual `JThrowable`. + static void throwException(JThrowablePtr exception) { + final details = _bindings.GetExceptionDetails(exception); + final env = Jni.env; + final message = env.toDartString(details.message); + final stacktrace = env.toDartString(details.stacktrace); + env.DeleteGlobalRef(exception); + env.DeleteGlobalRef(details.message); + env.DeleteGlobalRef(details.stacktrace); + throw JniException(message, stacktrace); + } + /// Returns the instance of [GlobalJniEnvStruct], which is an abstraction over /// JNIEnv without the same-thread restriction. static Pointer _fetchGlobalEnv() { @@ -195,8 +217,6 @@ abstract final class Jni { /// any thread, and always returns global object references. static final env = GlobalJniEnv(_fetchGlobalEnv()); - static final accessors = JniAccessors(_bindings.GetAccessors()); - /// Returns current application context on Android. static JReference getCachedApplicationContext() { return JGlobalReference(_bindings.GetApplicationContext()); diff --git a/pkgs/jni/lib/src/jobject.dart b/pkgs/jni/lib/src/jobject.dart index 1822d5e08..df3fa94e9 100644 --- a/pkgs/jni/lib/src/jobject.dart +++ b/pkgs/jni/lib/src/jobject.dart @@ -6,7 +6,6 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; -import 'accessors.dart'; import 'jni.dart'; import 'jreference.dart'; import 'lang/jstring.dart'; @@ -60,7 +59,7 @@ class JObject { JClass get jClass { final classRef = Jni.env.GetObjectClass(reference.pointer); if (classRef == nullptr) { - Jni.accessors.throwException(Jni.env.ExceptionOccurred()); + Jni.throwException(Jni.env.ExceptionOccurred()); } return JClass.fromReference(JGlobalReference(classRef)); } diff --git a/pkgs/jni/lib/src/jprimitives.dart b/pkgs/jni/lib/src/jprimitives.dart index f6a42af77..6516a6b2e 100644 --- a/pkgs/jni/lib/src/jprimitives.dart +++ b/pkgs/jni/lib/src/jprimitives.dart @@ -15,7 +15,10 @@ abstract final class jbyte extends JPrimitive { } final class jbyteType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jbyteType(); @override @@ -52,6 +55,14 @@ final class jbyteType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, int val) { return Jni.env.SetStaticByteField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewByteArray(length)), + ); + } } abstract final class jboolean extends JPrimitive { @@ -59,7 +70,10 @@ abstract final class jboolean extends JPrimitive { } final class jbooleanType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jbooleanType(); @override @@ -96,6 +110,14 @@ final class jbooleanType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, bool val) { return Jni.env.SetStaticBooleanField(clazz, fieldID, val ? 1 : 0); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewBooleanArray(length)), + ); + } } abstract final class jchar extends JPrimitive { @@ -103,7 +125,10 @@ abstract final class jchar extends JPrimitive { } final class jcharType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jcharType(); @override @@ -140,6 +165,14 @@ final class jcharType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, int val) { return Jni.env.SetStaticCharField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewCharArray(length)), + ); + } } abstract final class jshort extends JPrimitive { @@ -147,7 +180,10 @@ abstract final class jshort extends JPrimitive { } final class jshortType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jshortType(); @override @@ -184,6 +220,14 @@ final class jshortType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, int val) { return Jni.env.SetStaticShortField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewShortArray(length)), + ); + } } abstract final class jint extends JPrimitive { @@ -191,7 +235,7 @@ abstract final class jint extends JPrimitive { } final class jintType extends JType - with JCallable, JAccessible { + with JCallable, JAccessible, JArrayElementType { const jintType(); @override @@ -228,6 +272,14 @@ final class jintType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, int val) { return Jni.env.SetStaticIntField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewIntArray(length)), + ); + } } abstract final class jlong extends JPrimitive { @@ -235,7 +287,10 @@ abstract final class jlong extends JPrimitive { } final class jlongType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jlongType(); @override @@ -272,6 +327,14 @@ final class jlongType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, int val) { return Jni.env.SetStaticLongField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewLongArray(length)), + ); + } } abstract final class jfloat extends JPrimitive { @@ -279,7 +342,10 @@ abstract final class jfloat extends JPrimitive { } final class jfloatType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jfloatType(); @override @@ -316,6 +382,14 @@ final class jfloatType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, double val) { return Jni.env.SetStaticFloatField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewFloatArray(length)), + ); + } } abstract final class jdouble extends JPrimitive { @@ -323,7 +397,10 @@ abstract final class jdouble extends JPrimitive { } final class jdoubleType extends JType - with JCallable, JAccessible { + with + JCallable, + JAccessible, + JArrayElementType { const jdoubleType(); @override @@ -360,6 +437,14 @@ final class jdoubleType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, double val) { return Jni.env.SetStaticDoubleField(clazz, fieldID, val); } + + @override + JArray _newArray(int length) { + return JArray.fromReference( + this, + JGlobalReference(Jni.env.NewDoubleArray(length)), + ); + } } abstract final class jvoid extends JPrimitive { diff --git a/pkgs/jni/lib/src/method_invocation.dart b/pkgs/jni/lib/src/method_invocation.dart index 5150aabe3..6ed82d67f 100644 --- a/pkgs/jni/lib/src/method_invocation.dart +++ b/pkgs/jni/lib/src/method_invocation.dart @@ -4,11 +4,11 @@ import 'dart:ffi'; -import 'jarray.dart'; import 'jobject.dart'; import 'jreference.dart'; import 'lang/jstring.dart'; import 'third_party/generated_bindings.dart'; +import 'types.dart'; class $MethodInvocation { final Pointer result; diff --git a/pkgs/jni/lib/src/nio/jbyte_buffer.dart b/pkgs/jni/lib/src/nio/jbyte_buffer.dart index c7ef927af..35b4f1774 100644 --- a/pkgs/jni/lib/src/nio/jbyte_buffer.dart +++ b/pkgs/jni/lib/src/nio/jbyte_buffer.dart @@ -5,7 +5,6 @@ import 'dart:ffi'; import 'dart:typed_data'; -import '../jarray.dart'; import '../jni.dart'; import '../jobject.dart'; import '../jreference.dart'; diff --git a/pkgs/jni/lib/src/third_party/global_env_extensions.dart b/pkgs/jni/lib/src/third_party/global_env_extensions.dart index 3fda9d4a1..ee8fbeeae 100644 --- a/pkgs/jni/lib/src/third_party/global_env_extensions.dart +++ b/pkgs/jni/lib/src/third_party/global_env_extensions.dart @@ -43,7 +43,7 @@ class GlobalJniEnv { final ffi.Pointer ptr; GlobalJniEnv(this.ptr); late final _GetVersion = - ptr.ref.GetVersion.asFunction(); + ptr.ref.GetVersion.asFunction(isLeaf: true); int GetVersion() => _GetVersion().integer; @@ -56,7 +56,8 @@ class GlobalJniEnv { _DefineClass(name, loader, buf, bufLen).value; late final _FindClass = ptr.ref.FindClass - .asFunction name)>(); + .asFunction name)>( + isLeaf: true); JClassPtr FindClass(ffi.Pointer name) => _FindClass(name).value; @@ -80,12 +81,13 @@ class GlobalJniEnv { _ToReflectedMethod(cls, methodId, isStatic).objectPointer; late final _GetSuperclass = ptr.ref.GetSuperclass - .asFunction(); + .asFunction(isLeaf: true); JClassPtr GetSuperclass(JClassPtr clazz) => _GetSuperclass(clazz).value; late final _IsAssignableFrom = ptr.ref.IsAssignableFrom - .asFunction(); + .asFunction( + isLeaf: true); bool IsAssignableFrom(JClassPtr clazz1, JClassPtr clazz2) => _IsAssignableFrom(clazz1, clazz2).boolean; @@ -139,30 +141,31 @@ class GlobalJniEnv { JObjectPtr PopLocalFrame(JObjectPtr result) => _PopLocalFrame(result).objectPointer; - late final _NewGlobalRef = - ptr.ref.NewGlobalRef.asFunction(); + late final _NewGlobalRef = ptr.ref.NewGlobalRef + .asFunction(isLeaf: true); JObjectPtr NewGlobalRef(JObjectPtr obj) => _NewGlobalRef(obj).objectPointer; late final _DeleteGlobalRef = ptr.ref.DeleteGlobalRef - .asFunction(); + .asFunction(isLeaf: true); void DeleteGlobalRef(JObjectPtr globalRef) => _DeleteGlobalRef(globalRef).check(); late final _DeleteLocalRef = ptr.ref.DeleteLocalRef - .asFunction(); + .asFunction(isLeaf: true); void DeleteLocalRef(JObjectPtr localRef) => _DeleteLocalRef(localRef).check(); late final _IsSameObject = ptr.ref.IsSameObject - .asFunction(); + .asFunction( + isLeaf: true); bool IsSameObject(JObjectPtr ref1, JObjectPtr ref2) => _IsSameObject(ref1, ref2).boolean; - late final _NewLocalRef = - ptr.ref.NewLocalRef.asFunction(); + late final _NewLocalRef = ptr.ref.NewLocalRef + .asFunction(isLeaf: true); JObjectPtr NewLocalRef(JObjectPtr obj) => _NewLocalRef(obj).objectPointer; @@ -192,7 +195,7 @@ class GlobalJniEnv { _NewObjectA(clazz, methodID, args).objectPointer; late final _GetObjectClass = ptr.ref.GetObjectClass - .asFunction(); + .asFunction(isLeaf: true); JClassPtr GetObjectClass(JObjectPtr obj) => _GetObjectClass(obj).value; @@ -204,7 +207,7 @@ class GlobalJniEnv { late final _GetMethodID = ptr.ref.GetMethodID.asFunction< JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, - ffi.Pointer sig)>(); + ffi.Pointer sig)>(isLeaf: true); JMethodIDPtr GetMethodID(JClassPtr clazz, ffi.Pointer name, ffi.Pointer sig) => @@ -532,126 +535,141 @@ class GlobalJniEnv { late final _GetFieldID = ptr.ref.GetFieldID.asFunction< JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, - ffi.Pointer sig)>(); + ffi.Pointer sig)>(isLeaf: true); JFieldIDPtr GetFieldID(JClassPtr clazz, ffi.Pointer name, ffi.Pointer sig) => _GetFieldID(clazz, name, sig).fieldID; late final _GetObjectField = ptr.ref.GetObjectField - .asFunction(); + .asFunction( + isLeaf: true); JObjectPtr GetObjectField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetObjectField(obj, fieldID).objectPointer; late final _GetBooleanField = ptr.ref.GetBooleanField - .asFunction(); + .asFunction( + isLeaf: true); bool GetBooleanField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetBooleanField(obj, fieldID).boolean; late final _GetByteField = ptr.ref.GetByteField - .asFunction(); + .asFunction( + isLeaf: true); int GetByteField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetByteField(obj, fieldID).byte; late final _GetCharField = ptr.ref.GetCharField - .asFunction(); + .asFunction( + isLeaf: true); int GetCharField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetCharField(obj, fieldID).char; late final _GetShortField = ptr.ref.GetShortField - .asFunction(); + .asFunction( + isLeaf: true); int GetShortField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetShortField(obj, fieldID).short; late final _GetIntField = ptr.ref.GetIntField - .asFunction(); + .asFunction( + isLeaf: true); int GetIntField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetIntField(obj, fieldID).integer; late final _GetLongField = ptr.ref.GetLongField - .asFunction(); + .asFunction( + isLeaf: true); int GetLongField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetLongField(obj, fieldID).long; late final _GetFloatField = ptr.ref.GetFloatField - .asFunction(); + .asFunction( + isLeaf: true); double GetFloatField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetFloatField(obj, fieldID).float; late final _GetDoubleField = ptr.ref.GetDoubleField - .asFunction(); + .asFunction( + isLeaf: true); double GetDoubleField(JObjectPtr obj, JFieldIDPtr fieldID) => _GetDoubleField(obj, fieldID).doubleFloat; late final _SetObjectField = ptr.ref.SetObjectField.asFunction< JThrowablePtr Function( - JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val)>(); + JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val)>(isLeaf: true); void SetObjectField(JObjectPtr obj, JFieldIDPtr fieldID, JObjectPtr val) => _SetObjectField(obj, fieldID, val).check(); late final _SetBooleanField = ptr.ref.SetBooleanField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetBooleanField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetBooleanField(obj, fieldID, val).check(); late final _SetByteField = ptr.ref.SetByteField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetByteField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetByteField(obj, fieldID, val).check(); late final _SetCharField = ptr.ref.SetCharField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetCharField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetCharField(obj, fieldID, val).check(); late final _SetShortField = ptr.ref.SetShortField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetShortField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetShortField(obj, fieldID, val).check(); late final _SetIntField = ptr.ref.SetIntField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetIntField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetIntField(obj, fieldID, val).check(); late final _SetLongField = ptr.ref.SetLongField.asFunction< - JThrowablePtr Function(JObjectPtr obj, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JObjectPtr obj, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetLongField(JObjectPtr obj, JFieldIDPtr fieldID, int val) => _SetLongField(obj, fieldID, val).check(); late final _SetFloatField = ptr.ref.SetFloatField.asFunction< JThrowablePtr Function( - JObjectPtr obj, JFieldIDPtr fieldID, double val)>(); + JObjectPtr obj, JFieldIDPtr fieldID, double val)>(isLeaf: true); void SetFloatField(JObjectPtr obj, JFieldIDPtr fieldID, double val) => _SetFloatField(obj, fieldID, val).check(); late final _SetDoubleField = ptr.ref.SetDoubleField.asFunction< JThrowablePtr Function( - JObjectPtr obj, JFieldIDPtr fieldID, double val)>(); + JObjectPtr obj, JFieldIDPtr fieldID, double val)>(isLeaf: true); void SetDoubleField(JObjectPtr obj, JFieldIDPtr fieldID, double val) => _SetDoubleField(obj, fieldID, val).check(); late final _GetStaticMethodID = ptr.ref.GetStaticMethodID.asFunction< JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, - ffi.Pointer sig)>(); + ffi.Pointer sig)>(isLeaf: true); JMethodIDPtr GetStaticMethodID(JClassPtr clazz, ffi.Pointer name, ffi.Pointer sig) => @@ -804,120 +822,135 @@ class GlobalJniEnv { late final _GetStaticFieldID = ptr.ref.GetStaticFieldID.asFunction< JniPointerResult Function(JClassPtr clazz, ffi.Pointer name, - ffi.Pointer sig)>(); + ffi.Pointer sig)>(isLeaf: true); JFieldIDPtr GetStaticFieldID(JClassPtr clazz, ffi.Pointer name, ffi.Pointer sig) => _GetStaticFieldID(clazz, name, sig).fieldID; late final _GetStaticObjectField = ptr.ref.GetStaticObjectField - .asFunction(); + .asFunction( + isLeaf: true); JObjectPtr GetStaticObjectField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticObjectField(clazz, fieldID).objectPointer; late final _GetStaticBooleanField = ptr.ref.GetStaticBooleanField - .asFunction(); + .asFunction( + isLeaf: true); bool GetStaticBooleanField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticBooleanField(clazz, fieldID).boolean; late final _GetStaticByteField = ptr.ref.GetStaticByteField - .asFunction(); + .asFunction( + isLeaf: true); int GetStaticByteField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticByteField(clazz, fieldID).byte; late final _GetStaticCharField = ptr.ref.GetStaticCharField - .asFunction(); + .asFunction( + isLeaf: true); int GetStaticCharField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticCharField(clazz, fieldID).char; late final _GetStaticShortField = ptr.ref.GetStaticShortField - .asFunction(); + .asFunction( + isLeaf: true); int GetStaticShortField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticShortField(clazz, fieldID).short; late final _GetStaticIntField = ptr.ref.GetStaticIntField - .asFunction(); + .asFunction( + isLeaf: true); int GetStaticIntField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticIntField(clazz, fieldID).integer; late final _GetStaticLongField = ptr.ref.GetStaticLongField - .asFunction(); + .asFunction( + isLeaf: true); int GetStaticLongField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticLongField(clazz, fieldID).long; late final _GetStaticFloatField = ptr.ref.GetStaticFloatField - .asFunction(); + .asFunction( + isLeaf: true); double GetStaticFloatField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticFloatField(clazz, fieldID).float; late final _GetStaticDoubleField = ptr.ref.GetStaticDoubleField - .asFunction(); + .asFunction( + isLeaf: true); double GetStaticDoubleField(JClassPtr clazz, JFieldIDPtr fieldID) => _GetStaticDoubleField(clazz, fieldID).doubleFloat; late final _SetStaticObjectField = ptr.ref.SetStaticObjectField.asFunction< JThrowablePtr Function( - JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val)>(); + JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val)>(isLeaf: true); void SetStaticObjectField( JClassPtr clazz, JFieldIDPtr fieldID, JObjectPtr val) => _SetStaticObjectField(clazz, fieldID, val).check(); late final _SetStaticBooleanField = ptr.ref.SetStaticBooleanField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticBooleanField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticBooleanField(clazz, fieldID, val).check(); late final _SetStaticByteField = ptr.ref.SetStaticByteField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticByteField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticByteField(clazz, fieldID, val).check(); late final _SetStaticCharField = ptr.ref.SetStaticCharField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticCharField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticCharField(clazz, fieldID, val).check(); late final _SetStaticShortField = ptr.ref.SetStaticShortField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticShortField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticShortField(clazz, fieldID, val).check(); late final _SetStaticIntField = ptr.ref.SetStaticIntField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticIntField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticIntField(clazz, fieldID, val).check(); late final _SetStaticLongField = ptr.ref.SetStaticLongField.asFunction< - JThrowablePtr Function(JClassPtr clazz, JFieldIDPtr fieldID, int val)>(); + JThrowablePtr Function( + JClassPtr clazz, JFieldIDPtr fieldID, int val)>(isLeaf: true); void SetStaticLongField(JClassPtr clazz, JFieldIDPtr fieldID, int val) => _SetStaticLongField(clazz, fieldID, val).check(); late final _SetStaticFloatField = ptr.ref.SetStaticFloatField.asFunction< JThrowablePtr Function( - JClassPtr clazz, JFieldIDPtr fieldID, double val)>(); + JClassPtr clazz, JFieldIDPtr fieldID, double val)>(isLeaf: true); void SetStaticFloatField(JClassPtr clazz, JFieldIDPtr fieldID, double val) => _SetStaticFloatField(clazz, fieldID, val).check(); late final _SetStaticDoubleField = ptr.ref.SetStaticDoubleField.asFunction< JThrowablePtr Function( - JClassPtr clazz, JFieldIDPtr fieldID, double val)>(); + JClassPtr clazz, JFieldIDPtr fieldID, double val)>(isLeaf: true); void SetStaticDoubleField(JClassPtr clazz, JFieldIDPtr fieldID, double val) => _SetStaticDoubleField(clazz, fieldID, val).check(); @@ -929,7 +962,7 @@ class GlobalJniEnv { _NewString(unicodeChars, len).objectPointer; late final _GetStringLength = ptr.ref.GetStringLength - .asFunction(); + .asFunction(isLeaf: true); int GetStringLength(JStringPtr string) => _GetStringLength(string).integer; @@ -955,7 +988,7 @@ class GlobalJniEnv { _NewStringUTF(bytes).objectPointer; late final _GetStringUTFLength = ptr.ref.GetStringUTFLength - .asFunction(); + .asFunction(isLeaf: true); int GetStringUTFLength(JStringPtr string) => _GetStringUTFLength(string).integer; @@ -974,8 +1007,8 @@ class GlobalJniEnv { void ReleaseStringUTFChars(JStringPtr string, ffi.Pointer utf) => _ReleaseStringUTFChars(string, utf).check(); - late final _GetArrayLength = - ptr.ref.GetArrayLength.asFunction(); + late final _GetArrayLength = ptr.ref.GetArrayLength + .asFunction(isLeaf: true); int GetArrayLength(JArrayPtr array) => _GetArrayLength(array).integer; @@ -988,14 +1021,15 @@ class GlobalJniEnv { _NewObjectArray(length, elementClass, initialElement).objectPointer; late final _GetObjectArrayElement = ptr.ref.GetObjectArrayElement - .asFunction(); + .asFunction( + isLeaf: true); JObjectPtr GetObjectArrayElement(JObjectArrayPtr array, int index) => _GetObjectArrayElement(array, index).objectPointer; late final _SetObjectArrayElement = ptr.ref.SetObjectArrayElement.asFunction< JThrowablePtr Function( - JObjectArrayPtr array, int index, JObjectPtr val)>(); + JObjectArrayPtr array, int index, JObjectPtr val)>(isLeaf: true); void SetObjectArrayElement( JObjectArrayPtr array, int index, JObjectPtr val) => @@ -1335,7 +1369,8 @@ class GlobalJniEnv { int MonitorExit(JObjectPtr obj) => _MonitorExit(obj).integer; late final _GetJavaVM = ptr.ref.GetJavaVM - .asFunction> vm)>(); + .asFunction> vm)>( + isLeaf: true); int GetJavaVM(ffi.Pointer> vm) => _GetJavaVM(vm).integer; @@ -1388,19 +1423,19 @@ class GlobalJniEnv { void ReleaseStringCritical(JStringPtr str, ffi.Pointer carray) => _ReleaseStringCritical(str, carray).check(); - late final _NewWeakGlobalRef = - ptr.ref.NewWeakGlobalRef.asFunction(); + late final _NewWeakGlobalRef = ptr.ref.NewWeakGlobalRef + .asFunction(isLeaf: true); JWeakPtr NewWeakGlobalRef(JObjectPtr obj) => _NewWeakGlobalRef(obj).objectPointer; late final _DeleteWeakGlobalRef = ptr.ref.DeleteWeakGlobalRef - .asFunction(); + .asFunction(isLeaf: true); void DeleteWeakGlobalRef(JWeakPtr obj) => _DeleteWeakGlobalRef(obj).check(); late final _ExceptionCheck = - ptr.ref.ExceptionCheck.asFunction(); + ptr.ref.ExceptionCheck.asFunction(isLeaf: true); bool ExceptionCheck() => _ExceptionCheck().boolean; @@ -1411,155 +1446,132 @@ class GlobalJniEnv { _NewDirectByteBuffer(address, capacity).objectPointer; late final _GetDirectBufferAddress = ptr.ref.GetDirectBufferAddress - .asFunction(); + .asFunction(isLeaf: true); ffi.Pointer GetDirectBufferAddress(JObjectPtr buf) => _GetDirectBufferAddress(buf).getPointer(); late final _GetDirectBufferCapacity = ptr.ref.GetDirectBufferCapacity - .asFunction(); + .asFunction(isLeaf: true); int GetDirectBufferCapacity(JObjectPtr buf) => _GetDirectBufferCapacity(buf).long; - late final _GetObjectRefType = - ptr.ref.GetObjectRefType.asFunction(); + late final _GetObjectRefType = ptr.ref.GetObjectRefType + .asFunction(isLeaf: true); int GetObjectRefType(JObjectPtr obj) => _GetObjectRefType(obj).integer; -} -/// Wraps over the function pointers in JniAccessorsStruct and exposes them as -/// methods. -class JniAccessors { - final ffi.Pointer ptr; - JniAccessors(this.ptr); - - late final _getClass = ptr.ref.getClass.asFunction< - JniClassLookupResult Function(ffi.Pointer internalName)>(); - JniClassLookupResult getClass(ffi.Pointer internalName) => - _getClass(internalName); - - late final _getFieldID = ptr.ref.getFieldID.asFunction< - JniPointerResult Function(JClassPtr cls, ffi.Pointer fieldName, - ffi.Pointer signature)>(); - JniPointerResult getFieldID(JClassPtr cls, ffi.Pointer fieldName, - ffi.Pointer signature) => - _getFieldID(cls, fieldName, signature); - - late final _getStaticFieldID = ptr.ref.getStaticFieldID.asFunction< - JniPointerResult Function(JClassPtr cls, ffi.Pointer fieldName, - ffi.Pointer signature)>(); - JniPointerResult getStaticFieldID(JClassPtr cls, - ffi.Pointer fieldName, ffi.Pointer signature) => - _getStaticFieldID(cls, fieldName, signature); - - late final _getMethodID = ptr.ref.getMethodID.asFunction< - JniPointerResult Function(JClassPtr cls, ffi.Pointer methodName, - ffi.Pointer signature)>(); - JniPointerResult getMethodID(JClassPtr cls, ffi.Pointer methodName, - ffi.Pointer signature) => - _getMethodID(cls, methodName, signature); - - late final _getStaticMethodID = ptr.ref.getStaticMethodID.asFunction< - JniPointerResult Function(JClassPtr cls, ffi.Pointer methodName, - ffi.Pointer signature)>(); - JniPointerResult getStaticMethodID(JClassPtr cls, - ffi.Pointer methodName, ffi.Pointer signature) => - _getStaticMethodID(cls, methodName, signature); - - late final _newObject = ptr.ref.newObject.asFunction< - JniResult Function( - JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args)>(); - JniResult newObject( - JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args) => - _newObject(cls, ctor, args); + late final _GetBooleanArrayElement = ptr.ref.GetBooleanArrayElement + .asFunction( + isLeaf: true); - late final _newPrimitiveArray = ptr.ref.newPrimitiveArray - .asFunction(); - JniResult newPrimitiveArray(int length, int type) => - _newPrimitiveArray(length, type); + bool GetBooleanArrayElement(JBooleanArrayPtr array, int index) => + _GetBooleanArrayElement(array, index).boolean; - late final _newObjectArray = ptr.ref.newObjectArray.asFunction< - JniResult Function( - int length, JClassPtr elementClass, JObjectPtr initialElement)>(); - JniResult newObjectArray( - int length, JClassPtr elementClass, JObjectPtr initialElement) => - _newObjectArray(length, elementClass, initialElement); + late final _SetBooleanArrayElement = ptr.ref.SetBooleanArrayElement + .asFunction< + JThrowablePtr Function( + JBooleanArrayPtr array, int index, int val)>(isLeaf: true); - late final _getArrayElement = ptr.ref.getArrayElement - .asFunction(); - JniResult getArrayElement(JArrayPtr array, int index, int type) => - _getArrayElement(array, index, type); + void SetBooleanArrayElement(JBooleanArrayPtr array, int index, bool value) => + _SetBooleanArrayElement(array, index, value ? 1 : 0).check(); - late final _setBooleanArrayElement = ptr.ref.setBooleanArrayElement - .asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setBooleanArrayElement(JArrayPtr array, int index, int value) => - _setBooleanArrayElement(array, index, value); - - late final _setByteArrayElement = ptr.ref.setByteArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setByteArrayElement(JArrayPtr array, int index, int value) => - _setByteArrayElement(array, index, value); - - late final _setShortArrayElement = ptr.ref.setShortArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setShortArrayElement(JArrayPtr array, int index, int value) => - _setShortArrayElement(array, index, value); - - late final _setCharArrayElement = ptr.ref.setCharArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setCharArrayElement(JArrayPtr array, int index, int value) => - _setCharArrayElement(array, index, value); - - late final _setIntArrayElement = ptr.ref.setIntArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setIntArrayElement(JArrayPtr array, int index, int value) => - _setIntArrayElement(array, index, value); - - late final _setLongArrayElement = ptr.ref.setLongArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, int value)>(); - JThrowablePtr setLongArrayElement(JArrayPtr array, int index, int value) => - _setLongArrayElement(array, index, value); - - late final _setFloatArrayElement = ptr.ref.setFloatArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, double value)>(); - JThrowablePtr setFloatArrayElement( - JArrayPtr array, int index, double value) => - _setFloatArrayElement(array, index, value); - - late final _setDoubleArrayElement = ptr.ref.setDoubleArrayElement.asFunction< - JThrowablePtr Function(JArrayPtr array, int index, double value)>(); - JThrowablePtr setDoubleArrayElement( - JArrayPtr array, int index, double value) => - _setDoubleArrayElement(array, index, value); - - late final _callMethod = ptr.ref.callMethod.asFunction< - JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, int callType, - ffi.Pointer args)>(); - JniResult callMethod(JObjectPtr obj, JMethodIDPtr methodID, int callType, - ffi.Pointer args) => - _callMethod(obj, methodID, callType, args); - - late final _callStaticMethod = ptr.ref.callStaticMethod.asFunction< - JniResult Function(JClassPtr cls, JMethodIDPtr methodID, int callType, - ffi.Pointer args)>(); - JniResult callStaticMethod(JClassPtr cls, JMethodIDPtr methodID, int callType, - ffi.Pointer args) => - _callStaticMethod(cls, methodID, callType, args); - - late final _getField = ptr.ref.getField.asFunction< - JniResult Function(JObjectPtr obj, JFieldIDPtr fieldID, int callType)>(); - JniResult getField(JObjectPtr obj, JFieldIDPtr fieldID, int callType) => - _getField(obj, fieldID, callType); - - late final _getStaticField = ptr.ref.getStaticField.asFunction< - JniResult Function(JClassPtr cls, JFieldIDPtr fieldID, int callType)>(); - JniResult getStaticField(JClassPtr cls, JFieldIDPtr fieldID, int callType) => - _getStaticField(cls, fieldID, callType); - - late final _getExceptionDetails = ptr.ref.getExceptionDetails - .asFunction(); - JniExceptionDetails getExceptionDetails(JThrowablePtr exception) => - _getExceptionDetails(exception); + late final _GetByteArrayElement = ptr.ref.GetByteArrayElement + .asFunction( + isLeaf: true); + + int GetByteArrayElement(JByteArrayPtr array, int index) => + _GetByteArrayElement(array, index).byte; + + late final _SetByteArrayElement = ptr.ref.SetByteArrayElement.asFunction< + JThrowablePtr Function( + JByteArrayPtr array, int index, int val)>(isLeaf: true); + + void SetByteArrayElement(JByteArrayPtr array, int index, int value) => + _SetByteArrayElement(array, index, value).check(); + + late final _GetCharArrayElement = ptr.ref.GetCharArrayElement + .asFunction( + isLeaf: true); + + int GetCharArrayElement(JCharArrayPtr array, int index) => + _GetCharArrayElement(array, index).char; + + late final _SetCharArrayElement = ptr.ref.SetCharArrayElement.asFunction< + JThrowablePtr Function( + JCharArrayPtr array, int index, int val)>(isLeaf: true); + + void SetCharArrayElement(JCharArrayPtr array, int index, int value) => + _SetCharArrayElement(array, index, value).check(); + + late final _GetShortArrayElement = ptr.ref.GetShortArrayElement + .asFunction( + isLeaf: true); + + int GetShortArrayElement(JShortArrayPtr array, int index) => + _GetShortArrayElement(array, index).short; + + late final _SetShortArrayElement = ptr.ref.SetShortArrayElement.asFunction< + JThrowablePtr Function( + JShortArrayPtr array, int index, int val)>(isLeaf: true); + + void SetShortArrayElement(JShortArrayPtr array, int index, int value) => + _SetShortArrayElement(array, index, value).check(); + + late final _GetIntArrayElement = ptr.ref.GetIntArrayElement + .asFunction( + isLeaf: true); + + int GetIntArrayElement(JIntArrayPtr array, int index) => + _GetIntArrayElement(array, index).integer; + + late final _SetIntArrayElement = ptr.ref.SetIntArrayElement.asFunction< + JThrowablePtr Function( + JIntArrayPtr array, int index, int val)>(isLeaf: true); + + void SetIntArrayElement(JIntArrayPtr array, int index, int value) => + _SetIntArrayElement(array, index, value).check(); + + late final _GetLongArrayElement = ptr.ref.GetLongArrayElement + .asFunction( + isLeaf: true); + + int GetLongArrayElement(JLongArrayPtr array, int index) => + _GetLongArrayElement(array, index).long; + + late final _SetLongArrayElement = ptr.ref.SetLongArrayElement.asFunction< + JThrowablePtr Function( + JLongArrayPtr array, int index, int val)>(isLeaf: true); + + void SetLongArrayElement(JLongArrayPtr array, int index, int value) => + _SetLongArrayElement(array, index, value).check(); + + late final _GetFloatArrayElement = ptr.ref.GetFloatArrayElement + .asFunction( + isLeaf: true); + + double GetFloatArrayElement(JFloatArrayPtr array, int index) => + _GetFloatArrayElement(array, index).float; + + late final _SetFloatArrayElement = ptr.ref.SetFloatArrayElement.asFunction< + JThrowablePtr Function( + JFloatArrayPtr array, int index, double val)>(isLeaf: true); + + void SetFloatArrayElement(JFloatArrayPtr array, int index, double value) => + _SetFloatArrayElement(array, index, value).check(); + + late final _GetDoubleArrayElement = ptr.ref.GetDoubleArrayElement + .asFunction( + isLeaf: true); + + double GetDoubleArrayElement(JDoubleArrayPtr array, int index) => + _GetDoubleArrayElement(array, index).doubleFloat; + + late final _SetDoubleArrayElement = ptr.ref.SetDoubleArrayElement.asFunction< + JThrowablePtr Function( + JDoubleArrayPtr array, int index, double val)>(isLeaf: true); + + void SetDoubleArrayElement(JDoubleArrayPtr array, int index, double value) => + _SetDoubleArrayElement(array, index, value).check(); } diff --git a/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart index f7007c102..8f03912ba 100644 --- a/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart +++ b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart @@ -63,15 +63,40 @@ class JniBindings { lookup) : _lookup = lookup; - ffi.Pointer GetAccessors() { - return _GetAccessors(); + late final ffi.Pointer _tlsKey = + _lookup('tlsKey'); + + int get tlsKey => _tlsKey.value; + + set tlsKey(int value) => _tlsKey.value = value; + + JniClassLookupResult FindClass( + ffi.Pointer name, + ) { + return _FindClass( + name, + ); + } + + late final _FindClassPtr = _lookup< + ffi.NativeFunction< + JniClassLookupResult Function(ffi.Pointer)>>('FindClass'); + late final _FindClass = _FindClassPtr.asFunction< + JniClassLookupResult Function(ffi.Pointer)>(); + + JniExceptionDetails GetExceptionDetails( + JThrowablePtr exception, + ) { + return _GetExceptionDetails( + exception, + ); } - late final _GetAccessorsPtr = - _lookup Function()>>( - 'GetAccessors'); - late final _GetAccessors = - _GetAccessorsPtr.asFunction Function()>(); + late final _GetExceptionDetailsPtr = + _lookup>( + 'GetExceptionDetails'); + late final _GetExceptionDetails = _GetExceptionDetailsPtr.asFunction< + JniExceptionDetails Function(JThrowablePtr)>(); ffi.Pointer GetJavaVM() { return _GetJavaVM(); @@ -291,6 +316,9 @@ class JniBindings { _GetGlobalEnvPtr.asFunction Function()>(); } +typedef pthread_key_t = __darwin_pthread_key_t; +typedef __darwin_pthread_key_t = ffi.UnsignedLong; + /// Types used by JNI API to distinguish between primitive types. abstract class JniCallType { static const int booleanType = 0; @@ -382,154 +410,6 @@ final class JniExceptionDetails extends ffi.Struct { } typedef JStringPtr = JObjectPtr; - -/// This struct contains functions which wrap method call / field access conveniently along with -/// exception checking. -/// -/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us -/// to check for and clear the exception before returning to dart code, which requires these functions -/// to return result types. -final class JniAccessorsStruct extends ffi.Struct { - external ffi.Pointer< - ffi.NativeFunction< - JniClassLookupResult Function( - ffi.Pointer internalName)>> getClass; - - external ffi.Pointer< - ffi.NativeFunction< - JniPointerResult Function( - JClassPtr cls, - ffi.Pointer fieldName, - ffi.Pointer signature)>> getFieldID; - - external ffi.Pointer< - ffi.NativeFunction< - JniPointerResult Function( - JClassPtr cls, - ffi.Pointer fieldName, - ffi.Pointer signature)>> getStaticFieldID; - - external ffi.Pointer< - ffi.NativeFunction< - JniPointerResult Function( - JClassPtr cls, - ffi.Pointer methodName, - ffi.Pointer signature)>> getMethodID; - - external ffi.Pointer< - ffi.NativeFunction< - JniPointerResult Function( - JClassPtr cls, - ffi.Pointer methodName, - ffi.Pointer signature)>> getStaticMethodID; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function( - JClassPtr cls, JMethodIDPtr ctor, ffi.Pointer args)>> - newObject; - - external ffi.Pointer< - ffi - .NativeFunction> - newPrimitiveArray; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function(JSizeMarker length, JClassPtr elementClass, - JObjectPtr initialElement)>> newObjectArray; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function(JArrayPtr array, ffi.Int index, ffi.Int type)>> - getArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JBooleanMarker value)>> - setBooleanArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JByteMarker value)>> - setByteArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JShortMarker value)>> - setShortArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JCharMarker value)>> - setCharArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JIntMarker value)>> - setIntArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JLongMarker value)>> - setLongArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JFloatMarker value)>> - setFloatArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JThrowablePtr Function( - JArrayPtr array, ffi.Int index, JDoubleMarker value)>> - setDoubleArrayElement; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function(JObjectPtr obj, JMethodIDPtr methodID, - ffi.Int callType, ffi.Pointer args)>> callMethod; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function(JClassPtr cls, JMethodIDPtr methodID, - ffi.Int callType, ffi.Pointer args)>> callStaticMethod; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function( - JObjectPtr obj, JFieldIDPtr fieldID, ffi.Int callType)>> getField; - - external ffi.Pointer< - ffi.NativeFunction< - JniResult Function( - JClassPtr cls, JFieldIDPtr fieldID, ffi.Int callType)>> - getStaticField; - - external ffi.Pointer< - ffi.NativeFunction< - JniExceptionDetails Function(JThrowablePtr exception)>> - getExceptionDetails; -} - -typedef JMethodIDPtr = ffi.Pointer; - -final class jmethodID_ extends ffi.Opaque {} - -/// "cardinal indices and sizes" -typedef JSizeMarker = JIntMarker; -typedef JArrayPtr = JObjectPtr; -typedef JFieldIDPtr = ffi.Pointer; - -final class jfieldID_ extends ffi.Opaque {} - typedef JavaVM = ffi.Pointer; /// JNI invocation interface. @@ -2023,6 +1903,18 @@ final class JNINativeInterface extends ffi.Struct { } typedef JniEnv1 = ffi.Pointer; + +/// "cardinal indices and sizes" +typedef JSizeMarker = JIntMarker; +typedef JMethodIDPtr = ffi.Pointer; + +final class jmethodID_ extends ffi.Opaque {} + +typedef JFieldIDPtr = ffi.Pointer; + +final class jfieldID_ extends ffi.Opaque {} + +typedef JArrayPtr = JObjectPtr; typedef JObjectArrayPtr = JArrayPtr; typedef JBooleanArrayPtr = JArrayPtr; typedef JByteArrayPtr = JArrayPtr; @@ -2083,78 +1975,30 @@ final class CallbackResult extends ffi.Struct { external JObjectPtr object; } -typedef MutexLock = CRITICAL_SECTION; -typedef CRITICAL_SECTION = RTL_CRITICAL_SECTION; -typedef RTL_CRITICAL_SECTION = _RTL_CRITICAL_SECTION; - -final class _RTL_CRITICAL_SECTION extends ffi.Struct { - external PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - @LONG() - external int LockCount; - - @LONG() - external int RecursionCount; - - external HANDLE OwningThread; - - external HANDLE LockSemaphore; - - @ULONG_PTR() - external int SpinCount; -} - -typedef PRTL_CRITICAL_SECTION_DEBUG = ffi.Pointer<_RTL_CRITICAL_SECTION_DEBUG>; - -final class _RTL_CRITICAL_SECTION_DEBUG extends ffi.Struct { - @WORD() - external int Type; - - @WORD() - external int CreatorBackTraceIndex; +typedef MutexLock = pthread_mutex_t; +typedef pthread_mutex_t = __darwin_pthread_mutex_t; +typedef __darwin_pthread_mutex_t = _opaque_pthread_mutex_t; - external ffi.Pointer<_RTL_CRITICAL_SECTION> CriticalSection; +final class _opaque_pthread_mutex_t extends ffi.Struct { + @ffi.Long() + external int __sig; - external LIST_ENTRY ProcessLocksList; - - @DWORD() - external int EntryCount; - - @DWORD() - external int ContentionCount; - - @DWORD() - external int Flags; - - @WORD() - external int CreatorBackTraceIndexHigh; - - @WORD() - external int Identifier; + @ffi.Array.multi([56]) + external ffi.Array __opaque; } -typedef WORD = ffi.UnsignedShort; -typedef LIST_ENTRY = _LIST_ENTRY; - -final class _LIST_ENTRY extends ffi.Struct { - external ffi.Pointer<_LIST_ENTRY> Flink; +typedef ConditionVariable = pthread_cond_t; +typedef pthread_cond_t = __darwin_pthread_cond_t; +typedef __darwin_pthread_cond_t = _opaque_pthread_cond_t; - external ffi.Pointer<_LIST_ENTRY> Blink; -} - -typedef DWORD = ffi.UnsignedLong; -typedef LONG = ffi.Long; -typedef HANDLE = ffi.Pointer; -typedef ULONG_PTR = ffi.UnsignedLongLong; -typedef ConditionVariable = CONDITION_VARIABLE; -typedef CONDITION_VARIABLE = RTL_CONDITION_VARIABLE; -typedef RTL_CONDITION_VARIABLE = _RTL_CONDITION_VARIABLE; +final class _opaque_pthread_cond_t extends ffi.Struct { + @ffi.Long() + external int __sig; -final class _RTL_CONDITION_VARIABLE extends ffi.Struct { - external PVOID Ptr; + @ffi.Array.multi([40]) + external ffi.Array __opaque; } -typedef PVOID = ffi.Pointer; typedef Dart_FinalizableHandle = ffi.Pointer<_Dart_FinalizableHandle>; final class _Dart_FinalizableHandle extends ffi.Opaque {} @@ -3420,6 +3264,90 @@ final class GlobalJniEnvStruct extends ffi.Struct { external ffi.Pointer> GetObjectRefType; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JBooleanArrayPtr array, JSizeMarker index)>> + GetBooleanArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JBooleanArrayPtr array, JSizeMarker index, + JBooleanMarker element)>> SetBooleanArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JByteArrayPtr array, JSizeMarker index)>> + GetByteArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JByteArrayPtr array, JSizeMarker index, JByteMarker element)>> + SetByteArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JCharArrayPtr array, JSizeMarker index)>> + GetCharArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JCharArrayPtr array, JSizeMarker index, JCharMarker element)>> + SetCharArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JShortArrayPtr array, JSizeMarker index)>> + GetShortArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JShortArrayPtr array, JSizeMarker index, + JShortMarker element)>> SetShortArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JIntArrayPtr array, JSizeMarker index)>> + GetIntArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JIntArrayPtr array, JSizeMarker index, JIntMarker element)>> + SetIntArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JLongArrayPtr array, JSizeMarker index)>> + GetLongArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function( + JLongArrayPtr array, JSizeMarker index, JLongMarker element)>> + SetLongArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JFloatArrayPtr array, JSizeMarker index)>> + GetFloatArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JFloatArrayPtr array, JSizeMarker index, + JFloatMarker element)>> SetFloatArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JniResult Function(JDoubleArrayPtr array, JSizeMarker index)>> + GetDoubleArrayElement; + + external ffi.Pointer< + ffi.NativeFunction< + JThrowablePtr Function(JDoubleArrayPtr array, JSizeMarker index, + JDoubleMarker element)>> SetDoubleArrayElement; } /// This file re-exports some JNI constants as enum, because they are not diff --git a/pkgs/jni/lib/src/types.dart b/pkgs/jni/lib/src/types.dart index ce8c09efd..d684d0cbe 100644 --- a/pkgs/jni/lib/src/types.dart +++ b/pkgs/jni/lib/src/types.dart @@ -3,15 +3,18 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:ffi'; +import 'dart:typed_data'; +import 'package:collection/collection.dart'; import 'package:ffi/ffi.dart'; -import '../internal_helpers_for_jnigen.dart'; +import '../internal_helpers_for_jnigen.dart'; import 'jni.dart'; import 'jobject.dart'; import 'jvalues.dart'; import 'third_party/generated_bindings.dart'; +part 'jarray.dart'; part 'jclass.dart'; part 'jprimitives.dart'; @@ -35,7 +38,7 @@ mixin JConstructable on JType { JClassPtr clazz, JMethodIDPtr methodID, Pointer args); } -/// Able to be the type of a field that can be get and set.s +/// Able to be the type of a field that can be get and set. mixin JAccessible on JType { DartT _staticGet(JClassPtr clazz, JFieldIDPtr fieldID); DartT _instanceGet(JObjectPtr obj, JFieldIDPtr fieldID); @@ -43,6 +46,11 @@ mixin JAccessible on JType { void _instanceSet(JObjectPtr obj, JFieldIDPtr fieldID, DartT val); } +/// Able to be the type of array elements. +mixin JArrayElementType on JType { + JArray _newArray(int length); +} + /// Only used for jnigen. /// /// Makes constructing objects easier inside the generated bindings by allowing @@ -65,7 +73,11 @@ final class _ReferenceType extends JType } abstract class JObjType extends JType - with JCallable, JConstructable, JAccessible { + with + JCallable, + JConstructable, + JAccessible, + JArrayElementType { /// Number of super types. Distance to the root type. int get superCount; @@ -122,6 +134,21 @@ abstract class JObjType extends JType void _staticSet(JClassPtr clazz, JFieldIDPtr fieldID, T val) { Jni.env.SetStaticObjectField(clazz, fieldID, val.reference.pointer); } + + @override + JArray _newArray(int length, [T? fill]) { + final clazz = jClass; + final array = JArray.fromReference( + this, + JGlobalReference(Jni.env.NewObjectArray( + length, + clazz.reference.pointer, + fill == null ? nullptr : fill.reference.pointer, + )), + ); + clazz.release(); + return array; + } } /// Lowest common ancestor of two types in the inheritance tree. diff --git a/pkgs/jni/pubspec.yaml b/pkgs/jni/pubspec.yaml index 460fcccf2..b829b1a12 100644 --- a/pkgs/jni/pubspec.yaml +++ b/pkgs/jni/pubspec.yaml @@ -4,7 +4,7 @@ name: jni description: A library to access JNI from Dart and Flutter that acts as a support library for package:jnigen. -version: 0.10.1 +version: 0.11.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/jni topics: diff --git a/pkgs/jni/src/dartjni.c b/pkgs/jni/src/dartjni.c index a803c5889..18a981a31 100644 --- a/pkgs/jni/src/dartjni.c +++ b/pkgs/jni/src/dartjni.c @@ -12,11 +12,7 @@ pthread_key_t tlsKey; #endif -/// Load class through platform-specific mechanism. -/// -/// Currently uses application classloader on android, -/// and JNIEnv->FindClass on other platforms. -jclass FindClass(const char* name) { +jclass FindClassUnchecked(const char* name) { attach_thread(); jclass cls; load_class_platform(&cls, name); @@ -26,6 +22,18 @@ jclass FindClass(const char* name) { return cls; }; +/// Load class through platform-specific mechanism. +/// +/// Currently uses application classloader on android, +/// and JNIEnv->FindClass on other platforms. +FFI_PLUGIN_EXPORT +JniClassLookupResult FindClass(const char* name) { + JniClassLookupResult result = {NULL, NULL}; + result.value = FindClassUnchecked(name); + result.exception = check_exception(); + return result; +} + /// Stores class and method references for obtaining exception details typedef struct JniExceptionMethods { jclass objectClass, exceptionClass, printStreamClass; @@ -57,11 +65,11 @@ void init() { init_lock(&jni_context.locks.classLoadingLock); // Init exception handling classes and methods. - exceptionMethods.objectClass = FindClass("java/lang/Object"); - exceptionMethods.exceptionClass = FindClass("java/lang/Exception"); - exceptionMethods.printStreamClass = FindClass("java/io/PrintStream"); + exceptionMethods.objectClass = FindClassUnchecked("java/lang/Object"); + exceptionMethods.exceptionClass = FindClassUnchecked("java/lang/Exception"); + exceptionMethods.printStreamClass = FindClassUnchecked("java/io/PrintStream"); exceptionMethods.byteArrayOutputStreamClass = - FindClass("java/io/ByteArrayOutputStream"); + FindClassUnchecked("java/io/ByteArrayOutputStream"); load_method(exceptionMethods.objectClass, &exceptionMethods.toStringMethod, "toString", "()Ljava/lang/String;"); load_method(exceptionMethods.exceptionClass, @@ -227,388 +235,8 @@ int SpawnJvm(JavaVMInitArgs* initArgs) { } #endif -// accessors - a bunch of functions which are directly called by jnigen generated bindings -// and also package:jni reflective method access. - -JniClassLookupResult getClass(char* internalName) { - JniClassLookupResult result = {NULL, NULL}; - result.value = FindClass(internalName); - result.exception = check_exception(); - return result; -} - -typedef void* (*MemberGetter)(JNIEnv* env, jclass clazz, char* name, char* sig); - -static inline JniPointerResult _getId(MemberGetter getter, - jclass cls, - char* name, - char* sig) { - JniPointerResult result = {NULL, NULL}; - result.value = getter(jniEnv, cls, name, sig); - result.exception = check_exception(); - return result; -} - -JniPointerResult getMethodID(jclass cls, char* name, char* sig) { - attach_thread(); - return _getId((MemberGetter)(*jniEnv)->GetMethodID, cls, name, sig); -} - -JniPointerResult getStaticMethodID(jclass cls, char* name, char* sig) { - attach_thread(); - return _getId((MemberGetter)(*jniEnv)->GetStaticMethodID, cls, name, sig); -} - -JniPointerResult getFieldID(jclass cls, char* name, char* sig) { - attach_thread(); - return _getId((MemberGetter)(*jniEnv)->GetFieldID, cls, name, sig); -} - -JniPointerResult getStaticFieldID(jclass cls, char* name, char* sig) { - attach_thread(); - return _getId((MemberGetter)(*jniEnv)->GetStaticFieldID, cls, name, sig); -} - -JniResult callMethod(jobject obj, - jmethodID fieldID, - int callType, - jvalue* args) { - attach_thread(); - jvalue result = {.j = 0}; - switch (callType) { - case booleanType: - result.z = (*jniEnv)->CallBooleanMethodA(jniEnv, obj, fieldID, args); - break; - case byteType: - result.b = (*jniEnv)->CallByteMethodA(jniEnv, obj, fieldID, args); - break; - case shortType: - result.s = (*jniEnv)->CallShortMethodA(jniEnv, obj, fieldID, args); - break; - case charType: - result.c = (*jniEnv)->CallCharMethodA(jniEnv, obj, fieldID, args); - break; - case intType: - result.i = (*jniEnv)->CallIntMethodA(jniEnv, obj, fieldID, args); - break; - case longType: - result.j = (*jniEnv)->CallLongMethodA(jniEnv, obj, fieldID, args); - break; - case floatType: - result.f = (*jniEnv)->CallFloatMethodA(jniEnv, obj, fieldID, args); - break; - case doubleType: - result.d = (*jniEnv)->CallDoubleMethodA(jniEnv, obj, fieldID, args); - break; - case objectType: - result.l = (*jniEnv)->CallObjectMethodA(jniEnv, obj, fieldID, args); - break; - case voidType: - (*jniEnv)->CallVoidMethodA(jniEnv, obj, fieldID, args); - break; - } - jthrowable exception = check_exception(); - if (callType == objectType && exception == NULL) { - result.l = to_global_ref(result.l); - } - JniResult jniResult = {.value = result, .exception = exception}; - return jniResult; -} - -// TODO(#60): Any way to reduce this boilerplate? -JniResult callStaticMethod(jclass cls, - jmethodID methodID, - int callType, - jvalue* args) { - attach_thread(); - jvalue result = {.j = 0}; - switch (callType) { - case booleanType: - result.z = - (*jniEnv)->CallStaticBooleanMethodA(jniEnv, cls, methodID, args); - break; - case byteType: - result.b = (*jniEnv)->CallStaticByteMethodA(jniEnv, cls, methodID, args); - break; - case shortType: - result.s = (*jniEnv)->CallStaticShortMethodA(jniEnv, cls, methodID, args); - break; - case charType: - result.c = (*jniEnv)->CallStaticCharMethodA(jniEnv, cls, methodID, args); - break; - case intType: - result.i = (*jniEnv)->CallStaticIntMethodA(jniEnv, cls, methodID, args); - break; - case longType: - result.j = (*jniEnv)->CallStaticLongMethodA(jniEnv, cls, methodID, args); - break; - case floatType: - result.f = (*jniEnv)->CallStaticFloatMethodA(jniEnv, cls, methodID, args); - break; - case doubleType: - result.d = - (*jniEnv)->CallStaticDoubleMethodA(jniEnv, cls, methodID, args); - break; - case objectType: - result.l = - (*jniEnv)->CallStaticObjectMethodA(jniEnv, cls, methodID, args); - break; - case voidType: - (*jniEnv)->CallStaticVoidMethodA(jniEnv, cls, methodID, args); - break; - } - jthrowable exception = check_exception(); - if (callType == objectType && exception == NULL) { - result.l = to_global_ref(result.l); - } - JniResult jniResult = {.value = result, .exception = exception}; - return jniResult; -} - -JniResult getField(jobject obj, jfieldID fieldID, int callType) { - attach_thread(); - jvalue result = {.j = 0}; - switch (callType) { - case booleanType: - result.z = (*jniEnv)->GetBooleanField(jniEnv, obj, fieldID); - break; - case byteType: - result.b = (*jniEnv)->GetByteField(jniEnv, obj, fieldID); - break; - case shortType: - result.s = (*jniEnv)->GetShortField(jniEnv, obj, fieldID); - break; - case charType: - result.c = (*jniEnv)->GetCharField(jniEnv, obj, fieldID); - break; - case intType: - result.i = (*jniEnv)->GetIntField(jniEnv, obj, fieldID); - break; - case longType: - result.j = (*jniEnv)->GetLongField(jniEnv, obj, fieldID); - break; - case floatType: - result.f = (*jniEnv)->GetFloatField(jniEnv, obj, fieldID); - break; - case doubleType: - result.d = (*jniEnv)->GetDoubleField(jniEnv, obj, fieldID); - break; - case objectType: - result.l = (*jniEnv)->GetObjectField(jniEnv, obj, fieldID); - break; - case voidType: - // This error should have been handled in Dart. - break; - } - jthrowable exception = check_exception(); - if (callType == objectType && exception == NULL) { - result.l = to_global_ref(result.l); - } - JniResult jniResult = {.value = result, .exception = exception}; - return jniResult; -} - FFI_PLUGIN_EXPORT -JniResult getStaticField(jclass cls, jfieldID fieldID, int callType) { - attach_thread(); - jvalue result = {.j = 0}; - switch (callType) { - case booleanType: - result.z = (*jniEnv)->GetStaticBooleanField(jniEnv, cls, fieldID); - break; - case byteType: - result.b = (*jniEnv)->GetStaticByteField(jniEnv, cls, fieldID); - break; - case shortType: - result.s = (*jniEnv)->GetStaticShortField(jniEnv, cls, fieldID); - break; - case charType: - result.c = (*jniEnv)->GetStaticCharField(jniEnv, cls, fieldID); - break; - case intType: - result.i = (*jniEnv)->GetStaticIntField(jniEnv, cls, fieldID); - break; - case longType: - result.j = (*jniEnv)->GetStaticLongField(jniEnv, cls, fieldID); - break; - case floatType: - result.f = (*jniEnv)->GetStaticFloatField(jniEnv, cls, fieldID); - break; - case doubleType: - result.d = (*jniEnv)->GetStaticDoubleField(jniEnv, cls, fieldID); - break; - case objectType: - result.l = (*jniEnv)->GetStaticObjectField(jniEnv, cls, fieldID); - break; - case voidType: - // This error should have been handled in dart. - // is there a way to mark this as unreachable? - // or throw exception in Dart using Dart's C API. - break; - } - jthrowable exception = check_exception(); - if (callType == objectType && exception == NULL) { - result.l = to_global_ref(result.l); - } - JniResult jniResult = {.value = result, .exception = exception}; - return jniResult; -} - -JniResult newObject(jclass cls, jmethodID ctor, jvalue* args) { - attach_thread(); - jobject result = (*jniEnv)->NewObjectA(jniEnv, cls, ctor, args); - return to_global_ref_result(result); -} - -JniResult newPrimitiveArray(jsize length, int type) { - attach_thread(); - jarray array; - switch (type) { - case booleanType: - array = (*jniEnv)->NewBooleanArray(jniEnv, length); - break; - case byteType: - array = (*jniEnv)->NewByteArray(jniEnv, length); - break; - case shortType: - array = (*jniEnv)->NewShortArray(jniEnv, length); - break; - case charType: - array = (*jniEnv)->NewCharArray(jniEnv, length); - break; - case intType: - array = (*jniEnv)->NewIntArray(jniEnv, length); - break; - case longType: - array = (*jniEnv)->NewLongArray(jniEnv, length); - break; - case floatType: - array = (*jniEnv)->NewFloatArray(jniEnv, length); - break; - case doubleType: - array = (*jniEnv)->NewDoubleArray(jniEnv, length); - break; - case objectType: - case voidType: - // This error should have been handled in dart. - // is there a way to mark this as unreachable? - // or throw exception in Dart using Dart's C API. - array = NULL; - break; - } - return to_global_ref_result(array); -} - -JniResult newObjectArray(jsize length, - jclass elementClass, - jobject initialElement) { - attach_thread(); - jarray array = - (*jniEnv)->NewObjectArray(jniEnv, length, elementClass, initialElement); - return to_global_ref_result(array); -} - -JniResult getArrayElement(jarray array, int index, int type) { - attach_thread(); - jvalue value; - switch (type) { - case booleanType: - (*jniEnv)->GetBooleanArrayRegion(jniEnv, array, index, 1, &value.z); - break; - case byteType: - (*jniEnv)->GetByteArrayRegion(jniEnv, array, index, 1, &value.b); - break; - case shortType: - (*jniEnv)->GetShortArrayRegion(jniEnv, array, index, 1, &value.s); - break; - case charType: - (*jniEnv)->GetCharArrayRegion(jniEnv, array, index, 1, &value.c); - break; - case intType: - (*jniEnv)->GetIntArrayRegion(jniEnv, array, index, 1, &value.i); - break; - case longType: - (*jniEnv)->GetLongArrayRegion(jniEnv, array, index, 1, &value.j); - break; - case floatType: - (*jniEnv)->GetFloatArrayRegion(jniEnv, array, index, 1, &value.f); - break; - case doubleType: - (*jniEnv)->GetDoubleArrayRegion(jniEnv, array, index, 1, &value.d); - break; - case objectType: - value.l = (*jniEnv)->GetObjectArrayElement(jniEnv, array, index); - case voidType: - // This error should have been handled in dart. - // is there a way to mark this as unreachable? - // or throw exception in Dart using Dart's C API. - break; - } - jthrowable exception = check_exception(); - if (type == objectType && exception == NULL) { - value.l = to_global_ref(value.l); - } - JniResult jniResult = {.value = value, .exception = exception}; - return jniResult; -} - -jthrowable setBooleanArrayElement(jarray array, int index, jboolean value) { - attach_thread(); - (*jniEnv)->SetBooleanArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setByteArrayElement(jarray array, int index, jbyte value) { - attach_thread(); - (*jniEnv)->SetByteArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setShortArrayElement(jarray array, int index, jshort value) { - attach_thread(); - (*jniEnv)->SetShortArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setCharArrayElement(jarray array, int index, jchar value) { - attach_thread(); - (*jniEnv)->SetCharArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setIntArrayElement(jarray array, int index, jint value) { - attach_thread(); - (*jniEnv)->SetIntArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setLongArrayElement(jarray array, int index, jlong value) { - attach_thread(); - (*jniEnv)->SetLongArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setFloatArrayElement(jarray array, int index, jfloat value) { - attach_thread(); - (*jniEnv)->SetFloatArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -jthrowable setDoubleArrayElement(jarray array, int index, jdouble value) { - attach_thread(); - (*jniEnv)->SetDoubleArrayRegion(jniEnv, array, index, 1, &value); - jthrowable exception = check_exception(); - return exception; -} - -JniExceptionDetails getExceptionDetails(jthrowable exception) { +JniExceptionDetails GetExceptionDetails(jthrowable exception) { JniExceptionDetails details; details.message = (*jniEnv)->CallObjectMethod( jniEnv, exception, exceptionMethods.toStringMethod); @@ -633,35 +261,6 @@ JniExceptionDetails getExceptionDetails(jthrowable exception) { return details; } -JniAccessorsStruct accessors = { - .getClass = getClass, - .getFieldID = getFieldID, - .getStaticFieldID = getStaticFieldID, - .getMethodID = getMethodID, - .getStaticMethodID = getStaticMethodID, - .newObject = newObject, - .newPrimitiveArray = newPrimitiveArray, - .newObjectArray = newObjectArray, - .getArrayElement = getArrayElement, - .setBooleanArrayElement = setBooleanArrayElement, - .setByteArrayElement = setByteArrayElement, - .setShortArrayElement = setShortArrayElement, - .setCharArrayElement = setCharArrayElement, - .setIntArrayElement = setIntArrayElement, - .setLongArrayElement = setLongArrayElement, - .setFloatArrayElement = setFloatArrayElement, - .setDoubleArrayElement = setDoubleArrayElement, - .callMethod = callMethod, - .callStaticMethod = callStaticMethod, - .getField = getField, - .getStaticField = getStaticField, - .getExceptionDetails = getExceptionDetails, -}; - -FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors() { - return &accessors; -} - // These will not be required after migrating to Dart-only bindings. FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr() { return jni; diff --git a/pkgs/jni/src/dartjni.h b/pkgs/jni/src/dartjni.h index 2ecb6570b..53a4ad15d 100644 --- a/pkgs/jni/src/dartjni.h +++ b/pkgs/jni/src/dartjni.h @@ -222,52 +222,11 @@ typedef struct JniExceptionDetails { jstring stacktrace; } JniExceptionDetails; -/// This struct contains functions which wrap method call / field access conveniently along with -/// exception checking. -/// -/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us -/// to check for and clear the exception before returning to dart code, which requires these functions -/// to return result types. -typedef struct JniAccessorsStruct { - JniClassLookupResult (*getClass)(char* internalName); - JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); - JniPointerResult (*getStaticFieldID)(jclass cls, - char* fieldName, - char* signature); - JniPointerResult (*getMethodID)(jclass cls, - char* methodName, - char* signature); - JniPointerResult (*getStaticMethodID)(jclass cls, - char* methodName, - char* signature); - JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); - JniResult (*newPrimitiveArray)(jsize length, int type); - JniResult (*newObjectArray)(jsize length, - jclass elementClass, - jobject initialElement); - JniResult (*getArrayElement)(jarray array, int index, int type); - jthrowable (*setBooleanArrayElement)(jarray array, int index, jboolean value); - jthrowable (*setByteArrayElement)(jarray array, int index, jbyte value); - jthrowable (*setShortArrayElement)(jarray array, int index, jshort value); - jthrowable (*setCharArrayElement)(jarray array, int index, jchar value); - jthrowable (*setIntArrayElement)(jarray array, int index, jint value); - jthrowable (*setLongArrayElement)(jarray array, int index, jlong value); - jthrowable (*setFloatArrayElement)(jarray array, int index, jfloat value); - jthrowable (*setDoubleArrayElement)(jarray array, int index, jdouble value); - JniResult (*callMethod)(jobject obj, - jmethodID methodID, - int callType, - jvalue* args); - JniResult (*callStaticMethod)(jclass cls, - jmethodID methodID, - int callType, - jvalue* args); - JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); - JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); - JniExceptionDetails (*getExceptionDetails)(jthrowable exception); -} JniAccessorsStruct; - -FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors(); +FFI_PLUGIN_EXPORT +JniClassLookupResult FindClass(const char* name); + +FFI_PLUGIN_EXPORT +JniExceptionDetails GetExceptionDetails(jthrowable exception); FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); diff --git a/pkgs/jni/src/third_party/global_jni_env.c b/pkgs/jni/src/third_party/global_jni_env.c index 70fc7697b..2e7e44829 100644 --- a/pkgs/jni/src/third_party/global_jni_env.c +++ b/pkgs/jni/src/third_party/global_jni_env.c @@ -2429,6 +2429,109 @@ JniResult globalEnv_GetObjectRefType(jobject obj) { return (JniResult){.value = {.i = _result}, .exception = NULL}; } +JniResult globalEnv_GetBooleanArrayElement(jbooleanArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetBooleanArrayRegion(array, index, 1, &value.z); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetBooleanArrayElement(jbooleanArray array, + jsize index, + jboolean val) { + return globalEnv_SetBooleanArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetByteArrayElement(jbyteArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetByteArrayRegion(array, index, 1, &value.b); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetByteArrayElement(jbyteArray array, + jsize index, + jbyte val) { + return globalEnv_SetByteArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetCharArrayElement(jcharArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetCharArrayRegion(array, index, 1, &value.c); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetCharArrayElement(jcharArray array, + jsize index, + jchar val) { + return globalEnv_SetCharArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetShortArrayElement(jshortArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetShortArrayRegion(array, index, 1, &value.s); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetShortArrayElement(jshortArray array, + jsize index, + jshort val) { + return globalEnv_SetShortArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetIntArrayElement(jintArray array, jsize index) { + jvalue value; + jthrowable exception = globalEnv_GetIntArrayRegion(array, index, 1, &value.i); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetIntArrayElement(jintArray array, + jsize index, + jint val) { + return globalEnv_SetIntArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetLongArrayElement(jlongArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetLongArrayRegion(array, index, 1, &value.j); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetLongArrayElement(jlongArray array, + jsize index, + jlong val) { + return globalEnv_SetLongArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetFloatArrayElement(jfloatArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetFloatArrayRegion(array, index, 1, &value.f); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetFloatArrayElement(jfloatArray array, + jsize index, + jfloat val) { + return globalEnv_SetFloatArrayRegion(array, index, 1, &val); +} + +JniResult globalEnv_GetDoubleArrayElement(jdoubleArray array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_GetDoubleArrayRegion(array, index, 1, &value.d); + return (JniResult){.value = value, .exception = exception}; +} + +jthrowable globalEnv_SetDoubleArrayElement(jdoubleArray array, + jsize index, + jdouble val) { + return globalEnv_SetDoubleArrayRegion(array, index, 1, &val); +} + GlobalJniEnvStruct globalJniEnv = { .reserved0 = NULL, .reserved1 = NULL, @@ -2663,6 +2766,22 @@ GlobalJniEnvStruct globalJniEnv = { .GetDirectBufferAddress = globalEnv_GetDirectBufferAddress, .GetDirectBufferCapacity = globalEnv_GetDirectBufferCapacity, .GetObjectRefType = globalEnv_GetObjectRefType, + .GetBooleanArrayElement = globalEnv_GetBooleanArrayElement, + .SetBooleanArrayElement = globalEnv_SetBooleanArrayElement, + .GetByteArrayElement = globalEnv_GetByteArrayElement, + .SetByteArrayElement = globalEnv_SetByteArrayElement, + .GetCharArrayElement = globalEnv_GetCharArrayElement, + .SetCharArrayElement = globalEnv_SetCharArrayElement, + .GetShortArrayElement = globalEnv_GetShortArrayElement, + .SetShortArrayElement = globalEnv_SetShortArrayElement, + .GetIntArrayElement = globalEnv_GetIntArrayElement, + .SetIntArrayElement = globalEnv_SetIntArrayElement, + .GetLongArrayElement = globalEnv_GetLongArrayElement, + .SetLongArrayElement = globalEnv_SetLongArrayElement, + .GetFloatArrayElement = globalEnv_GetFloatArrayElement, + .SetFloatArrayElement = globalEnv_SetFloatArrayElement, + .GetDoubleArrayElement = globalEnv_GetDoubleArrayElement, + .SetDoubleArrayElement = globalEnv_SetDoubleArrayElement, }; FFI_PLUGIN_EXPORT GlobalJniEnvStruct* GetGlobalEnv() { diff --git a/pkgs/jni/src/third_party/global_jni_env.h b/pkgs/jni/src/third_party/global_jni_env.h index 041718c69..c27bc0687 100644 --- a/pkgs/jni/src/third_party/global_jni_env.h +++ b/pkgs/jni/src/third_party/global_jni_env.h @@ -443,6 +443,36 @@ typedef struct GlobalJniEnvStruct { JniPointerResult (*GetDirectBufferAddress)(jobject buf); JniResult (*GetDirectBufferCapacity)(jobject buf); JniResult (*GetObjectRefType)(jobject obj); + JniResult (*GetBooleanArrayElement)(jbooleanArray array, jsize index); + jthrowable (*SetBooleanArrayElement)(jbooleanArray array, + jsize index, + jboolean element); + JniResult (*GetByteArrayElement)(jbyteArray array, jsize index); + jthrowable (*SetByteArrayElement)(jbyteArray array, + jsize index, + jbyte element); + JniResult (*GetCharArrayElement)(jcharArray array, jsize index); + jthrowable (*SetCharArrayElement)(jcharArray array, + jsize index, + jchar element); + JniResult (*GetShortArrayElement)(jshortArray array, jsize index); + jthrowable (*SetShortArrayElement)(jshortArray array, + jsize index, + jshort element); + JniResult (*GetIntArrayElement)(jintArray array, jsize index); + jthrowable (*SetIntArrayElement)(jintArray array, jsize index, jint element); + JniResult (*GetLongArrayElement)(jlongArray array, jsize index); + jthrowable (*SetLongArrayElement)(jlongArray array, + jsize index, + jlong element); + JniResult (*GetFloatArrayElement)(jfloatArray array, jsize index); + jthrowable (*SetFloatArrayElement)(jfloatArray array, + jsize index, + jfloat element); + JniResult (*GetDoubleArrayElement)(jdoubleArray array, jsize index); + jthrowable (*SetDoubleArrayElement)(jdoubleArray array, + jsize index, + jdouble element); } GlobalJniEnvStruct; FFI_PLUGIN_EXPORT GlobalJniEnvStruct* GetGlobalEnv(); FFI_PLUGIN_EXPORT JniResult globalEnv_NewObject(jclass clazz, diff --git a/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart b/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart index a76b7bbf0..51be17f42 100644 --- a/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart +++ b/pkgs/jni/tool/wrapper_generators/generate_c_extensions.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:ffigen/src/code_generator.dart'; import 'ffigen_util.dart'; +import 'generate_helper_functions.dart'; import 'logging.dart'; class Paths { @@ -85,6 +86,10 @@ FunctionType getGlobalJniEnvFunctionType(FunctionType ft) { ); } +String getWrapperFuncName(String name) { + return 'globalEnv_$name'; +} + // Returns declaration of function field in GlobalJniEnv struct String getFunctionFieldDecl(Member field, {required bool isField}) { final fieldType = field.type; @@ -103,16 +108,12 @@ String getFunctionFieldDecl(Member field, {required bool isField}) { return '${resultWrapper.returnType} (*$name)($params);'; } return '$willExport${resultWrapper.returnType} ' - '${getWrapperFuncName(field)}($params);'; + '${getWrapperFuncName(field.name)}($params);'; } else { return 'void* ${field.name};'; } } -String getWrapperFuncName(Member field) { - return 'globalEnv_${field.name}'; -} - class ResultWrapper { String returnType, onResult, onError; ResultWrapper.withResultAndError( @@ -133,17 +134,8 @@ class ResultWrapper { ); } -ResultWrapper getResultWrapper(String returnType) { - if (returnType.endsWith('*')) { - return ResultWrapper.unionType('JniPointerResult', 'NULL'); - } - - final jobjectWrapper = ResultWrapper.forJValueField('l'); - if (returnType.endsWith('Array')) { - return jobjectWrapper; - } - - const jfields = { +String jValueGetterOf(String returnType) { + const getters = { 'jboolean': 'z', 'jbyte': 'b', 'jshort': 's', @@ -159,6 +151,22 @@ ResultWrapper getResultWrapper(String returnType) { 'jstring': 'l', 'jthrowable': 'l', }; + if (!getters.containsKey(returnType)) { + stderr.writeln('Unknown type $returnType for return type'); + exit(1); + } + return getters[returnType]!; +} + +ResultWrapper getResultWrapper(String returnType) { + if (returnType.endsWith('*')) { + return ResultWrapper.unionType('JniPointerResult', 'NULL'); + } + + final jobjectWrapper = ResultWrapper.forJValueField('l'); + if (returnType.endsWith('Array')) { + return jobjectWrapper; + } switch (returnType) { case 'void': @@ -175,11 +183,7 @@ ResultWrapper getResultWrapper(String returnType) { case 'int32_t': return ResultWrapper.forJValueField('i'); default: - if (jfields.containsKey(returnType)) { - return ResultWrapper.forJValueField(jfields[returnType]!); - } - stderr.writeln('Unknown type $returnType for return type'); - exit(1); + return ResultWrapper.forJValueField(jValueGetterOf(returnType)); } } @@ -231,7 +235,7 @@ String? getWrapperFunc(Member field) { } final outerFunctionType = getGlobalJniEnvFunctionType(functionType); - final wrapperName = getWrapperFuncName(field); + final wrapperName = getWrapperFuncName(field.name); final returnType = getCType(outerFunctionType.returnType); final withVarArgs = hasVarArgs(field.name); final params = [ @@ -287,7 +291,6 @@ String? getWrapperFunc(Member field) { void writeGlobalJniEnvWrapper(Library library) { final jniEnvType = findCompound(library, envType); - final fieldDecls = jniEnvType.members .map((member) => getFunctionFieldDecl(member, isField: true)) .join('\n'); @@ -295,8 +298,13 @@ void writeGlobalJniEnvWrapper(Library library) { .where((member) => hasVarArgs(member.name)) .map((member) => getFunctionFieldDecl(member, isField: false)) .join('\n'); - final structDecl = - 'typedef struct $wrapperName {\n$fieldDecls\n} $wrapperName;\n'; + final generatedFields = primitiveArrayHelperFields.join(); + final structDecl = ''' +typedef struct $wrapperName { + $fieldDecls + $generatedFields +} $wrapperName; +'''; File.fromUri(Paths.globalJniEnvH).writeAsStringSync('$preamble' '$wrapperDeclIncludes' '$structDecl' @@ -308,12 +316,20 @@ void writeGlobalJniEnvWrapper(Library library) { for (final member in jniEnvType.members) { final wrapper = getWrapperFunc(member); if (wrapper == null) { - structInst.write('.${member.name} = NULL,\n'); + structInst.writeln('.${member.name} = NULL,'); } else { - structInst.write('.${member.name} = ${getWrapperFuncName(member)},\n'); - functionWrappers.write('$wrapper\n'); + structInst + .writeln('.${member.name} = ${getWrapperFuncName(member.name)},'); + functionWrappers.writeln(wrapper); } } + final generatedFunctions = primitiveArrayHelperFunctions; + for (final function in generatedFunctions) { + structInst + .writeln('.${function.name} = ${getWrapperFuncName(function.name)},'); + functionWrappers.writeln(function); + } + structInst.write('};'); File.fromUri(Paths.globalJniEnvC).writeAsStringSync( '$preamble$wrapperIncludes$functionWrappers$structInst$wrapperGetter'); diff --git a/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart b/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart index ad6e720a6..f8cf124f6 100644 --- a/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart +++ b/pkgs/jni/tool/wrapper_generators/generate_dart_extensions.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:ffigen/src/code_generator.dart'; import 'ffigen_util.dart'; +import 'generate_helper_functions.dart'; import 'logging.dart'; class Paths { @@ -74,7 +75,11 @@ String getCheckedGetter(Type returnType) { exit(1); } -String? getGlobalEnvExtensionFunction(Member field, Type? checkedReturnType) { +String? getGlobalEnvExtensionFunction( + Member field, + Type? checkedReturnType, { + required bool isLeaf, +}) { final fieldType = field.type; if (fieldType is PointerType && fieldType.child is NativeFunc) { final nativeFunc = fieldType.child as NativeFunc; @@ -101,9 +106,10 @@ String? getGlobalEnvExtensionFunction(Member field, Type? checkedReturnType) { if (checkedGetter == 'boolean') { returns = 'bool'; } + final leafCall = isLeaf ? 'isLeaf: true' : ''; return ''' late final _${field.name} = - ptr.ref.${field.name}.asFunction<$dartType>();\n + ptr.ref.${field.name}.asFunction<$dartType>($leafCall);\n $returns ${field.name}($signature) => _${field.name}($callArgs).$checkedGetter; @@ -117,26 +123,16 @@ void writeDartExtensions(Library library) { // ignore_for_file: non_constant_identifier_names // coverage:ignore-file -import "dart:ffi" as ffi;\n -import "jni_bindings_generated.dart"; +import 'dart:ffi' as ffi; -'''; - const importAccessors = ''' -import "../accessors.dart"; +import '../accessors.dart'; +import 'jni_bindings_generated.dart'; '''; final globalEnvExtension = getGlobalEnvExtension(library); - final accessorExtension = getFunctionPointerExtension( - library, - 'JniAccessorsStruct', - 'JniAccessors', - ); - File.fromUri(Paths.globalEnvExts).writeAsStringSync(preamble + - header + - importAccessors + - globalEnvExtension + - accessorExtension); + File.fromUri(Paths.globalEnvExts) + .writeAsStringSync('$preamble$header$globalEnvExtension'); final localEnvExtsFile = File.fromUri(Paths.localEnvExts); if (localEnvExtsFile.existsSync()) { localEnvExtsFile.deleteSync(); @@ -159,9 +155,91 @@ import "../accessors.dart"; implicitThis: true, ); localEnvExtsFile - .writeAsStringSync(preamble + header + envExtension + jvmExtension); + .writeAsStringSync('$preamble$header$envExtension$jvmExtension'); } +const leafFunctions = { + 'GetVersion', + 'FindClass', + 'GetSuperclass', + 'IsAssignableFrom', + 'NewGlobalRef', + 'DeleteGlobalRef', + 'DeleteLocalRef', + 'IsSameObject', + 'NewLocalRef', + 'GetObjectClass', + 'GetMethodID', + 'GetFieldID', + 'GetObjectField', + 'GetBooleanField', + 'GetByteField', + 'GetCharField', + 'GetShortField', + 'GetIntField', + 'GetLongField', + 'GetFloatField', + 'GetDoubleField', + 'SetObjectField', + 'SetBooleanField', + 'SetByteField', + 'SetCharField', + 'SetShortField', + 'SetIntField', + 'SetLongField', + 'SetFloatField', + 'SetDoubleField', + 'GetStaticMethodID', + 'GetStaticFieldID', + 'GetStaticObjectField', + 'GetStaticBooleanField', + 'GetStaticByteField', + 'GetStaticCharField', + 'GetStaticShortField', + 'GetStaticIntField', + 'GetStaticLongField', + 'GetStaticFloatField', + 'GetStaticDoubleField', + 'SetStaticObjectField', + 'SetStaticBooleanField', + 'SetStaticByteField', + 'SetStaticCharField', + 'SetStaticShortField', + 'SetStaticIntField', + 'SetStaticLongField', + 'SetStaticFloatField', + 'SetStaticDoubleField', + 'GetStringLength', + 'GetStringUTFLength', + 'GetArrayLength', + 'GetObjectArrayElement', + 'SetObjectArrayElement', + 'GetJavaVM', + 'NewWeakGlobalRef', + 'DeleteWeakGlobalRef', + 'ExceptionCheck', + 'GetObjectRefType', + 'GetDirectBufferAddress', + 'GetDirectBufferCapacity', + // Accessors + 'getClass', + 'getFieldID', + 'getStaticFieldID', + 'getMethodID', + 'getStaticMethodID', + 'getArrayElement', + 'setBooleanArrayElement', + 'setByteArrayElement', + 'setShortArrayElement', + 'setCharArrayElement', + 'setIntArrayElement', + 'setLongArrayElement', + 'setFloatArrayElement', + 'setDoubleArrayElement', + 'getField', + 'getStaticField', +}; + String getGlobalEnvExtension( Library library, ) { @@ -176,9 +254,15 @@ String getGlobalEnvExtension( } } final extensionFunctions = env.members - .map((m) => getGlobalEnvExtensionFunction(m, checkedReturnTypes[m.name])) + .map((member) => getGlobalEnvExtensionFunction( + member, + checkedReturnTypes[member.name], + isLeaf: leafFunctions.contains(member.name), + )) .nonNulls .join('\n'); + final generatedFunctions = + primitiveArrayHelperFunctions.map((f) => f.dartCode).join('\n'); return ''' /// Wraps over Pointer and exposes function pointer fields /// as methods. @@ -186,12 +270,17 @@ class GlobalJniEnv { final ffi.Pointer ptr; GlobalJniEnv(this.ptr); $extensionFunctions + $generatedFunctions } '''; } -String? getFunctionPointerExtensionFunction(Member field, - {bool indirect = false, bool implicitThis = false}) { +String? getFunctionPointerExtensionFunction( + Member field, { + bool indirect = false, + bool implicitThis = false, + required bool isLeaf, +}) { final fieldType = field.type; if (fieldType is PointerType && fieldType.child is NativeFunc) { final nativeFunc = fieldType.child as NativeFunc; @@ -216,9 +305,10 @@ String? getFunctionPointerExtensionFunction(Member field, ].join(', '); final returns = returnType.getDartType(dummyWriter); final dereference = indirect ? 'value.ref' : 'ref'; + final leafCall = isLeaf ? 'isLeaf: true' : ''; return ''' late final _${field.name} = - ptr.$dereference.${field.name}.asFunction<$dartType>(); + ptr.$dereference.${field.name}.asFunction<$dartType>($leafCall); $returns ${field.name}($signature) => _${field.name}($callArgs); '''; @@ -234,11 +324,14 @@ String getFunctionPointerExtension( final compound = typeBinding.typealiasType.baseType as Compound; final extensionFunctions = compound.members .map((f) => getFunctionPointerExtensionFunction(f, - indirect: indirect, implicitThis: implicitThis)) + indirect: indirect, + implicitThis: implicitThis, + isLeaf: leafFunctions.contains(f.name))) .nonNulls .join('\n'); return ''' -/// Wraps over the function pointers in $type and exposes them as methods. +/// Wraps over the function pointers in $type and exposes them +/// as methods. class $wrapperClassName { final ffi.Pointer<$type> ptr; $wrapperClassName(this.ptr); diff --git a/pkgs/jni/tool/wrapper_generators/generate_helper_functions.dart b/pkgs/jni/tool/wrapper_generators/generate_helper_functions.dart new file mode 100644 index 000000000..c5b5409b7 --- /dev/null +++ b/pkgs/jni/tool/wrapper_generators/generate_helper_functions.dart @@ -0,0 +1,121 @@ +// Copyright (c) 2024, 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. + +class GeneratedFunction { + final String name; + final String cCode; + final String? dartCode; + + GeneratedFunction(this.name, this.cCode, this.dartCode); + + @override + String toString() => cCode; +} + +class PrimitiveType { + final String name; + final String jValueGetter; + final String dartReturnType; + final String dartArgumentType; + final String conversionSuffix; + final String resultGetter; + + const PrimitiveType( + this.name, + this.jValueGetter, + this.dartReturnType, + this.dartArgumentType, + this.conversionSuffix, + this.resultGetter, + ); +} + +const primitiveTypes = [ + PrimitiveType('Boolean', 'z', 'bool', 'int', ' ? 1 : 0', 'boolean'), + PrimitiveType('Byte', 'b', 'int', 'int', '', 'byte'), + PrimitiveType('Char', 'c', 'int', 'int', '', 'char'), + PrimitiveType('Short', 's', 'int', 'int', '', 'short'), + PrimitiveType('Int', 'i', 'int', 'int', '', 'integer'), + PrimitiveType('Long', 'j', 'int', 'int', '', 'long'), + PrimitiveType('Float', 'f', 'double', 'double', '', 'float'), + PrimitiveType('Double', 'd', 'double', 'double', '', 'doubleFloat'), +]; + +final primitiveArrayHelperFields = _primitiveArrayHelpers(isField: true); +final primitiveArrayHelperFunctions = _primitiveArrayHelpers(isField: false); + +/// Generates helpers for setting and getting a single element in primitive +/// Java arrays faster. +/// +/// By default, the JNI primitive array functions operate on ranges. +/// This means that Dart has to allocate pointers on heap to pass to them, which +/// is slower. +List _primitiveArrayHelpers({required bool isField}) { + final functions = []; + for (final PrimitiveType( + name: typeName, + :jValueGetter, + :dartReturnType, + :dartArgumentType, + :conversionSuffix, + :resultGetter + ) in primitiveTypes) { + final elementType = 'j${typeName.toLowerCase()}'; + final arrayType = '${elementType}Array'; + + /* Get */ { + final name = 'Get${typeName}ArrayElement'; + if (isField) { + functions.add(GeneratedFunction( + name, + 'JniResult (*$name)($arrayType array, jsize index);', + null, + )); + } else { + functions.add(GeneratedFunction(name, ''' +JniResult globalEnv_$name($arrayType array, jsize index) { + jvalue value; + jthrowable exception = + globalEnv_Get${typeName}ArrayRegion(array, index, 1, + &value.$jValueGetter); + return (JniResult){.value = value, .exception = exception}; +} +''', ''' + late final _$name = ptr.ref.$name.asFunction< + JniResult Function(J${typeName}ArrayPtr array, int index)>(isLeaf: true); + + $dartReturnType $name( + J${typeName}ArrayPtr array, int index) => + _$name(array, index).$resultGetter; +''')); + } + /* Set */ { + final name = 'Set${typeName}ArrayElement'; + if (isField) { + functions.add(GeneratedFunction( + name, + 'jthrowable (*$name)($arrayType array, jsize index,' + ' $elementType element);', + null, + )); + } else { + functions.add(GeneratedFunction(name, ''' +jthrowable globalEnv_$name($arrayType array, jsize index, $elementType val) { + return globalEnv_Set${typeName}ArrayRegion(array, index, 1, &val); +} +''', ''' + late final _$name = ptr.ref.$name.asFunction< + JThrowablePtr Function(J${typeName}ArrayPtr array, int index, + $dartArgumentType val)>(isLeaf: true); + + void $name( + J${typeName}ArrayPtr array, int index, $dartReturnType value) => + _$name(array, index, value$conversionSuffix).check(); +''')); + } + } + } + } + return functions; +}