Skip to content

Commit bd5b751

Browse files
[jnigen] Support Throwing Java Exceptions in Interface Impl (#1211)
Co-authored-by: Hossein Yousefi <[email protected]>
1 parent e5205d6 commit bd5b751

File tree

15 files changed

+597
-57
lines changed

15 files changed

+597
-57
lines changed

pkgs/jni/example/pubspec.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ packages:
200200
path: ".."
201201
relative: true
202202
source: path
203-
version: "0.8.0"
203+
version: "0.9.3-wip"
204204
js:
205205
dependency: transitive
206206
description:
@@ -490,10 +490,10 @@ packages:
490490
dependency: transitive
491491
description:
492492
name: vm_service
493-
sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0
493+
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
494494
url: "https://pub.dev"
495495
source: hosted
496-
version: "14.1.0"
496+
version: "14.2.1"
497497
watcher:
498498
dependency: transitive
499499
description:

pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import java.lang.reflect.*;
88

99
public class PortProxy implements InvocationHandler {
10+
private static final PortCleaner cleaner = new PortCleaner();
11+
1012
static {
1113
System.loadLibrary("dartjni");
1214
}
1315

14-
private static final PortCleaner cleaner = new PortCleaner();
1516
private final long port;
1617
private final long isolateId;
1718
private final long functionPtr;
@@ -73,22 +74,6 @@ public static Object newInstance(String binaryName, long port, long isolateId, l
7374
return obj;
7475
}
7576

76-
private static final class DartException extends Exception {
77-
private DartException(String message) {
78-
super(message);
79-
}
80-
}
81-
82-
@Override
83-
public Object invoke(Object proxy, Method method, Object[] args) throws DartException {
84-
Object[] result = _invoke(port, isolateId, functionPtr, proxy, getDescriptor(method), args);
85-
_cleanUp((Long) result[0]);
86-
if (result[1] instanceof DartException) {
87-
throw (DartException) result[1];
88-
}
89-
return result[1];
90-
}
91-
9277
/// Returns an array with two objects:
9378
/// [0]: The address of the result pointer used for the clean-up.
9479
/// [1]: The result of the invocation.
@@ -101,4 +86,28 @@ private static native Object[] _invoke(
10186
Object[] args);
10287

10388
private static native void _cleanUp(long resultPtr);
89+
90+
@Override
91+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
92+
Object[] result = _invoke(port, isolateId, functionPtr, proxy, getDescriptor(method), args);
93+
_cleanUp((Long) result[0]);
94+
if (result[1] instanceof DartException) {
95+
Throwable cause = ((DartException) result[1]).cause;
96+
if (cause != null) {
97+
throw cause;
98+
} else {
99+
throw (DartException) result[1];
100+
}
101+
}
102+
return result[1];
103+
}
104+
105+
private static final class DartException extends Exception {
106+
Throwable cause;
107+
108+
private DartException(String message, Throwable cause) {
109+
super(message);
110+
this.cause = cause;
111+
}
112+
}
104113
}

pkgs/jni/lib/src/jni.dart

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import 'dart:io';
77
import 'dart:isolate';
88

99
import 'package:ffi/ffi.dart';
10+
import 'package:jni/jni.dart';
1011
import 'package:path/path.dart';
1112

12-
import 'errors.dart';
13-
import 'jreference.dart';
14-
import 'third_party/generated_bindings.dart';
1513
import 'accessors.dart';
14+
import 'third_party/generated_bindings.dart';
1615

