static void invoke_callback(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) { jobject self; void *oldresp = resp; self = (*env)->NewLocalRef(env, cb->object); // Avoid calling back to a GC'd object if ((*env)->IsSameObject(env, self, NULL)) { fprintf(stderr, "JNA: callback object has been garbage collected\n"); if (cif->rtype->type != FFI_TYPE_VOID) { memset(resp, 0, cif->rtype->size); } } else if (cb->direct) { unsigned int i; void **args = alloca((cif->nargs + 3) * sizeof(void *)); args[0] = (void *)&env; args[1] = &self; args[2] = &cb->methodID; memcpy(&args[3], cbargs, cif->nargs * sizeof(void *)); // Note that there is no support for CVT_TYPE_MAPPER here if (cb->conversion_flags) { for (i=0;i < cif->nargs;i++) { switch(cb->conversion_flags[i]) { case CVT_INTEGER_TYPE: case CVT_POINTER_TYPE: case CVT_NATIVE_MAPPED: case CVT_NATIVE_MAPPED_STRING: case CVT_NATIVE_MAPPED_WSTRING: // Make sure we have space enough for the new argument args[i+3] = alloca(sizeof(void *)); *((void **)args[i+3]) = fromNativeCallbackParam(env, cb->arg_classes[i], cif->arg_types[i], cbargs[i], JNI_FALSE, cb->encoding); break; case CVT_POINTER: *((void **)args[i+3]) = newJavaPointer(env, *(void **)cbargs[i]); break; case CVT_STRING: *((void **)args[i+3]) = newJavaString(env, *(void **)cbargs[i], cb->encoding); break; case CVT_WSTRING: *((void **)args[i+3]) = newJavaWString(env, *(void **)cbargs[i]); break; case CVT_STRUCTURE: *((void **)args[i+3]) = newJavaStructure(env, *(void **)cbargs[i], cb->arg_classes[i]); break; case CVT_STRUCTURE_BYVAL: args[i+3] = alloca(sizeof(void *)); *((void **)args[i+3]) = newJavaStructure(env, cbargs[i], cb->arg_classes[i]); break; case CVT_CALLBACK: *((void **)args[i+3]) = newJavaCallback(env, *(void **)cbargs[i], cb->arg_classes[i]); break; case CVT_FLOAT: args[i+3] = alloca(sizeof(double)); *((double *)args[i+3]) = *(float*)cbargs[i]; break; case CVT_DEFAULT: break; default: fprintf(stderr, "JNA: Unhandled arg conversion type %d\n", cb->conversion_flags[i]); break; } } } if (cb->rflag == CVT_STRUCTURE_BYVAL) { resp = alloca(sizeof(jobject)); } else if (cb->cif.rtype->size > cif->rtype->size) { resp = alloca(cb->cif.rtype->size); } #define FPTR(ENV,OFFSET) (*(void **)((char *)(*(ENV)) + OFFSET)) #define JNI_FN(X) ((void (*)(void))(X)) ffi_call(&cb->java_cif, JNI_FN(FPTR(env, cb->fptr_offset)), resp, args); if ((*env)->ExceptionCheck(env)) { jthrowable throwable = (*env)->ExceptionOccurred(env); (*env)->ExceptionClear(env); if (!handle_exception(env, self, throwable)) { fprintf(stderr, "JNA: error handling callback exception, continuing\n"); } if (cif->rtype->type != FFI_TYPE_VOID) { memset(oldresp, 0, cif->rtype->size); } } else switch(cb->rflag) { case CVT_INTEGER_TYPE: if (cb->cif.rtype->size > sizeof(ffi_arg)) { *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp); } else { *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp); } break; case CVT_POINTER_TYPE: *(void **)resp = getPointerTypeAddress(env, *(void **)resp); break; case CVT_NATIVE_MAPPED: toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding); break; case CVT_NATIVE_MAPPED_STRING: case CVT_NATIVE_MAPPED_WSTRING: // TODO: getNativeString rather than allocated memory fprintf(stderr, "JNA: Likely memory leak here\n"); toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding); break; case CVT_POINTER: *(void **)resp = getNativeAddress(env, *(void **)resp); break; case CVT_STRING: *(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE); break; case CVT_WSTRING: *(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE); break; case CVT_STRUCTURE: writeStructure(env, *(void **)resp); *(void **)resp = getStructureAddress(env, *(void **)resp); break; case CVT_STRUCTURE_BYVAL: writeStructure(env, *(void **)resp); memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size); break; case CVT_CALLBACK: *(void **)resp = getCallbackAddress(env, *(void **)resp); break; case CVT_DEFAULT: break; default: fprintf(stderr, "JNA: Unhandled result conversion: %d\n", cb->rflag); break; } if (cb->conversion_flags) { for (i=0;i < cif->nargs;i++) { if (cb->conversion_flags[i] == CVT_STRUCTURE) { writeStructure(env, *(void **)cbargs[i]); } } } } else { jobject result; jobjectArray params = (*env)->NewObjectArray(env, cif->nargs, classObject, NULL); unsigned int i; for (i=0;i < cif->nargs;i++) { jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE, cb->encoding); (*env)->SetObjectArrayElement(env, params, i, arg); } result = (*env)->CallObjectMethod(env, self, cb->methodID, params); if ((*env)->ExceptionCheck(env)) { jthrowable throwable = (*env)->ExceptionOccurred(env); (*env)->ExceptionClear(env); if (!handle_exception(env, self, throwable)) { fprintf(stderr, "JNA: error while handling callback exception, continuing\n"); } if (cif->rtype->type != FFI_TYPE_VOID) memset(resp, 0, cif->rtype->size); } else { extract_value(env, result, resp, cif->rtype->size, JNI_TRUE, cb->encoding); } } }
static void callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) { jobject self; void *oldresp = resp; self = (*env)->NewLocalRef(env, cb->object); // Avoid calling back to a GC'd object if ((*env)->IsSameObject(env, self, NULL)) { fprintf(stderr, "JNA: callback object has been garbage collected\n"); if (cif->rtype->type != FFI_TYPE_VOID) { memset(resp, 0, cif->rtype->size); } } else if (cb->direct) { unsigned int i; void **args = alloca((cif->nargs + 3) * sizeof(void *)); args[0] = (void *)&env; args[1] = &self; args[2] = &cb->methodID; memcpy(&args[3], cbargs, cif->nargs * sizeof(void *)); if (cb->flags) { for (i=0;i < cif->nargs;i++) { switch(cb->flags[i]) { case CVT_INTEGER_TYPE: case CVT_POINTER_TYPE: case CVT_NATIVE_MAPPED: *((void **)args[i+3]) = fromNative(env, cb->arg_classes[i], cif->arg_types[i], args[i+3], JNI_FALSE); break; case CVT_POINTER: *((void **)args[i+3]) = newJavaPointer(env, *(void **)args[i+3]); break; case CVT_STRING: *((void **)args[i+3]) = newJavaString(env, *(void **)args[i+3], JNI_FALSE); break; case CVT_WSTRING: *((void **)args[i+3]) = newJavaWString(env, *(void **)args[i+3]); break; case CVT_STRUCTURE: *((void **)args[i+3]) = newJavaStructure(env, *(void **)args[i+3], cb->arg_classes[i], JNI_FALSE); break; case CVT_STRUCTURE_BYVAL: { void *ptr = args[i+3]; args[i+3] = alloca(sizeof(void *)); *((void **)args[i+3]) = newJavaStructure(env, ptr, cb->arg_classes[i], JNI_TRUE); } break; case CVT_CALLBACK: *((void **)args[i+3]) = newJavaCallback(env, *(void **)args[i+3], cb->arg_classes[i]); break; case CVT_FLOAT: { void *ptr = alloca(sizeof(double)); *(double *)ptr = *(float*)args[i+3]; args[i+3] = ptr; } break; } } } if (cb->rflag == CVT_STRUCTURE_BYVAL) { resp = alloca(sizeof(jobject)); } else if (cb->cif.rtype->size > cif->rtype->size) { resp = alloca(cb->cif.rtype->size); } ffi_call(&cb->java_cif, FFI_FN(cb->fptr), resp, args); if ((*env)->ExceptionCheck(env)) { jthrowable throwable = (*env)->ExceptionOccurred(env); (*env)->ExceptionClear(env); if (!handle_exception(env, self, throwable)) { fprintf(stderr, "JNA: error handling callback exception, continuing\n"); } if (cif->rtype->type != FFI_TYPE_VOID) memset(oldresp, 0, cif->rtype->size); } else switch(cb->rflag) { case CVT_INTEGER_TYPE: if (cb->cif.rtype->size > sizeof(ffi_arg)) { *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp); } else { *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp); } break; case CVT_POINTER_TYPE: *(void **)resp = getPointerTypeAddress(env, *(void **)resp); break; case CVT_NATIVE_MAPPED: toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE); break; case CVT_POINTER: *(void **)resp = getNativeAddress(env, *(void **)resp); break; case CVT_STRING: *(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE); break; case CVT_WSTRING: *(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE); break; case CVT_STRUCTURE: writeStructure(env, *(void **)resp); *(void **)resp = getStructureAddress(env, *(void **)resp); break; case CVT_STRUCTURE_BYVAL: writeStructure(env, *(void **)resp); memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size); break; case CVT_CALLBACK: *(void **)resp = getCallbackAddress(env, *(void **)resp); break; default: break; } if (cb->flags) { for (i=0;i < cif->nargs;i++) { if (cb->flags[i] == CVT_STRUCTURE) { writeStructure(env, *(void **)args[i+3]); } } } } else { jobject result; jobjectArray array = (*env)->NewObjectArray(env, cif->nargs, classObject, NULL); unsigned int i; for (i=0;i < cif->nargs;i++) { jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE); (*env)->SetObjectArrayElement(env, array, i, arg); } result = (*env)->CallObjectMethod(env, self, cb->methodID, array); if ((*env)->ExceptionCheck(env)) { jthrowable throwable = (*env)->ExceptionOccurred(env); (*env)->ExceptionClear(env); if (!handle_exception(env, self, throwable)) { fprintf(stderr, "JNA: error handling callback exception, continuing\n"); } if (cif->rtype->type != FFI_TYPE_VOID) memset(resp, 0, cif->rtype->size); } else { extract_value(env, result, resp, cif->rtype->size, JNI_TRUE); } } }