#include #include #include #include "ffijni.h" #include "jni.h" #if defined(FFIJNI_LINUX) || defined(FFIJNI_MACOSX) #include #else #if defined(FFIJNI_WINDOWS) #include #endif #endif #define FFIJNI_VERSION JNI_VERSION_1_6 #ifdef FFIJNI_DEBUG /* def FFIJNI_DEBUG */ static jboolean _ffijni_debug = JNI_FALSE; jboolean getDebugStatus() { return _ffijni_debug; } void setDebugStatus(jboolean status) { _ffijni_debug = status; } #define DEBUG(STR) \ if (_ffijni_debug) { \ printf("ffijni: %s\n", STR); \ } #define DEBUG1(STR, ARG1) \ if (_ffijni_debug) { \ printf("ffijni: " STR "\n", ARG1); \ fflush(stdout); \ } #define DEBUG2(STR, ARG1, ARG2) \ if (_ffijni_debug) { \ printf("ffijni: " STR "\n", ARG1, ARG2); \ fflush(stdout); \ } #define DEBUG3(STR, ARG1, ARG2, ARG3) \ if (_ffijni_debug) { \ printf("ffijni: " STR "\n", ARG1, ARG2, ARG3); \ fflush(stdout); \ } #define DEBUG4(STR, ARG1, ARG2, ARG3, ARG4) \ if (_ffijni_debug) { \ printf("ffijni: " STR "\n", ARG1, ARG2, ARG3, ARG4); \ fflush(stdout); \ } #else /* def FFIJNI_DEBUG */ jboolean getDebugStatus() { return JNI_FALSE; } void setDebugStatus(jboolean _state) { fprintf(stderr, "ffijni: setDebugStatus(%s) was called, but this is not a debug build.\n" "ffijni: Use the DEBUG flag to enable a debug build.\n", _state ? "true" : "false"); } #define DEBUG(STR) #define DEBUG1(STR, ARG1) #define DEBUG2(STR, ARG1, ARG2) #define DEBUG3(STR, ARG1, ARG2, ARG3) #define DEBUG4(STR, ARG1, ARG2, ARG3, ARG4) #endif /* def FFIJNI_DEBUG */ #define XSTR(s) STR(s) #define STR(s) #s #define GLOBAL_REF(VMI, LOCAL, GLOBAL) \ jobject GLOBAL = (*VMI->env)->NewGlobalRef(VMI->env, LOCAL); \ (*VMI->env)->DeleteLocalRef(VMI->env, LOCAL); \ DEBUG2("-> new global ref from local: %p -> %p", LOCAL, GLOBAL); #ifdef FFIJNI_OSX_FRAMEWORK /* def FFIJNI_OSX_FRAMEWORK */ #define GET_CREATED_JAVA_VMS(a, b, c) JNI_GetCreatedJavaVMs(a, b, c) #define CREATE_JAVA_VM(a, b, c) JNI_CreateJavaVM(a, b, c) void setLibjvmPath(char* path) {} char* getLibjvmPath() { return "Linked with JavaVM Framework at compile time."; } char* getCompiledLibjvmPath() { return "Linked with JavaVM Framework at compile time."; } #else /* def FFIJNI_OSX_FRAMEWORK */ #ifndef FFIJNI_LIBJVM #error "Please specify -DFFIJNI_LIBJVM=." #endif #define GET_CREATED_JAVA_VMS(a, b, c) _GetCreatedJavaVMs(a, b, c) #define CREATE_JAVA_VM(a, b, c) _CreateJavaVM(a, b, c) static jint (*_GetCreatedJavaVMs) (JavaVM** vmBuf, jsize bufLen, jsize* nVMs) = NULL; static jint (*_CreateJavaVM) (JavaVM** pvm, void** penv, void* vmargs) = NULL; static char* _libjvm_path = NULL; void setLibjvmPath(char* path) { _libjvm_path = path; } char* getLibjvmPath() { return _libjvm_path; } char* getCompiledLibjvmPath() { return XSTR(FFIJNI_LIBJVM); } jint _load_JNI() { if (!_GetCreatedJavaVMs) { if (!_libjvm_path) { /* The location of libjvm can be overriden by the * environment variable FFIJNI_LIBJVM. */ _libjvm_path = getenv("FFIJNI_LIBJVM"); } if (!_libjvm_path) { /* If no such environment variable exists, use the built in * location (needs to be given at compile time) */ _libjvm_path = XSTR(FFIJNI_LIBJVM); } DEBUG1("Loading libjvm from %s.", _libjvm_path) #if defined(FFIJNI_LINUX) || defined(FFIJNI_MACOSX) /* On Linux and MacOSX use dlopen(...) to manually * load the dynamic library. */ void* libVM = dlopen(_libjvm_path, RTLD_LAZY); if (!libVM) { return -41; } _GetCreatedJavaVMs = (jint (*)(JavaVM**,jsize,jsize*)) dlsym(libVM, "JNI_GetCreatedJavaVMs"); _CreateJavaVM = (jint (*)(JavaVM**,void**,void*)) dlsym(libVM, "JNI_CreateJavaVM"); #else #if defined(FFIJNI_WINDOWS) /* On Windows use LoadLibrary(...) to manually * load the dynamic library. */ HINSTANCE hVM = LoadLibrary(_libjvm_path); if (!hVM) { return -41; } _GetCreatedJavaVMs = (jint (*)(JavaVM**,jsize,jsize*)) GetProcAddress(hVM, "JNI_GetCreatedJavaVMs"); _CreateJavaVM = (jint (*)(JavaVM**,void**,void*)) GetProcAddress(hVM, "JNI_CreateJavaVM"); #else #error "Unsupported platform." #endif #endif } return 0; } #endif /* def FFIJNI_OSX_FRAMEWORK */ void runCocoaMain() { #if defined(FFIJNI_MACOSX) && defined(FFIJNI_OSX_GUI) DEBUG("Retrieving NSApp...") void* clazz = objc_getClass("NSApplication"); void* app = objc_msgSend(clazz, sel_registerName("sharedApplication")); DEBUG1("-> %p", app) DEBUG("Starting cocoa main runloop") objc_msgSend(app, sel_registerName("run")); #endif } jobject JNICALL _callCallback(JNIEnv* env, jobject self, jlong func, jobject method, jobjectArray args) { WrappedFun funPtr = (WrappedFun) func; DEBUG3("Callback called (func: %d -> %p, method: %p)\m", func, funPtr, method) vm_t vmi; vmi.env = env; (*env)->GetJavaVM(env, &vmi.vm); return funPtr(&vmi, self, method, args); } void JNICALL _releaseCallback(JNIEnv* env, jobject self, jlong func) { WrappedFun funPtr = (WrappedFun) func; DEBUG2("Callback released (func: %d -> %p)", func, funPtr) freeFunPtr(funPtr); } void _loadHFunctionClass(JNIEnv* env) { /* boilerplate: * - find java.lang.ClassLoader * - get #getSystemClassLoader * - get #defineClass * - retrieve the systemClassLoader */ jclass clazz = (*env)->FindClass(env, "java/lang/ClassLoader"); DEBUG1("Loaded java.lang.ClassLoader: %p", clazz) jmethodID getSystemClassLoader = (*env)->GetStaticMethodID(env, clazz, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); DEBUG1("Got #getSystemClassLoader: %p", getSystemClassLoader) jmethodID defineClass = (*env)->GetMethodID(env, clazz, "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;"); DEBUG1("Got #defineClass: %p", defineClass) jobject systemClassLoader = (*env)->CallStaticObjectMethod(env, clazz, getSystemClassLoader); DEBUG1("Retrieved systemClassLoader: %p", systemClassLoader) /* define the class: * - create the string className ("HFunction") * - create the jbyteArray bytes from hFunctionClass (see hfunction.h) * - call #defineClass on systemClassLoader */ jstring className = (*env)->NewStringUTF(env, "HFunction"); DEBUG1("Allocated className: %p", className) jbyteArray classBytes = (*env)->NewByteArray(env, FFIJNI_HFUNCTION_LENGTH); (*env)->SetByteArrayRegion(env, classBytes, 0, FFIJNI_HFUNCTION_LENGTH, hFunctionClass); DEBUG1("Allocated classBytes: %p", classBytes) jclass hFunction = (*env)->CallObjectMethod(env, systemClassLoader, defineClass, className, classBytes, 0, FFIJNI_HFUNCTION_LENGTH); DEBUG1("Defined class HFunction: %p", hFunction) /* clean up */ (*env)->DeleteLocalRef(env, systemClassLoader); (*env)->DeleteLocalRef(env, className); (*env)->DeleteLocalRef(env, classBytes); (*env)->DeleteLocalRef(env, hFunction); } jboolean registerCallbacks(vm_t* vmi, jclass hFunction) { JNIEnv* env = vmi->env; JNINativeMethod method; jint result; /* register native call function */ DEBUG1("Registering call(...): %p", _callCallback) method.name = "call"; method.signature = "(JLjava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"; method.fnPtr = _callCallback; result = (*env)->RegisterNatives(env, hFunction, &method, 1); if (result < 0) { (*env)->ExceptionDescribe(env); return JNI_FALSE; } /* register native release function */ DEBUG1("Registering release(...): %p", _releaseCallback) method.name = "release"; method.signature = "(J)V"; method.fnPtr = _releaseCallback; result = (*env)->RegisterNatives(env, hFunction, &method, 1); if (result < 0) { (*env)->ExceptionDescribe(env); return JNI_FALSE; } return JNI_TRUE; } jint _get_vm(JavaVM** jvm, unsigned int argc, char** argv) { #ifndef FFIJNI_OSX_FRAMEWORK /* First things first: load the dynamic library * (this is not necessary if the library was linked with the * JavaVM framework on OSX, see OSX_FRAMEWORK flag / cabal file). */ if (_load_JNI() < 0) { DEBUG("Could not load libjvm") return -41; } #endif jsize numCreatedVMs = 0; GET_CREATED_JAVA_VMS(jvm, 1, &numCreatedVMs); if (numCreatedVMs > 0) { DEBUG("JVM already created") return 1; } JNIEnv* env; JavaVMInitArgs vm_args; vm_args.version = FFIJNI_VERSION; vm_args.ignoreUnrecognized = JNI_FALSE; /* Create a new Virtual Machine: */ JavaVMOption* options = calloc(argc, sizeof(JavaVMOption)); if (argc == 0) { vm_args.nOptions = 0; } else { for (int i = 0; i < argc; i++) { options[i].optionString = argv[i]; } vm_args.nOptions = argc; vm_args.options = options; } jint status; if ((status = CREATE_JAVA_VM(jvm, (void**) &env, &vm_args)) < 0) { /* Creation of Virtual Machine failed. */ free(options); return status; } /* Creation of Virtual Machine was successfull. */ free(options); _loadHFunctionClass(env); return 0; } vm_t* createVM () { return createVM2(0, NULL); } vm_t* createVM2 (unsigned int argc, char** argv) { JavaVM* jvm; jint status = _get_vm(&jvm, argc, argv); if (status < 0) { return NULL; } JNIEnv* env; vm_t* vmi = malloc(sizeof(vm_t)); vmi->attached = false; (*jvm)->GetEnv(jvm, (void**) &env, FFIJNI_VERSION); if (env == NULL) { DEBUG("Attach current thread") if ((*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL) < 0) { free(vmi); return NULL; } else { vmi->attached = true; } } vmi->env = env; vmi->vm = jvm; return vmi; } void destroyVM (vm_t* vmi) { if (vmi->attached) { DEBUG("Detach current thread") (*vmi->vm)->DetachCurrentThread(vmi->vm); } else { DEBUG("Destroy Java VM") (*vmi->vm)->DestroyJavaVM(vmi->vm); } free(vmi); } void persistVM (vm_t* vmi) { DEBUG("persistVM()") vmi->attached = true; } jclass findClass (vm_t* vmi, const char* className) { DEBUG1("findClass(%s)", className) jclass clazzLocal = (*vmi->env)->FindClass(vmi->env, className); GLOBAL_REF(vmi, clazzLocal, clazz) return clazz; } jobject newObject (vm_t* vmi, jclass clazz, jmethodID constructor, jvalue* args) { DEBUG2("newObject(%p, %p)", clazz, constructor) jobject objLocal = (*vmi->env)->NewObjectA(vmi->env, clazz, constructor, args); GLOBAL_REF(vmi, objLocal, obj) return obj; } jmethodID getConstructorID (vm_t* vmi, jclass clazz, const char* sig) { DEBUG1("getConstructorID(%s)", sig) jmethodID methodID = (*vmi->env)->GetMethodID(vmi->env, clazz, "", sig); DEBUG1("-> %p", methodID) return methodID; } jmethodID getStaticMethodID(vm_t* vmi, jclass clazz, const char* methodName, const char* sig) { DEBUG2("getStaticMethodID(%s, %s)", methodName, sig) jmethodID methodID = (*vmi->env)->GetStaticMethodID(vmi->env, clazz, methodName, sig); DEBUG1("-> %p", methodID) return methodID; } jmethodID getMethodID(vm_t* vmi, jclass clazz, const char* methodName, const char* sig) { DEBUG2("getMethodID(%s, %s)", methodName, sig) jmethodID methodID = (*vmi->env)->GetMethodID(vmi->env, clazz, methodName, sig); DEBUG1("-> %p", methodID) return methodID; } jfieldID getStaticFieldID(vm_t* vmi, jclass clazz, const char* fieldName, const char* sig) { DEBUG2("getStaticFieldID(%s, %s)", fieldName, sig) return (*vmi->env)->GetStaticFieldID(vmi->env, clazz, fieldName, sig); } jfieldID getFieldID(vm_t* vmi, jclass clazz, const char* fieldName, const char* sig) { DEBUG2("getFieldID(%s, %s)", fieldName, sig) return (*vmi->env)->GetFieldID(vmi->env, clazz, fieldName, sig); } void callStaticVoidMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticVoidMethod(%p, %p)", clazz, method) (*vmi->env)->CallStaticVoidMethodA(vmi->env, clazz, method, args); } jint callStaticIntMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticIntMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticIntMethodA(vmi->env, clazz, method, args); } jlong callStaticLongMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticLongMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticLongMethodA(vmi->env, clazz, method, args); } jshort callStaticShortMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticShortMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticShortMethodA(vmi->env, clazz, method, args); } jbyte callStaticByteMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticVoidMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticByteMethodA(vmi->env, clazz, method, args); } jfloat callStaticFloatMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticFloatMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticFloatMethodA(vmi->env, clazz, method, args); } jdouble callStaticDoubleMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticVoidMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticDoubleMethodA(vmi->env, clazz, method, args); } jboolean callStaticBooleanMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticBooleanMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticBooleanMethodA(vmi->env, clazz, method, args); } jchar callStaticCharMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticCharMethod(%p, %p)", clazz, method) return (*vmi->env)->CallStaticCharMethodA(vmi->env, clazz, method, args); } jobject callStaticObjectMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticObjectMethod(%p, %p)", clazz, method) jobject objLocal = (*vmi->env)->CallStaticObjectMethodA(vmi->env, clazz, method, args); if (objLocal) { GLOBAL_REF(vmi, objLocal, obj) return obj; } else { return NULL; } } const char* callStaticStringMethod (vm_t* vmi, jclass clazz, jmethodID method, jvalue* args) { DEBUG2("callStaticStringMethod(%p, %p)", clazz, method) jobject string = (*vmi->env)->CallStaticObjectMethodA(vmi->env, clazz, method, args); if (string) { return jStringToCString(vmi, string); } else { return NULL; } } void callVoidMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callVoidMethod(%p, %p)", object, method) (*vmi->env)->CallVoidMethodA(vmi->env, object, method, args); } jlong callLongMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callLongMethod(%p, %p)", object, method) return (*vmi->env)->CallLongMethodA(vmi->env, object, method, args); } jint callIntMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callIntMethod(%p, %p)", object, method) return (*vmi->env)->CallIntMethodA(vmi->env, object, method, args); } jshort callShortMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callShortMethod(%p, %p)", object, method) return (*vmi->env)->CallShortMethodA(vmi->env, object, method, args); } jbyte callByteMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callByteMethod(%p, %p)", object, method) return (*vmi->env)->CallByteMethodA(vmi->env, object, method, args); } jfloat callFloatMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callFloatMethod(%p, %p)", object, method) return (*vmi->env)->CallFloatMethodA(vmi->env, object, method, args); } jdouble callDoubleMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callDoubleMethod(%p, %p)", object, method) return (*vmi->env)->CallDoubleMethodA(vmi->env, object, method, args); } jboolean callBooleanMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callBooleanMethod(%p, %p)", object, method) return (*vmi->env)->CallBooleanMethodA(vmi->env, object, method, args); } jchar callCharMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callCharMethod(%p, %p)", object, method) return (*vmi->env)->CallCharMethodA(vmi->env, object, method, args); } jobject callObjectMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callObjectMethod(%p, %p)", object, method) jobject objLocal = (*vmi->env)->CallObjectMethodA(vmi->env, object, method, args); if (objLocal) { GLOBAL_REF(vmi, objLocal, obj) return obj; } else { return NULL; } } const char* callStringMethod (vm_t* vmi, jobject object, jmethodID method, jvalue* args) { DEBUG2("callStringMethod(%p, %p)", object, method) jobject string = (*vmi->env)->CallObjectMethodA(vmi->env, object, method, args); if (string) { return jStringToCString(vmi, string); } else { return NULL; } } jlong getStaticLongField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticLongField(vmi->env, clazz, field); } jint getStaticIntField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticIntField(vmi->env, clazz, field); } jshort getStaticShortField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticShortField(vmi->env, clazz, field); } jbyte getStaticByteField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticByteField(vmi->env, clazz, field); } jfloat getStaticFloatField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticFloatField(vmi->env, clazz, field); } jdouble getStaticDoubleField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticDoubleField(vmi->env, clazz, field); } jboolean getStaticBooleanField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticBooleanField(vmi->env, clazz, field); } jchar getStaticCharField (vm_t* vmi, jclass clazz, jfieldID field) { return (*vmi->env)->GetStaticCharField(vmi->env, clazz, field); } jobject getStaticObjectField (vm_t* vmi, jclass clazz, jfieldID field) { jobject objLocal = (*vmi->env)->GetStaticObjectField(vmi->env, clazz, field); GLOBAL_REF(vmi, objLocal, obj) return obj; } const char* getStaticStringField (vm_t* vmi, jclass clazz, jfieldID field) { jobject string = (*vmi->env)->GetStaticObjectField(vmi->env, clazz, field); return jStringToCString(vmi, string); } jlong getLongField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetLongField(vmi->env, object, field); } jint getIntField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetIntField(vmi->env, object, field); } jshort getShortField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetShortField(vmi->env, object, field); } jbyte getByteField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetByteField(vmi->env, object, field); } jfloat getFloatField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetFloatField(vmi->env, object, field); } jdouble getDoubleField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetDoubleField(vmi->env, object, field); } jboolean getBooleanField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetBooleanField(vmi->env, object, field); } jchar getCharField (vm_t* vmi, jobject object, jfieldID field) { return (*vmi->env)->GetCharField(vmi->env, object, field); } jobject getObjectField (vm_t* vmi, jobject object, jfieldID field) { jobject objLocal = (*vmi->env)->GetObjectField(vmi->env, object, field); GLOBAL_REF(vmi, objLocal, obj) return obj; } const char* getStringField (vm_t* vmi, jobject object, jfieldID field) { jobject string = (*vmi->env)->GetObjectField(vmi->env, object, field); return jStringToCString(vmi, string); } void setStaticLongField (vm_t* vmi, jclass clazz, jfieldID field, jlong value) { (*vmi->env)->SetStaticLongField(vmi->env, clazz, field, value); } void setStaticIntField (vm_t* vmi, jclass clazz, jfieldID field, jint value) { (*vmi->env)->SetStaticIntField(vmi->env, clazz, field, value); } void setStaticShortField (vm_t* vmi, jclass clazz, jfieldID field, jshort value) { (*vmi->env)->SetStaticShortField(vmi->env, clazz, field, value); } void setStaticByteField (vm_t* vmi, jclass clazz, jfieldID field, jbyte value) { (*vmi->env)->SetStaticByteField(vmi->env, clazz, field, value); } void setStaticFloatField (vm_t* vmi, jclass clazz, jfieldID field, jfloat value) { (*vmi->env)->SetStaticFloatField(vmi->env, clazz, field, value); } void setStaticDoubleField (vm_t* vmi, jclass clazz, jfieldID field, jdouble value) { (*vmi->env)->SetStaticDoubleField(vmi->env, clazz, field, value); } void setStaticBooleanField (vm_t* vmi, jclass clazz, jfieldID field, jboolean value) { (*vmi->env)->SetStaticBooleanField(vmi->env, clazz, field, value); } void setStaticCharField (vm_t* vmi, jclass clazz, jfieldID field, jchar value) { (*vmi->env)->SetStaticCharField(vmi->env, clazz, field, value); } void setStaticObjectField (vm_t* vmi, jclass clazz, jfieldID field, jobject value) { (*vmi->env)->SetStaticObjectField(vmi->env, clazz, field, value); } void setStaticStringField (vm_t* vmi, jclass clazz, jfieldID field, const char* value) { jstring string = (*vmi->env)->NewStringUTF(vmi->env, value); (*vmi->env)->SetStaticObjectField(vmi->env, clazz, field, string); } void setLongField (vm_t* vmi, jobject object, jfieldID field, jlong value) { (*vmi->env)->SetLongField(vmi->env, object, field, value); } void setIntField (vm_t* vmi, jobject object, jfieldID field, jint value) { (*vmi->env)->SetIntField(vmi->env, object, field, value); } void setShortField (vm_t* vmi, jobject object, jfieldID field, jshort value) { (*vmi->env)->SetShortField(vmi->env, object, field, value); } void setByteField (vm_t* vmi, jobject object, jfieldID field, jbyte value) { (*vmi->env)->SetByteField(vmi->env, object, field, value); } void setFloatField (vm_t* vmi, jobject object, jfieldID field, jfloat value) { (*vmi->env)->SetFloatField(vmi->env, object, field, value); } void setDoubleField (vm_t* vmi, jobject object, jfieldID field, jdouble value) { (*vmi->env)->SetDoubleField(vmi->env, object, field, value); } void setBooleanField (vm_t* vmi, jobject object, jfieldID field, jboolean value) { (*vmi->env)->SetBooleanField(vmi->env, object, field, value); } void setCharField (vm_t* vmi, jobject object, jfieldID field, jchar value) { (*vmi->env)->SetCharField(vmi->env, object, field, value); } void setObjectField (vm_t* vmi, jobject object, jfieldID field, jobject value) { (*vmi->env)->SetObjectField(vmi->env, object, field, value); } void setStringField (vm_t* vmi, jobject object, jfieldID field, const char* value) { jstring string = (*vmi->env)->NewStringUTF(vmi->env, value); (*vmi->env)->SetObjectField(vmi->env, object, field, string); } jvalue* newJValues (int size) { jvalue* arrayPointer = calloc (size, sizeof(jvalue)); return arrayPointer; } void setJValueBoolean (jvalue* array, int ix, jboolean val) { (array + ix)->z = val; } void setJValueInt (jvalue* array, int ix, jint val) { (array + ix)->i = val; } void setJValueLong (jvalue* array, int ix, jlong val) { (array + ix)->j = val; } void setJValueShort (jvalue* array, int ix, jshort val) { (array + ix)->s = val; } void setJValueByte (jvalue* array, int ix, jbyte val) { (array + ix)->b = val; } void setJValueFloat (jvalue* array, int ix, jfloat val) { (array + ix)->f = val; } void setJValueDouble (jvalue* array, int ix, jdouble val) { (array + ix)->d = val; } void setJValueChar (jvalue* array, int ix, jchar val) { (array + ix)->c = val; } void setJValueString (vm_t* vmi, jvalue* array, int ix, const char* string) { jstring jstr = (*vmi->env)->NewStringUTF(vmi->env, string); (array + ix)->l = jstr; } void setJValueObject (jvalue* array, int ix, jobject object) { (array + ix)->l = object; } jobject newJString (vm_t* vmi, const char* string) { DEBUG1("newJString(\"%s\")", string) return (*vmi->env)->NewStringUTF(vmi->env, string); } jint getArrayLength (vm_t* vmi, jobject array) { jint length = (*vmi->env)->GetArrayLength(vmi->env, array); DEBUG2("getArrayLength(%p) -> %i", array, length) return length; } jclass getObjectClass (vm_t* vmi, jobject object) { DEBUG1("getObjectClass(%p)", object) jobject objLocal = (*vmi->env)->GetObjectClass(vmi->env, object); GLOBAL_REF(vmi, objLocal, obj) return obj; } jboolean isInstanceOf (vm_t* vmi, jobject object, jclass clazz) { DEBUG2("isInstanceOf(%p, %p)", object, clazz) return (*vmi->env)->IsInstanceOf(vmi->env, object, clazz); } const jchar* charsFromJString (vm_t* vmi, jobject string) { DEBUG1("charsFromString(%p)", string) const jchar* chars = (*vmi->env)->GetStringChars(vmi->env, string, NULL); DEBUG1("-> %p", chars) return chars; } const char* bytesFromJString (vm_t* vmi, jobject string) { DEBUG1("bytesFromString(%p)", string) const char* bytes = (*vmi->env)->GetStringUTFChars(vmi->env, string, NULL); DEBUG1("-> %p", bytes) return bytes; } void releaseJChars (vm_t* vmi, jobject string, const jchar* chars) { DEBUG2("releaseJChars(%p, %p)", string, chars) (*vmi->env)->ReleaseStringChars(vmi->env, string, chars); } void releaseJBytes (vm_t* vmi, jobject string, const char* bytes) { DEBUG2("releaseJBytes(%p, %p)", string, bytes) (*vmi->env)->ReleaseStringUTFChars(vmi->env, string, bytes); } const char* jStringToCString (vm_t* vmi, jobject string) { if (string == NULL) { return NULL; } jsize length = (*vmi->env)->GetStringUTFLength(vmi->env, string); const char* bytes = (*vmi->env)->GetStringUTFChars(vmi->env, string, NULL); char* cstring = malloc(length + 1); memcpy(cstring, bytes, length); cstring[length] = '\0'; (*vmi->env)->ReleaseStringUTFChars(vmi->env, string, bytes); return cstring; } jboolean exceptionCheck (vm_t* vmi) { return (*vmi->env)->ExceptionCheck(vmi->env); } void exceptionClear (vm_t* vmi) { (*vmi->env)->ExceptionClear(vmi->env); } void exceptionDescribe (vm_t* vmi) { (*vmi->env)->ExceptionDescribe(vmi->env); } jthrowable exceptionOccurred (vm_t* vmi) { jthrowable exc = (*vmi->env)->ExceptionOccurred(vmi->env); DEBUG1("exceptionOccurred() -> %p", exc) return exc; } jthrowable exceptionOccurredClear (vm_t* vmi) { jthrowable excLocal = (*vmi->env)->ExceptionOccurred(vmi->env); DEBUG1("exceptionOccurredClear() -> %p", excLocal) if (excLocal) { (*vmi->env)->ExceptionClear(vmi->env); GLOBAL_REF(vmi, excLocal, exc) return exc; } else { return NULL; } } void releaseJObjectRef (vm_t* vmi, jobject obj) { (*vmi->env)->DeleteGlobalRef(vmi->env, obj); } void releaseJClassRef (vm_t* vmi, jclass obj) { (*vmi->env)->DeleteGlobalRef(vmi->env, obj); } void releaseJThrowableRef (vm_t* vmi, jthrowable obj) { (*vmi->env)->DeleteGlobalRef(vmi->env, obj); } void release (jobject obj) { JavaVM* jvm; jsize numCreatedVMs = 0; GET_CREATED_JAVA_VMS(&jvm, 1, &numCreatedVMs); if (numCreatedVMs == 1) { JNIEnv* env; if ((*jvm)->GetEnv(jvm, (void**) &env, FFIJNI_VERSION) == JNI_OK) { DEBUG1("release(%p)\n", (void*) obj) (*env)->DeleteGlobalRef(env, obj); } } else if (numCreatedVMs > 1) { fprintf(stderr, "THE IMPOSSIBLE HAPPENED - This should not have happend.\n" "Somehow more than one JVM was created.\n" "Please report this as a bug.\n"); fflush(stderr); } else { DEBUG1("release(%p) - already shut down", (void*) obj) /* This is not an error, since the virtual machine * has already been teared down and no objects are * alive anymore - therefor nothing has to be freed * anymore (nor can it be). */ } }