1716
String _getLibraryFileName(String base) {
1817
if (Platform.isLinux || Platform.isAndroid) {
@@ -221,6 +220,8 @@ typedef _SetJniGettersDartType = void Function(Pointer<Void>, Pointer<Void>);
221220

222221
/// Extensions for use by `jnigen` generated code.
223222
extension ProtectedJniExtensions on Jni {
223+
static final _jThrowableClass = JClass.forName('java/lang/Throwable');
224+
224225
static Pointer<T> Function<T extends NativeType>(String) initGeneratedLibrary(
225226
String name) {
226227
var path = _getLibraryFileName(name);
@@ -237,9 +238,16 @@ extension ProtectedJniExtensions on Jni {
237238
}
238239

239240
/// Returns a new DartException.
240-
static Pointer<Void> newDartException(String message) {
241+
static Pointer<Void> newDartException(Object exception) {
242+
JObjectPtr? cause;
243+
if (exception is JObject &&
244+
Jni.env.IsInstanceOf(
245+
exception.reference.pointer, _jThrowableClass.reference.pointer)) {
246+
cause = exception.reference.pointer;
247+
}
241248
return Jni._bindings
242-
.DartException__ctor(Jni.env.toJStringPtr(message))
249+
.DartException__ctor(
250+
Jni.env.toJStringPtr(exception.toString()), cause ?? nullptr)
243251
.objectPointer;
244252
}
245253

pkgs/jni/lib/src/jprimitives.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ final class jdoubleType extends JType<jdouble>
363363
}
364364

365365
abstract final class jvoid extends JPrimitive {
366-
static const type = jdoubleType();
366+
static const type = jvoidType();
367367
}
368368

369369
final class jvoidType extends JType<jvoid> with JCallable<jvoid, void> {

pkgs/jni/lib/src/third_party/jni_bindings_generated.dart

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,19 @@ class JniBindings {
162162

163163
JniResult DartException__ctor(
164164
JStringPtr message,
165+
JThrowablePtr cause,
165166
) {
166167
return _DartException__ctor(
167168
message,
169+
cause,
168170
);
169171
}
170172

171-
late final _DartException__ctorPtr =
172-
_lookup<ffi.NativeFunction<JniResult Function(JStringPtr)>>(
173-
'DartException__ctor');
174-
late final _DartException__ctor =
175-
_DartException__ctorPtr.asFunction<JniResult Function(JStringPtr)>();
173+
late final _DartException__ctorPtr = _lookup<
174+
ffi.NativeFunction<JniResult Function(JStringPtr, JThrowablePtr)>>(
175+
'DartException__ctor');
176+
late final _DartException__ctor = _DartException__ctorPtr.asFunction<
177+
JniResult Function(JStringPtr, JThrowablePtr)>();
176178

177179
JniResult PortContinuation__ctor(
178180
int j,
@@ -2081,30 +2083,78 @@ final class CallbackResult extends ffi.Struct {
20812083
external JObjectPtr object;
20822084
}
20832085

2084-
typedef MutexLock = pthread_mutex_t;
2085-
typedef pthread_mutex_t = __darwin_pthread_mutex_t;
2086-
typedef __darwin_pthread_mutex_t = _opaque_pthread_mutex_t;
2086+
typedef MutexLock = CRITICAL_SECTION;
2087+
typedef CRITICAL_SECTION = RTL_CRITICAL_SECTION;
2088+
typedef RTL_CRITICAL_SECTION = _RTL_CRITICAL_SECTION;
20872089

2088-
final class _opaque_pthread_mutex_t extends ffi.Struct {
2089-
@ffi.Long()
2090-
external int __sig;
2090+
final class _RTL_CRITICAL_SECTION extends ffi.Struct {
2091+
external PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
20912092

2092-
@ffi.Array.multi([56])
2093-
external ffi.Array<ffi.Char> __opaque;
2093+
@LONG()
2094+
external int LockCount;
2095+
2096+
@LONG()
2097+
external int RecursionCount;
2098+
2099+
external HANDLE OwningThread;
2100+
2101+
external HANDLE LockSemaphore;
2102+
2103+
@ULONG_PTR()
2104+
external int SpinCount;
2105+
}
2106+
2107+
typedef PRTL_CRITICAL_SECTION_DEBUG = ffi.Pointer<_RTL_CRITICAL_SECTION_DEBUG>;
2108+
2109+
final class _RTL_CRITICAL_SECTION_DEBUG extends ffi.Struct {
2110+
@WORD()
2111+
external int Type;
2112+
2113+
@WORD()
2114+
external int CreatorBackTraceIndex;
2115+
2116+
external ffi.Pointer<_RTL_CRITICAL_SECTION> CriticalSection;
2117+
2118+
external LIST_ENTRY ProcessLocksList;
2119+
2120+
@DWORD()
2121+
external int EntryCount;
2122+
2123+
@DWORD()
2124+
external int ContentionCount;
2125+
2126+
@DWORD()
2127+
external int Flags;
2128+
2129+
@WORD()
2130+
external int CreatorBackTraceIndexHigh;
2131+
2132+
@WORD()
2133+
external int Identifier;
20942134
}
20952135

2096-
typedef ConditionVariable = pthread_cond_t;
2097-
typedef pthread_cond_t = __darwin_pthread_cond_t;
2098-
typedef __darwin_pthread_cond_t = _opaque_pthread_cond_t;
2136+
typedef WORD = ffi.UnsignedShort;
2137+
typedef LIST_ENTRY = _LIST_ENTRY;
2138+
2139+
final class _LIST_ENTRY extends ffi.Struct {
2140+
external ffi.Pointer<_LIST_ENTRY> Flink;
2141+
2142+
external ffi.Pointer<_LIST_ENTRY> Blink;
2143+
}
20992144

2100-
final class _opaque_pthread_cond_t extends ffi.Struct {
2101-
@ffi.Long()
2102-
external int __sig;
2145+
typedef DWORD = ffi.UnsignedLong;
2146+
typedef LONG = ffi.Long;
2147+
typedef HANDLE = ffi.Pointer<ffi.Void>;
2148+
typedef ULONG_PTR = ffi.UnsignedLongLong;
2149+
typedef ConditionVariable = CONDITION_VARIABLE;
2150+
typedef CONDITION_VARIABLE = RTL_CONDITION_VARIABLE;
2151+
typedef RTL_CONDITION_VARIABLE = _RTL_CONDITION_VARIABLE;
21032152

2104-
@ffi.Array.multi([40])
2105-
external ffi.Array<ffi.Char> __opaque;
2153+
final class _RTL_CONDITION_VARIABLE extends ffi.Struct {
2154+
external PVOID Ptr;
21062155
}
21072156

2157+
typedef PVOID = ffi.Pointer<ffi.Void>;
21082158
typedef Dart_FinalizableHandle = ffi.Pointer<_Dart_FinalizableHandle>;
21092159

21102160
final class _Dart_FinalizableHandle extends ffi.Opaque {}

pkgs/jni/src/dartjni.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -683,18 +683,19 @@ FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data) {
683683
jclass _c_DartException = NULL;
684684

685685
jmethodID _m_DartException__ctor = NULL;
686-
FFI_PLUGIN_EXPORT JniResult DartException__ctor(jstring message) {
686+
FFI_PLUGIN_EXPORT JniResult DartException__ctor(jstring message,
687+
jthrowable cause) {
687688
attach_thread();
688689
load_class_global_ref(&_c_DartException,
689690
"com/github/dart_lang/jni/PortProxy$DartException");
690691
if (_c_DartException == NULL)
691692
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
692693
load_method(_c_DartException, &_m_DartException__ctor, "<init>",
693-
"(Ljava/lang/String;)V");
694+
"(Ljava/lang/String;Ljava/lang/Throwable;)V");
694695
if (_m_DartException__ctor == NULL)
695696
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
696-
jobject _result = (*jniEnv)->NewObject(jniEnv, _c_DartException,
697-
_m_DartException__ctor, message);
697+
jobject _result = (*jniEnv)->NewObject(
698+
jniEnv, _c_DartException, _m_DartException__ctor, message, cause);
698699
jthrowable exception = check_exception();
699700
if (exception == NULL) {
700701
_result = to_global_ref(_result);

pkgs/jni/src/dartjni.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ static inline JniResult to_global_ref_result(jobject ref) {
382382
FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data);
383383

384384
FFI_PLUGIN_EXPORT
385-
JniResult DartException__ctor(jstring message);
385+
JniResult DartException__ctor(jstring message, jthrowable cause);
386386

387387
FFI_PLUGIN_EXPORT
388388
JniResult PortContinuation__ctor(int64_t j);

pkgs/jnigen/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
- Fixed a bug where wrong argument types were generated for varargs.
44
- Fixed the macOS arm64 varargs issue caused by the previous release.
5-
5+
- Support throwing Java exceptions from Dart code.
6+
([#1209](https://github.com/dart-lang/native/issues/1209))
67

78
## 0.9.2
89

pkgs/jnigen/lib/src/bindings/dart_generator.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ class $name$typeParamsDef extends $superName {
413413
}
414414
s.write('''
415415
} catch (e) {
416-
return $_protectedExtension.newDartException(e.toString());
416+
return $_protectedExtension.newDartException(e);
417417
}
418418
return jni.nullptr;
419419
}

0 commit comments

Comments
 (0)