Skip to content

Commit

Permalink
Make Some JNI functions leaf and remove Jni.accessors (#1355)
Browse files Browse the repository at this point in the history
* Make some functions leaf, refactor array construction
* Remove Jni.accessors
  • Loading branch information
HosseinYousefi authored Jul 23, 2024
1 parent 4423654 commit 7efefec
Show file tree
Hide file tree
Showing 21 changed files with 1,009 additions and 1,078 deletions.
5 changes: 5 additions & 0 deletions pkgs/jni/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 0 additions & 1 deletion pkgs/jni/lib/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
19 changes: 1 addition & 18 deletions pkgs/jni/lib/src/accessors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '../jni.dart';

void _check(JThrowablePtr exception) {
if (exception != nullptr) {
Jni.accessors.throwException(exception);
Jni.throwException(exception);
}
}

Expand Down Expand Up @@ -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);
}
}
116 changes: 33 additions & 83 deletions pkgs/jni/lib/src/jarray.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<E> extends JObjType<JArray<E>> {
final JType<E> elementType;
final JArrayElementType<E> elementType;

const JArrayType(this.elementType);

Expand Down Expand Up @@ -46,13 +36,13 @@ final class JArrayType<E> extends JObjType<JArray<E>> {
}

class JArray<E> extends JObject {
final JType<E> elementType;
final JArrayElementType<E> elementType;

@override
late final JArrayType<E> $type = type(elementType) as JArrayType<E>;

/// The type which includes information such as the signature of this class.
static JObjType<JArray<T>> type<T>(JType<T> innerType) =>
static JObjType<JArray<T>> type<T>(JArrayElementType<T> innerType) =>
JArrayType(innerType);

/// Construct a new [JArray] with [reference] as its underlying reference.
Expand All @@ -62,40 +52,8 @@ class JArray<E> extends JObject {
/// Creates a [JArray] of the given length from the given [elementType].
///
/// The [length] must be a non-negative integer.
factory JArray(JType<E> 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<E>.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<E> elementType, int length) {
return elementType._newArray(length);
}

/// Creates a [JArray] of the given length with [fill] at each position.
Expand All @@ -105,25 +63,11 @@ class JArray<E> 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);
Expand Down Expand Up @@ -154,13 +98,13 @@ extension on Allocator {

extension BoolArray on JArray<jboolean> {
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}) {
Expand All @@ -187,12 +131,13 @@ extension BoolArray on JArray<jboolean> {

extension ByteArray on JArray<jbyte> {
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}) {
Expand Down Expand Up @@ -222,12 +167,13 @@ extension ByteArray on JArray<jbyte> {
/// the number of characters.
extension CharArray on JArray<jchar> {
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}) {
Expand All @@ -253,12 +199,13 @@ extension CharArray on JArray<jchar> {

extension ShortArray on JArray<jshort> {
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}) {
Expand All @@ -284,12 +231,13 @@ extension ShortArray on JArray<jshort> {

extension IntArray on JArray<jint> {
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}) {
Expand All @@ -315,12 +263,13 @@ extension IntArray on JArray<jint> {

extension LongArray on JArray<jlong> {
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}) {
Expand All @@ -346,12 +295,13 @@ extension LongArray on JArray<jlong> {

extension FloatArray on JArray<jfloat> {
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}) {
Expand All @@ -377,14 +327,13 @@ extension FloatArray on JArray<jfloat> {

extension DoubleArray on JArray<jdouble> {
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}) {
Expand All @@ -410,8 +359,9 @@ extension DoubleArray on JArray<jdouble> {

extension ObjectArray<T extends JObject> on JArray<T> {
T operator [](int index) {
RangeError.checkValidIndex(index, this);
return (elementType as JObjType<T>).fromReference(JGlobalReference(
_elementAt(index, JniCallType.objectType).objectPointer));
Jni.env.GetObjectArrayElement(reference.pointer, index)));
}

void operator []=(int index, T value) {
Expand Down
35 changes: 11 additions & 24 deletions pkgs/jni/lib/src/jclass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<JavaT, DartT>(JObject object, JAccessible<JavaT, DartT> type) {
return type._instanceGet(object.reference.pointer, this as JFieldIDPtr);
Expand All @@ -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<JavaT, DartT>(JClass jClass, JAccessible<JavaT, DartT> type) {
return type._staticGet(jClass.reference.pointer, this as JFieldIDPtr);
Expand All @@ -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<JavaT, DartT>(
Expand All @@ -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<JavaT, DartT>(
Expand All @@ -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,
'<init>'.toNativeChars(arena),
signature.toNativeChars(arena),
)
.methodID);
));

/// Constructs an instance of [jClass] with the given arguments.
DartT call<JavaT, DartT>(JClass jClass,
Expand Down
Loading

0 comments on commit 7efefec

Please sign in to comment.