/* * Class: com_kenai_jffi_Foreign * Method: dlopen * Signature: (Ljava/lang/String;I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlopen(JNIEnv* env, jobject self, jstring jPath, jint jFlags) { #ifdef _WIN32 wchar_t path[PATH_MAX]; getWideString(env, path, jstr, sizeof(path) / sizeof(path[0])); return p2j(LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)); #else char path_[PATH_MAX]; const char* path = NULL; // Handle dlopen(NULL, flags); int flags = 0; #define F(x) (jFlags & com_kenai_jffi_Foreign_RTLD_##x) != 0 ? RTLD_##x : 0; flags |= F(LAZY); flags |= F(GLOBAL); flags |= F(LOCAL); flags |= F(NOW); #undef F #ifdef _AIX flags |= RTLD_MEMBER; // Needed for AIX #endif if (jPath != NULL) { path = path_; getMultibyteString(env, path_, jPath, sizeof(path_)); } return p2j(dl_open(path, flags)); #endif }
JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getJavaVM(JNIEnv *env, jobject self) { JavaVM* vm; (*env)->GetJavaVM(env, &vm); return p2j(vm); }
/* * Class: com_kenai_jffi_Foreign * Method: dlopen * Signature: (Ljava/lang/String;I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlopen(JNIEnv* env, jobject self, jstring jPath, jint jFlags) { #ifdef _WIN32 if (jPath == NULL) { return p2j(GetModuleHandle(NULL)); } else { wchar_t path[PATH_MAX]; DWORD dwFlags; getWideString(env, path, jPath, sizeof(path) / sizeof(path[0])); dwFlags = PathIsRelativeW(path) ? 0 : LOAD_WITH_ALTERED_SEARCH_PATH; return p2j(LoadLibraryExW(path, NULL, dwFlags)); } #else char path_[PATH_MAX]; const char* path = NULL; // Handle dlopen(NULL, flags); void* handle = NULL; int flags = 0; #define F(x) (jFlags & com_kenai_jffi_Foreign_RTLD_##x) != 0 ? RTLD_##x : 0; flags |= F(LAZY); flags |= F(GLOBAL); flags |= F(LOCAL); flags |= F(NOW); #undef F #ifdef _AIX flags |= RTLD_MEMBER; // Needed for AIX #endif if (jPath != NULL) { path = path_; getMultibyteString(env, path_, jPath, sizeof(path_)); } handle = dl_open(path, flags); if (handle == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(handle); #endif }
JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlsym(JNIEnv* env, jclass cls, jlong handle, jstring jstr) { char sym[1024]; getMultibyteString(env, sym, jstr, sizeof(sym)); #ifndef _WIN32 dlerror(); // clear any errors #endif return p2j(dl_sym(j2p(handle), sym)); }
/* * Class: com_kenai_jffi_Foreign * Method: VirtualAlloc * Signature: (JIII)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_VirtualAlloc(JNIEnv *env, jobject self, jlong addr, jint size, jint flags, jint prot) { void* ptr = VirtualAlloc(j2p(addr), size, flags, prot); if (unlikely(ptr == NULL)) { jffi_save_errno(); return 0; } return p2j(ptr); }
/* * Class: com_kenai_jffi_Foreign * Method: mmap * Signature: (JJIIIJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_mmap(JNIEnv *env, jobject self, jlong addr, jlong len, jint prot, jint flags, jint fd, jlong off) { caddr_t result; result = mmap(j2p(addr), len, PROT(prot), FLAGS(flags), fd, off); if (unlikely(result == (caddr_t) -1)) { jffi_save_errno(); return -1; } return p2j(result); }
/* * Class: com_kenai_jffi_Foreign * Method: closureMagazineGet * Signature: (JLjava/lang/Object;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_closureMagazineGet(JNIEnv *env, jobject self, jlong magAddress, jobject closureProxy) { Magazine* magazine = (Magazine *) j2p(magAddress); if (magazine->nextclosure < magazine->nclosures) { Closure* closure = &magazine->closures[magazine->nextclosure]; closure->javaObject = (*env)->NewGlobalRef(env, closureProxy); if (closure->javaObject == NULL) { throwException(env, IllegalArgument, "could not obtain reference to java object"); return 0L; } magazine->nextclosure++; return p2j(closure); } return 0L; }
JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlsym(JNIEnv* env, jclass cls, jlong handle, jstring jstr) { char sym[1024]; void* addr; getMultibyteString(env, sym, jstr, sizeof(sym)); #ifndef _WIN32 dlerror(); // clear any errors #endif addr = dl_sym(j2p(handle), sym); if (addr == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(addr); }
/* * Class: com_kenai_jffi_Foreign * Method: newStruct * Signature: ([J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newStruct(JNIEnv* env, jobject self, jlongArray typeArray, jboolean isUnion) { ffi_type* s = NULL; int fieldCount; jlong* fieldTypes; int i; if (typeArray == NULL) { throwException(env, NullPointer, "types array cannot be null"); return 0L; } fieldCount = (*env)->GetArrayLength(env, typeArray); if (fieldCount < 1) { throwException(env, IllegalArgument, "No fields specified"); return 0L; } s = calloc(1, sizeof(*s)); if (s == NULL) { return 0L; } // // Need to terminate the list of field types with a NULL, so allocate 1 extra // s->elements = calloc(fieldCount + 1, sizeof(ffi_type *)); if (s->elements == NULL) { goto error; } // Copy out all the field descriptors fieldTypes = alloca(fieldCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, typeArray, 0, fieldCount, fieldTypes); s->type = FFI_TYPE_STRUCT; s->size = 0; s->alignment = 0; for (i = 0; i < fieldCount; ++i) { ffi_type* elem = (ffi_type *) j2p(fieldTypes[i]); if (elem == NULL) { throwException(env, IllegalArgument, "Type for field %d is NULL", i); goto error; } if (elem->size == 0) { throwException(env, IllegalArgument, "Type for field %d has size 0", i); goto error; } s->elements[i] = elem; if (!isUnion) { s->size = ALIGN(s->size, elem->alignment) + elem->size; } else { s->size = MAX(s->size, elem->size); } s->alignment = MAX(s->alignment, elem->alignment); //printf("s->size=%d s->alignment=%d\n", s->size, s->alignment); } if (s->size == 0) { throwException(env, Runtime, "Struct size is zero"); goto error; } // Include tail padding s->size = ALIGN(s->size, s->alignment); return p2j(s); error: if (s != NULL) { if (s->elements != NULL) { free(s->elements); } free(s); } return 0L; }
JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newClosureMagazine(JNIEnv *env, jobject self, jlong ctxAddress, jobject closureMethod, jboolean callWithPrimitiveParameters) { CallContext* ctx = (CallContext *) j2p(ctxAddress); Closure* list = NULL; Magazine* magazine = NULL; caddr_t code = NULL; char errmsg[256]; int i; int trampolineSize, pageSize, nclosures; trampolineSize = roundup(sizeof(ffi_closure), 8); pageSize = jffi_getPageSize(); nclosures = pageSize / trampolineSize; magazine = calloc(1, sizeof(*magazine)); list = calloc(nclosures, sizeof(*list)); code = jffi_allocatePages(1); if (magazine == NULL || list == NULL || code == NULL) { snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno)); goto error; } // Thread all the closure handles onto a list, and init each one for (i = 0; i < nclosures; ++i) { Closure* closure = &list[i]; closure->magazine = magazine; closure->code = (code + (i * trampolineSize)); if (!closure_prep(&ctx->cif, closure->code, closure, errmsg, sizeof(errmsg))) { goto error; } } if (!jffi_makePagesExecutable(code, 1)) { snprintf(errmsg, sizeof(errmsg), "failed to make page executable. errno=%d (%s)", errno, strerror(errno)); goto error; } magazine->methodID = (*env)->FromReflectedMethod(env, closureMethod); if (magazine->methodID == NULL) { throwException(env, IllegalArgument, "could not obtain reference to closure method"); goto error; } /* Track the allocated page + Closure memory area */ magazine->closures = list; magazine->nextclosure = 0; magazine->nclosures = nclosures; magazine->code = code; magazine->callWithPrimitiveParameters = callWithPrimitiveParameters; (*env)->GetJavaVM(env, &magazine->jvm); return p2j(magazine); error: free(list); free(magazine); if (code != NULL) { jffi_freePages(code, 1); } throwException(env, Runtime, errmsg); return 0L; }
static void closure_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) { Closure* closure = (Closure *) user_data; JNIEnv* env; int i; bool detach; #if FAULT_PROTECT_ENABLED ThreadData* td = thread_data_get(); FaultData* fdp; #endif closure_begin(closure, &env, &detach); #if FAULT_PROTECT_ENABLED fdp = td->fault_data; td->fault_data = NULL; #endif if (closure->magazine->callWithPrimitiveParameters) { // allocate one more than the parameter count (for the struct return value) jvalue* jparams = alloca((cif->nargs + 1) * sizeof(jvalue)); for (i = 0; i < (int) cif->nargs; i++) { jvalue* vp = &jparams[i]; vp->j = 0LL; // zero out any bits not filled below switch (cif->arg_types[i]->type) { case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: vp->b = *(jbyte *) parameters[i]; break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: vp->s = *(jshort *) parameters[i]; break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_INT: vp->i = *(jint *) parameters[i]; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: vp->j = *(jlong *) parameters[i]; break; case FFI_TYPE_FLOAT: vp->i = *(jfloat *) parameters[i]; break; case FFI_TYPE_DOUBLE: vp->i = *(jdouble *) parameters[i]; break; case FFI_TYPE_POINTER: if (cif->arg_types[i]->size == 4) { vp->i = (uintptr_t) *(void **) parameters[i]; } else { vp->j = p2j(*(void **) parameters[i]); } break; case FFI_TYPE_STRUCT: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif vp->j = p2j(parameters[i]); break; default: memset(vp, 0, sizeof(*vp)); break; } } switch (cif->rtype->type) { case FFI_TYPE_VOID: (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); *((ffi_sarg *) retval) = 0; break; case FFI_TYPE_SINT8: *((ffi_sarg *) retval) = (*env)->CallByteMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT16: *((ffi_sarg *) retval) = (*env)->CallShortMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT32: case FFI_TYPE_INT: *((ffi_sarg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT8: *((ffi_arg *) retval) = (*env)->CallByteMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT16: *((ffi_arg *) retval) = (*env)->CallShortMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT32: *((ffi_arg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT64: *((int64_t *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT64: *((uint64_t *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_POINTER: if (cif->rtype->size == 4) { *((ffi_arg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } else { *((ffi_arg *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } break; case FFI_TYPE_FLOAT: *((float *) retval) = (*env)->CallFloatMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_DOUBLE: *((double *) retval) = (*env)->CallDoubleMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_STRUCT: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif // stuff the retval in as the last parameter passed to the java method jparams[cif->nargs].j = p2j(retval); (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; default: memset(retval, 0, cif->rtype->size); } } else { jvalue jparams[2]; jparams[0].j = p2j(retval); jparams[1].j = p2j(parameters); // // Do the actual invoke - the java code will unmarshal the arguments // (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } if ((*env)->ExceptionCheck(env)) { memset(retval, 0, cif->rtype->size); } #if FAULT_PROTECT_ENABLED td->fault_data = fdp; #endif closure_end(closure, env, detach); }
/* * Class: com_kenai_jffi_Foreign * Method: lookupType * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_lookupBuiltinType(JNIEnv* env, jobject self, jint type) { return p2j(typeToFFI(type)); }