-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use MethodResultContext in direct mapping (as done in interface mapping) #589
Changes from 2 commits
a2faba3
1f12326
5fbf51e
c526af2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -183,6 +183,7 @@ static jmethodID MID_DoubleBuffer_arrayOffset; | |
|
||
static jmethodID MID_Pointer_init; | ||
static jmethodID MID_Native_dispose; | ||
static jmethodID MID_Native_fromNativeCallbackParam; | ||
static jmethodID MID_Native_fromNative; | ||
static jmethodID MID_Native_nativeType; | ||
static jmethodID MID_Native_toNativeTypeMapped; | ||
|
@@ -1147,16 +1148,17 @@ static void | |
fromNativeTypeMapped(JNIEnv* env, jobject from_native, | ||
void* native_return_value, | ||
int jtype, size_t size, | ||
jclass java_return_class, | ||
jobject java_method, | ||
void* result_storage, | ||
const char* encoding) { | ||
jobject value = new_object(env, (char)jtype, native_return_value, JNI_TRUE, encoding); | ||
if (!(*env)->ExceptionCheck(env)) { | ||
jobject obj = (*env)->CallStaticObjectMethod(env, classNative, | ||
MID_Native_fromNativeTypeMapped, | ||
from_native, value, java_return_class); | ||
from_native, value, java_method); | ||
if (!(*env)->ExceptionCheck(env)) { | ||
// Convert objects into primitive types if the return class demands it | ||
jclass java_return_class = (*env)->CallObjectMethod(env, java_method, MID_Method_getReturnType); | ||
if ((*env)->IsSameObject(env, java_return_class, classPrimitiveBoolean) | ||
|| (*env)->IsSameObject(env, java_return_class, classPrimitiveByte) | ||
|| (*env)->IsSameObject(env, java_return_class, classPrimitiveCharacter) | ||
|
@@ -1175,17 +1177,29 @@ fromNativeTypeMapped(JNIEnv* env, jobject from_native, | |
} | ||
|
||
jobject | ||
fromNative(JNIEnv* env, jclass javaClass, ffi_type* type, void* resp, jboolean promote, const char* encoding) { | ||
fromNativeCallbackParam(JNIEnv* env, jclass javaClass, ffi_type* type, void* resp, jboolean promote, const char* encoding) { | ||
int jtype = get_java_type_from_ffi_type(type); | ||
jobject value = new_object(env, (char)jtype, resp, promote, encoding); | ||
if (!(*env)->ExceptionCheck(env)) { | ||
return (*env)->CallStaticObjectMethod(env, classNative, | ||
MID_Native_fromNative, | ||
MID_Native_fromNativeCallbackParam, | ||
javaClass, value); | ||
} | ||
return NULL; | ||
} | ||
|
||
jobject | ||
fromNative(JNIEnv* env, jobject javaMethod, ffi_type* type, void* resp, jboolean promote, const char* encoding) { | ||
int jtype = get_java_type_from_ffi_type(type); | ||
jobject value = new_object(env, (char)jtype, resp, promote, encoding); | ||
if (!(*env)->ExceptionCheck(env)) { | ||
return (*env)->CallStaticObjectMethod(env, classNative, | ||
MID_Native_fromNative, | ||
javaMethod, value); | ||
} | ||
return NULL; | ||
} | ||
|
||
|
||
static ffi_type* | ||
getStructureType(JNIEnv *env, jobject obj) { | ||
|
@@ -1670,7 +1684,7 @@ typedef struct _method_data { | |
ffi_type** closure_arg_types; | ||
int* flags; | ||
int rflag; | ||
jclass closure_rclass; | ||
jobject closure_method; | ||
jobject* to_native; | ||
jobject from_native; | ||
jboolean throw_last_error; | ||
|
@@ -1860,15 +1874,15 @@ dispatch_direct(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { | |
? 'c' : (data->rflag == CVT_TYPE_MAPPER_WSTRING | ||
? 'w' : get_java_type_from_ffi_type(data->cif.rtype))); | ||
fromNativeTypeMapped(env, data->from_native, resp, jtype, data->cif.rtype->size, | ||
data->closure_rclass, oldresp, data->encoding); | ||
data->closure_method, oldresp, data->encoding); | ||
} | ||
break; | ||
case CVT_INTEGER_TYPE: | ||
case CVT_POINTER_TYPE: | ||
case CVT_NATIVE_MAPPED: | ||
case CVT_NATIVE_MAPPED_STRING: | ||
case CVT_NATIVE_MAPPED_WSTRING: | ||
*(void **)oldresp = fromNative(env, data->closure_rclass, data->cif.rtype, resp, JNI_TRUE, data->encoding); | ||
*(void **)oldresp = fromNative(env, data->closure_method, data->cif.rtype, resp, JNI_TRUE, data->encoding); | ||
break; | ||
case CVT_POINTER: | ||
*(void **)resp = newJavaPointer(env, *(void **)resp); | ||
|
@@ -1880,13 +1894,22 @@ dispatch_direct(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { | |
*(void **)resp = newJavaWString(env, *(void **)resp); | ||
break; | ||
case CVT_STRUCTURE: | ||
*(void **)resp = newJavaStructure(env, *(void **)resp, data->closure_rclass); | ||
{ | ||
jclass return_class = (*env)->CallObjectMethod(env, data->closure_method, MID_Method_getReturnType); | ||
*(void **)resp = newJavaStructure(env, *(void **)resp, return_class); | ||
} | ||
break; | ||
case CVT_STRUCTURE_BYVAL: | ||
*(void **)oldresp = newJavaStructure(env, resp, data->closure_rclass); | ||
{ | ||
jclass return_class = (*env)->CallObjectMethod(env, data->closure_method, MID_Method_getReturnType); | ||
*(void **)oldresp = newJavaStructure(env, resp, return_class); | ||
} | ||
break; | ||
case CVT_CALLBACK: | ||
*(void **)resp = newJavaCallback(env, *(void **)resp, data->closure_rclass); | ||
{ | ||
jclass return_class = (*env)->CallObjectMethod(env, data->closure_method, MID_Method_getReturnType); | ||
*(void **)resp = newJavaCallback(env, *(void **)resp, return_class); | ||
} | ||
break; | ||
default: | ||
break; | ||
|
@@ -2749,11 +2772,17 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { | |
throwByName(env, EUnsatisfiedLink, | ||
"Can't obtain static method dispose from class com.sun.jna.Native"); | ||
} | ||
else if (!(MID_Native_fromNative | ||
else if (!(MID_Native_fromNativeCallbackParam | ||
= (*env)->GetStaticMethodID(env, classNative, | ||
"fromNative", "(Ljava/lang/Class;Ljava/lang/Object;)Lcom/sun/jna/NativeMapped;"))) { | ||
throwByName(env, EUnsatisfiedLink, | ||
"Can't obtain static method fromNative from class com.sun.jna.Native"); | ||
"Can't obtain static method fromNative(Class, Object) from class com.sun.jna.Native"); | ||
} | ||
else if (!(MID_Native_fromNative | ||
= (*env)->GetStaticMethodID(env, classNative, | ||
"fromNative", "(Ljava/lang/reflect/Method;Ljava/lang/Object;)Lcom/sun/jna/NativeMapped;"))) { | ||
throwByName(env, EUnsatisfiedLink, | ||
"Can't obtain static method fromNative(Method, Object) from class com.sun.jna.Native"); | ||
} | ||
else if (!(MID_Native_nativeType | ||
= (*env)->GetStaticMethodID(env, classNative, | ||
|
@@ -2769,9 +2798,9 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { | |
} | ||
else if (!(MID_Native_fromNativeTypeMapped | ||
= (*env)->GetStaticMethodID(env, classNative, | ||
"fromNative", "(Lcom/sun/jna/FromNativeConverter;Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"))) { | ||
"fromNative", "(Lcom/sun/jna/FromNativeConverter;Ljava/lang/Object;Ljava/lang/reflect/Method;)Ljava/lang/Object;"))) { | ||
throwByName(env, EUnsatisfiedLink, | ||
"Can't obtain static method fromNative from class com.sun.jna.Native"); | ||
"Can't obtain static method fromNative(FromNativeConverter, Object, Method) from class com.sun.jna.Native"); | ||
} | ||
else if (!LOAD_CREF(env, Structure, "com/sun/jna/Structure")) { | ||
throwByName(env, EUnsatisfiedLink, | ||
|
@@ -3250,7 +3279,7 @@ Java_com_sun_jna_Native_unregister(JNIEnv *env, jclass UNUSED(ncls), jclass cls, | |
} | ||
} | ||
if (md->from_native) (*env)->DeleteWeakGlobalRef(env, md->from_native); | ||
if (md->closure_rclass) (*env)->DeleteWeakGlobalRef(env, md->closure_rclass); | ||
if (md->closure_method) (*env)->DeleteGlobalRef(env, md->closure_method); | ||
free(md->arg_types); | ||
free(md->closure_arg_types); | ||
free(md->flags); | ||
|
@@ -3277,7 +3306,7 @@ Java_com_sun_jna_Native_registerMethod(JNIEnv *env, jclass UNUSED(ncls), | |
jint rconversion, | ||
jlong closure_return_type, | ||
jlong return_type, | ||
jclass closure_rclass, | ||
jobject closure_method, | ||
jlong function, jint cc, | ||
jboolean throw_last_error, | ||
jobjectArray to_native, | ||
|
@@ -3315,7 +3344,7 @@ Java_com_sun_jna_Native_registerMethod(JNIEnv *env, jclass UNUSED(ncls), | |
data->closure_arg_types = malloc(sizeof(ffi_type*) * (argc + 2)); | ||
data->closure_arg_types[0] = &ffi_type_pointer; | ||
data->closure_arg_types[1] = &ffi_type_pointer; | ||
data->closure_rclass = NULL; | ||
data->closure_method = NULL; | ||
data->flags = cvts ? malloc(sizeof(jint)*argc) : NULL; | ||
data->rflag = rconversion; | ||
data->to_native = NULL; | ||
|
@@ -3342,7 +3371,7 @@ Java_com_sun_jna_Native_registerMethod(JNIEnv *env, jclass UNUSED(ncls), | |
if (closure_types) (*env)->ReleaseLongArrayElements(env, closure_atypes, closure_types, 0); | ||
if (cvts) (*env)->ReleaseIntArrayElements(env, conversions, cvts, 0); | ||
data->fptr = L2A(function); | ||
data->closure_rclass = (*env)->NewWeakGlobalRef(env, closure_rclass); | ||
data->closure_method = (*env)->NewGlobalRef(env, closure_method); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why a global here and not a weak global? The method object should stay around as long as the callback class is extant. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised it worked before with a weak global. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it not work for you with a weak global? The return type class will be referenced by the callback class, although I'm not sure how the JVM manages references to Method objects; it's quite possible Class objects don't actually have any references to Method objects and they're only created on demand. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At any rate, if you keep a hard reference on the JNA side, you need to ensure you explicitly release it when the closure data is disposed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the weak global is collected sooner or later. The testsuite fails. Took me a while to figure out why (I assumed since a weak global was enough for the Class it should be enough for the Method). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doing it in unregister is probably sufficient.
|
||
|
||
status = ffi_prep_cif(closure_cif, abi, argc+2, closure_rtype, data->closure_arg_types); | ||
if (ffi_error(env, "Native method mapping", status)) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes to the JNI API require a bump in JNA's JNI major version, and a corresponding rebuild of all the natives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR (bumped major version from 4 to 5).
I don't think I can rebuild the natives myself unless there's some fancy cross compilation option in JNA I don't know about. I only have Linux x64. How can I do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ll deal with the native rebuilds. I have VM setups for a number of them and access to some compile farms for the others. Build and test on whichever you have available; I’ll build/test the rest after merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some VMs for other platforms, so I had access to Linux and Windows, 32bit and 64bit each to do native rebuilds:
So I committed 3 natives. I'd be happy if you could take care of the others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My win32 native rebuild is actually more than double the size of the previous one. Maybe you want to rebuild this yourself too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ll take care of the windows rebuilds.
The long name failures have been there already, they actually expose a Sun JVM bug.