[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