[jffi-next] 37/49: Add native support for boolean, char arrays, handle pinned arrays properly, and add more exception checking where needed.
Tim Potter
tpot-guest at moszumanska.debian.org
Wed Mar 4 04:51:15 UTC 2015
This is an automated email from the git hooks/post-receive script.
tpot-guest pushed a commit to annotated tag upstream/1.0.10
in repository jffi-next.
commit a61b1fc42aa70add2ded067a36befdeabb98fd5e
Author: Wayne Meissner <wmeissner at gmail.com>
Date: Tue Apr 26 19:31:35 2011 +1000
Add native support for boolean, char arrays, handle pinned arrays properly, and add more exception checking where needed.
---
jni/jffi/Array.c | 186 +++++++++++++++++++++++++++++++++++++++++-------------
jni/jffi/Array.h | 22 +++++++
jni/jffi/Invoke.c | 77 +++++++++++++++++-----
3 files changed, 226 insertions(+), 59 deletions(-)
diff --git a/jni/jffi/Array.c b/jni/jffi/Array.c
index 7151b87..6d572ca 100644
--- a/jni/jffi/Array.c
+++ b/jni/jffi/Array.c
@@ -42,54 +42,42 @@
#include "Array.h"
-#define ARRAY_NULTERMINATE com_kenai_jffi_ObjectBuffer_ZERO_TERMINATE
-#define ARRAY_IN com_kenai_jffi_ObjectBuffer_IN
-#define ARRAY_OUT com_kenai_jffi_ObjectBuffer_OUT
-#define ARRAY_PINNED com_kenai_jffi_ObjectBuffer_PINNED
-#define ARRAY_CLEAR com_kenai_jffi_ObjectBuffer_CLEAR
#define ARGPRIM_MASK com_kenai_jffi_ObjectBuffer_PRIM_MASK
#define ARGTYPE_MASK com_kenai_jffi_ObjectBuffer_TYPE_MASK
#define ARGTYPE_SHIFT com_kenai_jffi_ObjectBuffer_TYPE_SHIFT
#define ARGFLAGS_MASK com_kenai_jffi_ObjectBuffer_FLAGS_MASK
-#define RELEASE(JTYPE, NTYPE) \
-static void release##JTYPE##ArrayHeap(JNIEnv *env, Array *array) \
-{ \
- (*env)->Set##JTYPE##ArrayRegion(env, array->array, array->offset, array->length, \
- (NTYPE *) array->elems); \
- free(array->elems); \
-} \
-static void free##JTYPE##Array(JNIEnv *env, Array *array) \
-{ \
- free(array->elems); \
-} \
-static void release##JTYPE##ArrayBuffer(JNIEnv *env, Array *array) \
-{ \
- (*env)->Set##JTYPE##ArrayRegion(env, array->array, array->offset, array->length, \
- (NTYPE *) array->elems); \
+static void
+releaseHeapArray(JNIEnv* env, Array* array)
+{
+ free(array->elems);
}
-RELEASE(Byte, jbyte);
-RELEASE(Short, jshort);
-RELEASE(Int, jint);
-RELEASE(Long, jlong);
-RELEASE(Float, jfloat);
-RELEASE(Double, jdouble);
-
#define isOut(flags) (((flags) & (ARRAY_IN | ARRAY_OUT)) != ARRAY_IN)
#define isIn(flags) (((flags) & (ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT)
#define COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array) do { \
if (isIn(flags)) { \
(*env)->Get##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) array->elems); \
+ if (unlikely((*env)->ExceptionCheck(env) != JNI_FALSE)) return NULL; \
} else if (unlikely((flags & ARRAY_CLEAR) != 0)) { \
memset(array->elems, 0, length * sizeof(NTYPE)); \
} \
} while (0)
+#define SET_COPYOUT(JTYPE, array, flags) \
+ (array)->copyout = isOut(flags) \
+ ? (void (*)(JNIEnv*, jobject, jsize, jsize, const void *))(*env)->Set##JTYPE##ArrayRegion \
+ : NULL
+
+#define SET_COPYIN(JTYPE, array, flags) \
+ (array)->copyin = isIn(flags) \
+ ? (void (*)(JNIEnv*, jobject, jsize, jsize, void *))(*env)->Get##JTYPE##ArrayRegion \
+ : NULL
+
#define GET_ARRAY_BUFFER(JTYPE, NTYPE, flags, obj, offset, length, array) do { \
COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \
- (array)->release = isOut(flags) ? release##JTYPE##ArrayBuffer : NULL; \
+ SET_COPYOUT(JTYPE, array, flags); \
} while (0)
#define GET_ARRAY_HEAP(JTYPE, NTYPE, flags, obj, offset, length, array) do { \
@@ -100,50 +88,67 @@ RELEASE(Double, jdouble);
return NULL; \
} \
COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \
- (array)->release = isOut(flags) ? release##JTYPE##ArrayHeap : free##JTYPE##Array; \
+ SET_COPYOUT(JTYPE, array, flags); \
} while(0)
void*
-jffi_getArrayHeap(JNIEnv* env, jobject buf, jsize offset, jsize length, int paramType,
+jffi_getArrayHeap(JNIEnv* env, jobject buf, jsize offset, jsize length, int type,
Array* array)
{
array->array = buf;
array->offset = offset;
array->length = length;
+ array->type = type;
+ array->copyin = NULL;
+ array->copyout = NULL;
+ array->release = releaseHeapArray;
/*
* Byte arrays are used for struct backing in both jaffl and jruby ffi, so
* are the most likely path.
*/
- if (likely((paramType & ARGPRIM_MASK) == com_kenai_jffi_ObjectBuffer_BYTE)) {
- GET_ARRAY_HEAP(Byte, jbyte, paramType, buf, offset, length, array);
+ if (likely((type & ARGPRIM_MASK) == com_kenai_jffi_ObjectBuffer_BYTE)) {
+ GET_ARRAY_HEAP(Byte, jbyte, type, buf, offset, length, array);
// If the array was really a string, nul terminate it
- if ((paramType & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) {
+ if ((type & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) {
*(((char *) array->elems) + length) = '\0';
}
} else {
- switch (paramType & ARGPRIM_MASK) {
+ switch (type & ARGPRIM_MASK) {
case com_kenai_jffi_ObjectBuffer_SHORT:
- GET_ARRAY_HEAP(Short, jshort, paramType, buf, offset, length, array);
+ GET_ARRAY_HEAP(Short, jshort, type, buf, offset, length, array);
break;
+
case com_kenai_jffi_ObjectBuffer_INT:
- GET_ARRAY_HEAP(Int, jint, paramType, buf, offset, length, array);
+ GET_ARRAY_HEAP(Int, jint, type, buf, offset, length, array);
break;
+
case com_kenai_jffi_ObjectBuffer_LONG:
- GET_ARRAY_HEAP(Long, jlong, paramType, buf, offset, length, array);
+ GET_ARRAY_HEAP(Long, jlong, type, buf, offset, length, array);
break;
+
case com_kenai_jffi_ObjectBuffer_FLOAT:
- GET_ARRAY_HEAP(Float, jfloat, paramType, buf, offset, length, array);
+ GET_ARRAY_HEAP(Float, jfloat, type, buf, offset, length, array);
break;
+
case com_kenai_jffi_ObjectBuffer_DOUBLE:
- GET_ARRAY_HEAP(Double, jdouble, paramType, buf, offset, length, array);
+ GET_ARRAY_HEAP(Double, jdouble, type, buf, offset, length, array);
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_BOOLEAN:
+ GET_ARRAY_HEAP(Boolean, jboolean, type, buf, offset, length, array);
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_CHAR:
+ GET_ARRAY_HEAP(Char, jchar, type, buf, offset, length, array);
break;
+
default:
- throwException(env, IllegalArgument, "Invalid array type: %#x\n", paramType);
+ throwException(env, IllegalArgument, "invalid array type: %#x\n", type);
return NULL;
}
}
-
+
return array->elems;
}
@@ -154,6 +159,10 @@ jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type
array->elems = buffer;
array->offset = offset;
array->length = length;
+ array->type = type;
+ array->release = NULL;
+ array->copyin = NULL;
+ array->copyout = NULL;
switch (type & ARGPRIM_MASK) {
case com_kenai_jffi_ObjectBuffer_BYTE:
@@ -183,6 +192,14 @@ jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type
case com_kenai_jffi_ObjectBuffer_DOUBLE:
GET_ARRAY_BUFFER(Double, jdouble, type, buf, offset, length, array);
break;
+
+ case com_kenai_jffi_ObjectBuffer_BOOLEAN:
+ GET_ARRAY_BUFFER(Boolean, jboolean, type, buf, offset, length, array);
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_CHAR:
+ GET_ARRAY_BUFFER(Char, jchar, type, buf, offset, length, array);
+ break;
default:
throwException(env, IllegalArgument, "Invalid array type: %#x\n", type);
return NULL;
@@ -225,19 +242,100 @@ jffi_releaseCriticalArray(JNIEnv* env, Array *array)
void*
-jffi_getArrayCritical(JNIEnv* env, jobject buf, jsize offset, jsize length, int paramType, struct Array* array)
+jffi_getArrayCritical(JNIEnv* env, jobject buf, jsize offset, jsize length, int type, struct Array* array)
{
array->array = buf;
array->offset = offset;
array->length = length;
+ array->type = type;
+ array->copyin = NULL;
+ array->copyout = NULL;
+ array->release = jffi_releaseCriticalArray;
array->elems = (*env)->GetPrimitiveArrayCritical(env, array->array, NULL);
if (unlikely(array->elems == NULL)) {
- throwException(env, NullPointer, "could not access array");
+ if (!(*env)->ExceptionCheck(env)) {
+ throwException(env, NullPointer, "failed to pin native array");
+ }
return NULL;
}
- array->release = jffi_releaseCriticalArray;
return (char *) array->elems + offset;
}
+void
+jffi_releaseArrays(JNIEnv *env, Array* arrays, int arrayCount)
+{
+ int aryIdx;
+ for (aryIdx = arrayCount - 1; aryIdx >= 0; aryIdx--) {
+
+ Array* array = &arrays[aryIdx];
+ if (IS_OUT_ARRAY(array->type) && array->copyout != NULL) {
+ if ((*env)->ExceptionCheck(env) == JNI_FALSE) {
+ (*array->copyout)(env, array->array, array->offset, array->length, array->elems);
+ }
+ }
+
+ if (unlikely(array->release != NULL)) {
+ (*array->release)(env, array);
+ }
+ }
+}
+
+#define INIT_ARRAY(array, JTYPE, componentSize_) do { \
+ array->copyin = (void (*)(JNIEnv*, jobject, jsize, jsize, void *))(*env)->Get##JTYPE##ArrayRegion; \
+ array->copyout = (void (*)(JNIEnv*, jobject, jsize, jsize, const void *))(*env)->Set##JTYPE##ArrayRegion; \
+ array->bytesize = componentSize_ * array->length; \
+ if ((array->type & ARRAY_NULTERMINATE) != 0) array->bytesize += componentSize_; \
+} while(0)
+
+bool
+jffi_initArray(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array)
+{
+ array->array = buf;
+ array->offset = offset;
+ array->length = length;
+ array->type = type;
+ array->release = NULL;
+ array->elems = NULL;
+
+ switch (type & ARGPRIM_MASK) {
+ case com_kenai_jffi_ObjectBuffer_BYTE:
+ INIT_ARRAY(array, Byte, sizeof(jbyte));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_SHORT:
+ INIT_ARRAY(array, Short, sizeof(jshort));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_INT:
+ INIT_ARRAY(array, Int, sizeof(jint));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_LONG:
+ INIT_ARRAY(array, Long, sizeof(jlong));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_FLOAT:
+ INIT_ARRAY(array, Float, sizeof(jfloat));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_DOUBLE:
+ INIT_ARRAY(array, Double, sizeof(jdouble));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_BOOLEAN:
+ INIT_ARRAY(array, Boolean, sizeof(jboolean));
+ break;
+
+ case com_kenai_jffi_ObjectBuffer_CHAR:
+ INIT_ARRAY(array, Char, sizeof(jchar));
+ break;
+
+ default:
+ throwException(env, IllegalArgument, "invalid array type: %#x\n", type);
+ return false;
+ }
+
+ return true;
+}
diff --git a/jni/jffi/Array.h b/jni/jffi/Array.h
index e07fe71..494fc05 100644
--- a/jni/jffi/Array.h
+++ b/jni/jffi/Array.h
@@ -37,22 +37,44 @@
// WARNING! Do not change the layout of this struct, it may be used from assembler
//
typedef struct Array {
+ void (*copyin)(JNIEnv* env, jobject array, jsize start, jsize len, void *buf);
+ void (*copyout)(JNIEnv* env, jobject array, jsize start, jsize len, const void *buf);
void (*release)(JNIEnv *env, struct Array *);
jobject array;
void* elems;
int offset;
int length;
+ int type;
+ int bytesize; // total size of array in bytes
} Array;
+extern bool jffi_getInitArray(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array);
extern void* jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array, void* buffer);
extern void* jffi_getArrayHeap(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array);
extern void* jffi_getArrayCritical(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array);
extern int jffi_arraySize(int length, int type);
+extern void jffi_releaseArrays(JNIEnv* env, Array* arrays, int arrayCount);
#include "com_kenai_jffi_ObjectBuffer.h"
#define OBJ_INDEX_MASK com_kenai_jffi_ObjectBuffer_INDEX_MASK
#define OBJ_INDEX_SHIFT com_kenai_jffi_ObjectBuffer_INDEX_SHIFT
+#define ARRAY_NULTERMINATE com_kenai_jffi_ObjectBuffer_ZERO_TERMINATE
+#define ARRAY_IN com_kenai_jffi_ObjectBuffer_IN
+#define ARRAY_OUT com_kenai_jffi_ObjectBuffer_OUT
+#define ARRAY_PINNED com_kenai_jffi_ObjectBuffer_PINNED
+#define ARRAY_CLEAR com_kenai_jffi_ObjectBuffer_CLEAR
+
+#define IS_PINNED_ARRAY(flags) \
+ (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED)) == (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED))
+
+#define IS_UNPINNED_ARRAY(flags) \
+ (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED)) == com_kenai_jffi_ObjectBuffer_ARRAY)
+
+#define IS_OUT_ARRAY(flags) (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN | ARRAY_OUT)) != (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN))
+#define IS_IN_ARRAY(flags) (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN | ARRAY_OUT)) != (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN))
+
+#define RELEASE_ARRAYS(env, arrays, arrayCount) jffi_releaseArrays(env, arrays, arrayCount)
#endif /* jffi_Array_h */
diff --git a/jni/jffi/Invoke.c b/jni/jffi/Invoke.c
index e49c399..17968d4 100644
--- a/jni/jffi/Invoke.c
+++ b/jni/jffi/Invoke.c
@@ -52,6 +52,14 @@
#define MAX_STACK_ARRAY (1024)
+
+typedef struct Pinned {
+ jobject object;
+ jsize offset;
+ jsize length;
+ int type;
+} Pinned;
+
#ifdef USE_RAW
static void
invokeArray(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, void* returnBuffer)
@@ -220,9 +228,11 @@ invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer,
jbyte *tmpBuffer = NULL;
void **ffiArgs = NULL;
Array *arrays = NULL;
- unsigned int i, arrayCount = 0, paramBytes = 0;
+ Pinned *pinned = NULL;
+ unsigned int i, arrayCount = 0, pinnedCount = 0, paramBytes = 0;
arrays = alloca(objectCount * sizeof(Array));
+ pinned = alloca(objectCount * sizeof(Pinned));
#if defined(USE_RAW)
paramBytes = ctx->rawParameterSize;
@@ -255,32 +265,45 @@ invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer,
if (unlikely(object == NULL)) {
throwException(env, NullPointer, "null object for parameter %d", idx);
goto cleanup;
+ }
- } else if (unlikely((type & com_kenai_jffi_ObjectBuffer_PINNED) != 0)) {
-
- ptr = jffi_getArrayCritical(env, object, offset, length, type, &arrays[arrayCount]);
- if (unlikely(ptr == NULL)) {
- goto cleanup;
- }
- } else if (true && likely(length < MAX_STACK_ARRAY)) {
+ if (unlikely((type & com_kenai_jffi_ObjectBuffer_PINNED) != 0)) {
+
+ // Record the pinned array, but the actual pinning will be done just before the ffi_call
+ Pinned* p = &pinned[pinnedCount++];
+ p->object = object;
+ p->offset = offset;
+ p->length = length;
+ p->type = type;
+ ptr = NULL;
+
+ } else if (likely(length < MAX_STACK_ARRAY)) {
ptr = alloca(jffi_arraySize(length + 1, type));
if (unlikely(jffi_getArrayBuffer(env, object, offset, length, type,
&arrays[arrayCount], ptr) == NULL)) {
goto cleanup;
}
+ ++arrayCount;
+
} else {
ptr = jffi_getArrayHeap(env, object, offset, length, type, &arrays[arrayCount]);
if (unlikely(ptr == NULL)) {
goto cleanup;
}
+ ++arrayCount;
}
- ++arrayCount;
+
break;
case com_kenai_jffi_ObjectBuffer_BUFFER:
+ if (unlikely(object == NULL)) {
+ throwException(env, NullPointer, "null object for parameter %d", idx);
+ goto cleanup;
+ }
+
ptr = (*env)->GetDirectBufferAddress(env, object);
if (unlikely(ptr == NULL)) {
throwException(env, NullPointer, "Could not get direct Buffer address");
@@ -320,6 +343,35 @@ invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer,
}
#endif
}
+
+ //
+ // Pin all the arrays just before calling the native function.
+ //
+ // Although hotspot allows it, other JVMs do not allow JNI operations
+ // once any array has been pinned, so pinning must be done last, just before
+ // the native function is called.
+ //
+ for (i = 0; i < pinnedCount; i++) {
+ Pinned* p = &pinned[i];
+ Array* ary = &arrays[arrayCount];
+ int idx = (p->type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT;
+
+ void* ptr = jffi_getArrayCritical(env, p->object, p->offset, p->length, p->type, &arrays[arrayCount]);
+ if (unlikely(ptr == NULL)) {
+ goto cleanup;
+ }
+#if defined(USE_RAW)
+ *((void **)(tmpBuffer + ctx->rawParamOffsets[idx])) = ptr;
+#else
+ if (unlikely(ctx->cif.arg_types[idx]->type == FFI_TYPE_STRUCT)) {
+ ffiArgs[idx] = ptr;
+ } else {
+ *((void **) ffiArgs[idx]) = ptr;
+ }
+#endif
+ ++arrayCount;
+ }
+
#if defined(USE_RAW)
//
// Special case for struct return values - unroll into a ptr array and
@@ -340,12 +392,7 @@ invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer,
SAVE_ERRNO(ctx);
cleanup:
/* Release any array backing memory */
- for (i = 0; i < arrayCount; ++i) {
- if (arrays[i].release != NULL) {
- //printf("releasing array=%p\n", arrays[i].elems);
- (*arrays[i].release)(env, &arrays[i]);
- }
- }
+ RELEASE_ARRAYS(env, arrays, arrayCount);
}
static void
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jffi-next.git
More information about the pkg-java-commits
mailing list