void* jffi_getArray(JNIEnv* env, jobject buf, jsize offset, jsize length, int paramType, StackAllocator* stackAllocator, Array* array) { if (buf == NULL) { return NULL; } if ((paramType & ARRAY_PINNED) != 0) { return jffi_getArrayCritical(env, buf, offset, length, paramType, array); } switch (paramType & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_BYTE: ARRAY(Byte, jbyte, paramType, 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 (array->elems != NULL) { *(((char *) array->elems) + length) = '\0'; } } break; case com_kenai_jffi_ObjectBuffer_SHORT: ARRAY(Short, jshort, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_INT: ARRAY(Int, jint, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_LONG: ARRAY(Long, jlong, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_FLOAT: ARRAY(Float, jfloat, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_DOUBLE: ARRAY(Double, jdouble, paramType, buf, offset, length, array); break; default: throwException(env, IllegalArgument, "Invalid array type: %#x\n", paramType); return NULL; } array->array = buf; array->offset = offset; array->length = length; /* If its an IN-only array, don't bother copying the native data back. */ array->mode = ((paramType & (ARRAY_IN | ARRAY_OUT)) == ARRAY_IN) ? JNI_ABORT : 0; return array->elems; }
static void invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jint* infoBuffer, jobject* objectBuffer, void* retval) { Function* ctx = (Function *) j2p(ctxAddress); jbyte *tmpBuffer = NULL; void **ffiArgs = NULL; Array *arrays = NULL; unsigned int i, arrayCount = 0, paramBytes = 0; arrays = alloca(objectCount * sizeof(Array)); #if defined(USE_RAW) paramBytes = ctx->rawParameterSize; #else paramBytes = ctx->cif.nargs * PARAM_SIZE; #endif tmpBuffer = alloca(paramBytes); (*env)->GetByteArrayRegion(env, paramBuffer, 0, paramBytes, tmpBuffer); #ifndef USE_RAW ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < (unsigned int) ctx->cif.nargs; ++i) { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } #endif for (i = 0; i < (unsigned int) objectCount; ++i) { int type = infoBuffer[i * 3]; jsize offset = infoBuffer[(i * 3) + 1]; jsize length = infoBuffer[(i * 3) + 2]; jobject object = objectBuffer[i]; int idx = (type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT; void* ptr; switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) { case com_kenai_jffi_ObjectBuffer_ARRAY: 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)) { ptr = alloca(jffi_arraySize(length + 1, type)); if (unlikely(jffi_getArrayBuffer(env, object, offset, length, type, &arrays[arrayCount], ptr) == NULL)) { goto cleanup; } } else { ptr = jffi_getArrayHeap(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } } ++arrayCount; break; case com_kenai_jffi_ObjectBuffer_BUFFER: ptr = (*env)->GetDirectBufferAddress(env, object); if (unlikely(ptr == NULL)) { throwException(env, NullPointer, "Could not get direct Buffer address"); goto cleanup; } ptr = ((char *) ptr + offset); break; case com_kenai_jffi_ObjectBuffer_JNI: switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK) { case com_kenai_jffi_ObjectBuffer_JNIENV: ptr = env; break; case com_kenai_jffi_ObjectBuffer_JNIOBJECT: ptr = (void *) object; break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); 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 } #if defined(USE_RAW) // // Special case for struct return values - unroll into a ptr array and // use ffi_call, since ffi_raw_call with struct return values is undocumented. // if (unlikely(ctx->cif.rtype->type == FFI_TYPE_STRUCT)) { ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < ctx->cif.nargs; ++i) { ffiArgs[i] = (tmpBuffer + ctx->rawParamOffsets[i]); } ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); } else { ffi_raw_call(&ctx->cif, FFI_FN(ctx->function), retval, (ffi_raw *) tmpBuffer); } #else ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); #endif 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]); } } }