Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Rename delete to release (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
HosseinYousefi authored Aug 30, 2023
1 parent 8562a31 commit 2b5c459
Show file tree
Hide file tree
Showing 51 changed files with 1,171 additions and 1,148 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ If the errors are similar to `symbol not found`, ensure all dependencies of the
#### How are classes mapped into bindings?
Each Java class generates a subclass of `JObject` class, which wraps a `jobject` reference in JNI. Nested classes use `_` as separator, `Example.NestedClass` will be mapped to `Example_NestedClass`.

#### Does `JObject` hold a local or global reference? Does it need to be manually deleted?
#### Does `JObject` hold a local or global reference? Does it need to be manually released?
Each Java object returned into Dart creates a JNI global reference. Reference deletion is taken care of by `NativeFinalizer` and that's usually sufficient.

It's a good practice to keep the interface between languages sparse. However, if there's a need to create several references (Eg: in a loop), you can use FFI Arena mechanism (`using` function) and `deletedIn` method, or manually delete the object using `delete` method.
It's a good practice to keep the interface between languages sparse. However, if there's a need to create several references (Eg: in a loop), you can use FFI Arena mechanism (`using` function) and `releasedBy` method, or manually release the object using `release` method.

#### Should I use `jnigen` over Method channels?
This is currently an experimental package. Many features are missing, and it's rough around the edges. You're welcome to try it and give feedback.
Expand Down
3 changes: 2 additions & 1 deletion jni/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## 0.6.0-wip-2
## 0.6.0
* **Breaking Change** ([#131](https://github.com/dart-lang/jnigen/issues/131)): Renamed `delete*` to `release*`.
* Added `PortProxy` and related methods used for interface implementation.
* Added the missing binding for `java.lang.Character`.

Expand Down
6 changes: 2 additions & 4 deletions jni/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ This is a support library to access JNI from Dart / Flutter code. This provides

This library contains:

* functions to access the JNIEnv and JavaVM variables from JNI, and wrapper functions to those provided by JNI. JNIEnv is exposed via `GlobalJniEnv` type which provides a thin abstraction over JNIEnv, so that it can be used from multiple threads.

* Functions to access the JNIEnv and JavaVM variables from JNI, and wrapper functions to those provided by JNI. JNIEnv is exposed via `GlobalJniEnv` type which provides a thin abstraction over JNIEnv, so that it can be used from multiple threads.
* Functions to spawn a JVM on desktop platforms (`Jni.spawn`).

* Some Android-specific helpers (get application context and current activity references).

* `JObject` class, which provides base class for classes generated by jnigen.
* Commonly used Java classes like `JList`, `JMap`, `JInteger`, ...

Apart from being the base library for code generated by `jnigen` this can also be used for one-off uses of the JNI and debugging. __To generate type-safe bindings from Java libraries, use `jnigen`.__

Expand Down
4 changes: 2 additions & 2 deletions jni/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ int randomUsingEnv(int n) => using((arena) {
double randomDouble() {
final math = Jni.findJClass("java/lang/Math");
final random = math.callStaticMethodByName<double>("random", "()D", []);
math.delete();
math.release();
return random;
}

Expand All @@ -57,7 +57,7 @@ int uptime() {

String backAndForth() {
final jstring = '🪓'.toJString();
final dartString = jstring.toDartString(deleteOriginal: true);
final dartString = jstring.toDartString(releaseOriginal: true);
return dartString;
}

Expand Down
2 changes: 1 addition & 1 deletion jni/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.6.0-wip.2"
version: "0.6.0"
js:
dependency: transitive
description:
Expand Down
4 changes: 2 additions & 2 deletions jni/lib/src/jarray.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class JArray<E> extends JObject {
type,
Jni.accessors.newObjectArray(length, clazz.reference, nullptr).object,
);
clazz.delete();
clazz.release();
return array;
}
return JArray.fromRef(
Expand All @@ -102,7 +102,7 @@ class JArray<E> extends JObject {
.newObjectArray(length, clazz.reference, fill.reference)
.object,
);
clazz.delete();
clazz.release();
return array;
}

Expand Down
12 changes: 6 additions & 6 deletions jni/lib/src/jexceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import 'package:jni/src/third_party/generated_bindings.dart';

abstract class JException implements Exception {}

class UseAfterFreeException implements JException {
class UseAfterReleaseException implements JException {
final Pointer<Void> ptr;
UseAfterFreeException(this.ptr);
UseAfterReleaseException(this.ptr);

@override
String toString() {
return 'Use after free on $ptr.';
return 'Use after release on $ptr.';
}
}

Expand All @@ -34,13 +34,13 @@ class InvalidJStringException implements JException {
'0x${reference.address.toRadixString(16)}.';
}

class DoubleFreeException implements JException {
class DoubleReleaseException implements JException {
final Pointer<Void> ptr;
DoubleFreeException(this.ptr);
DoubleReleaseException(this.ptr);

@override
String toString() {
return 'Double free on $ptr.';
return 'Double release on $ptr.';
}
}

Expand Down
20 changes: 6 additions & 14 deletions jni/lib/src/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:path/path.dart';

import 'jexceptions.dart';
import 'jobject.dart';
import 'jreference.dart';
import 'third_party/generated_bindings.dart';
import 'jvalues.dart';
import 'accessors.dart';
Expand Down Expand Up @@ -230,7 +229,7 @@ abstract class Jni {
final cls = findJClass(qualifiedName);
final ctor = cls.getCtorID(ctorSignature);
final obj = cls.newInstance(ctor, args);
cls.delete();
cls.release();
return obj;
}

Expand All @@ -252,7 +251,7 @@ abstract class Jni {
[int? callType]) {
final cls = findJClass(className);
final result = cls.getStaticFieldByName<T>(fieldName, signature, callType);
cls.delete();
cls.release();
return result;
}

Expand All @@ -267,16 +266,9 @@ abstract class Jni {
final cls = findJClass(className);
final result =
cls.callStaticMethodByName<T>(methodName, signature, args, callType);
cls.delete();
cls.release();
return result;
}

/// Delete all references in [objects].
static void deleteAll(List<JReference> objects) {
for (var object in objects) {
object.delete();
}
}
}

typedef _SetJniGettersNativeType = Void Function(Pointer<Void>, Pointer<Void>);
Expand Down Expand Up @@ -340,9 +332,9 @@ extension ProtectedJniExtensions on Jni {
extension AdditionalEnvMethods on GlobalJniEnv {
/// Convenience method for converting a [JStringPtr]
/// to dart string.
/// if [deleteOriginal] is specified, jstring passed will be deleted using
/// if [releaseOriginal] is specified, jstring passed will be deleted using
/// DeleteGlobalRef.
String toDartString(JStringPtr jstringPtr, {bool deleteOriginal = false}) {
String toDartString(JStringPtr jstringPtr, {bool releaseOriginal = false}) {
if (jstringPtr == nullptr) {
throw const JNullException();
}
Expand All @@ -352,7 +344,7 @@ extension AdditionalEnvMethods on GlobalJniEnv {
}
final result = chars.cast<Utf16>().toDartString();
ReleaseStringChars(jstringPtr, chars);
if (deleteOriginal) {
if (releaseOriginal) {
DeleteGlobalRef(jstringPtr);
}
return result;
Expand Down
29 changes: 17 additions & 12 deletions jni/lib/src/jobject.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ T _callOrGet<T>(int? callType, JniResult Function(int) function) {
callType, JniCallType.objectType, {JniCallType.objectType});
final ref = function(finalCallType).object;
final ctor = T == String
? (ref) => Jni.env.toDartString(ref, deleteOriginal: true)
? (ref) => Jni.env.toDartString(ref, releaseOriginal: true)
: (T == JObject ? JObject.fromRef : JString.fromRef);
result = ctor(ref) as T;
break;
Expand Down Expand Up @@ -177,12 +177,12 @@ class JObject extends JReference {
return _jClass ??= getClass();
}

/// Deletes the JNI reference and marks this object as deleted. Any further
/// uses will throw [UseAfterFreeException].
/// Deletes the JNI reference and marks this object as released. Any further
/// uses will throw [UseAfterReleaseException].
@override
void delete() {
_jClass?.delete();
super.delete();
void release() {
_jClass?.release();
super.release();
}

/// Returns [JClass] corresponding to concrete class of this object.
Expand Down Expand Up @@ -304,12 +304,17 @@ class JObject extends JReference {
return callStaticMethod<T>(id, args, callType);
}

/// Casts this object to another type.
T castTo<T extends JObject>(JObjType<T> type, {bool deleteOriginal = false}) {
if (deleteOriginal) {
_jClass?.delete();
/// Casts this object to another [type].
///
/// If [releaseOriginal] is `true`, the casted object will be released.
T castTo<T extends JObject>(
JObjType<T> type, {
bool releaseOriginal = false,
}) {
if (releaseOriginal) {
_jClass?.release();
final ret = type.fromRef(reference);
setAsDeleted();
setAsReleased();
return ret;
}
final newRef = Jni.env.NewGlobalRef(reference);
Expand Down Expand Up @@ -341,7 +346,7 @@ class JObject extends JReference {
String toString() {
return JString.fromRef(Jni.accessors.callMethodWithArgs(
reference, _toStringId, JniCallType.objectType, []).object)
.toDartString(deleteOriginal: true);
.toDartString(releaseOriginal: true);
}
}

Expand Down
43 changes: 22 additions & 21 deletions jni/lib/src/jreference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import 'jexceptions.dart';
import 'jni.dart';

extension ProtectedJReference on JReference {
void setAsDeleted() {
if (_deleted) {
throw DoubleFreeException(_reference);
void setAsReleased() {
if (_released) {
throw DoubleReleaseException(_reference);
}
_deleted = true;
_released = true;
JReference._finalizer.detach(this);
}

Expand All @@ -29,13 +29,14 @@ extension ProtectedJReference on JReference {
///
/// Detaches the finalizer so the underlying pointer will not be deleted.
JObjectPtr toPointer() {
setAsDeleted();
setAsReleased();
return _reference;
}
}

/// A class which holds one or more JNI references, and has a `delete` operation
/// which disposes the reference(s).
/// A managed JNI global reference.
///
/// Uses a [NativeFinalizer] to delete the JNI global reference when finalized.
abstract class JReference implements Finalizable {
static final _finalizer =
NativeFinalizer(Jni.env.ptr.ref.DeleteGlobalRef.cast());
Expand All @@ -44,37 +45,37 @@ abstract class JReference implements Finalizable {
_finalizer.attach(this, _reference, detach: this);
}

bool _deleted = false;
bool _released = false;

/// Check whether the underlying JNI reference is `null`.
bool get isNull => reference == nullptr;

/// Returns whether this object is deleted.
bool get isDeleted => _deleted;
/// Returns `true` if the underlying JNI reference is deleted.
bool get isReleased => _released;

/// Deletes the underlying JNI reference.
///
/// Further uses will throw [UseAfterFreeException].
void delete() {
setAsDeleted();
/// Further uses will throw [UseAfterReleaseException].
void release() {
setAsReleased();
Jni.env.DeleteGlobalRef(_reference);
}

/// The underlying JNI global object reference.
///
/// Throws [UseAfterFreeException] if the object is previously deleted.
/// Throws [UseAfterReleaseException] if the object is previously released.
///
/// Be careful when storing this reference in a variable, since the underlying
/// object might get deleted.
/// Be careful when storing this in a variable since it might have gotten
/// released upon use.
JObjectPtr get reference {
if (_deleted) throw UseAfterFreeException(_reference);
if (_released) throw UseAfterReleaseException(_reference);
return _reference;
}

final JObjectPtr _reference;

/// Registers this object to be deleted at the end of [arena]'s lifetime.
void deletedIn(Arena arena) => arena.onReleaseAll(delete);
/// Registers this object to be released at the end of [arena]'s lifetime.
void releasedBy(Arena arena) => arena.onReleaseAll(release);
}

extension JReferenceUseExtension<T extends JReference> on T {
Expand All @@ -83,10 +84,10 @@ extension JReferenceUseExtension<T extends JReference> on T {
R use<R>(R Function(T) callback) {
try {
final result = callback(this);
delete();
release();
return result;
} catch (e) {
delete();
release();
rethrow;
}
}
Expand Down
6 changes: 3 additions & 3 deletions jni/lib/src/lang/jboolean.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ class JBoolean extends JObject {
static final _booleanValueId =
Jni.accessors.getMethodIDOf(_class.reference, r"booleanValue", r"()Z");

bool booleanValue({bool deleteOriginal = false}) {
bool booleanValue({bool releaseOriginal = false}) {
ensureNotNull();
final ret = Jni.accessors.callMethodWithArgs(
reference, _booleanValueId, JniCallType.booleanType, []).boolean;
if (deleteOriginal) {
delete();
if (releaseOriginal) {
release();
}
return ret;
}
Expand Down
6 changes: 3 additions & 3 deletions jni/lib/src/lang/jcharacter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ class JCharacter extends JObject {
static final _charValueId =
Jni.accessors.getMethodIDOf(_class.reference, r"charValue", r"()C");

int charValue({bool deleteOriginal = false}) {
int charValue({bool releaseOriginal = false}) {
ensureNotNull();
final ret = Jni.accessors.callMethodWithArgs(
reference, _charValueId, JniCallType.charType, []).char;
if (deleteOriginal) {
delete();
if (releaseOriginal) {
release();
}
return ret;
}
Expand Down
Loading

0 comments on commit 2b5c459

Please sign in to comment.