Example #1
0
static void
invoke_callback(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) {
  jobject self;
  void *oldresp = resp;

  self = (*env)->NewLocalRef(env, cb->object);
  // Avoid calling back to a GC'd object
  if ((*env)->IsSameObject(env, self, NULL)) {
    fprintf(stderr, "JNA: callback object has been garbage collected\n");
    if (cif->rtype->type != FFI_TYPE_VOID) {
      memset(resp, 0, cif->rtype->size); 
    }
  }
  else if (cb->direct) {
    unsigned int i;
    void **args = alloca((cif->nargs + 3) * sizeof(void *));
    args[0] = (void *)&env;
    args[1] = &self;
    args[2] = &cb->methodID;
    memcpy(&args[3], cbargs, cif->nargs * sizeof(void *));

    // Note that there is no support for CVT_TYPE_MAPPER here
    if (cb->conversion_flags) {
      for (i=0;i < cif->nargs;i++) {
        switch(cb->conversion_flags[i]) {
        case CVT_INTEGER_TYPE:
        case CVT_POINTER_TYPE:
        case CVT_NATIVE_MAPPED:
        case CVT_NATIVE_MAPPED_STRING:
        case CVT_NATIVE_MAPPED_WSTRING:
	  // Make sure we have space enough for the new argument
	  args[i+3] = alloca(sizeof(void *));
	  *((void **)args[i+3]) = fromNativeCallbackParam(env, cb->arg_classes[i], cif->arg_types[i], cbargs[i], JNI_FALSE, cb->encoding);
          break;
        case CVT_POINTER:
          *((void **)args[i+3]) = newJavaPointer(env, *(void **)cbargs[i]);
          break;
        case CVT_STRING:
          *((void **)args[i+3]) = newJavaString(env, *(void **)cbargs[i], cb->encoding);
          break;
        case CVT_WSTRING:
          *((void **)args[i+3]) = newJavaWString(env, *(void **)cbargs[i]);
          break;
        case CVT_STRUCTURE:
          *((void **)args[i+3]) = newJavaStructure(env, *(void **)cbargs[i], cb->arg_classes[i]);
          break;
        case CVT_STRUCTURE_BYVAL:
	  args[i+3] = alloca(sizeof(void *));
	  *((void **)args[i+3]) = newJavaStructure(env, cbargs[i], cb->arg_classes[i]);
          break;
        case CVT_CALLBACK:
          *((void **)args[i+3]) = newJavaCallback(env, *(void **)cbargs[i], cb->arg_classes[i]);
          break;
        case CVT_FLOAT:
	  args[i+3] = alloca(sizeof(double));
	  *((double *)args[i+3]) = *(float*)cbargs[i];
          break;
        case CVT_DEFAULT:
          break;
        default:
          fprintf(stderr, "JNA: Unhandled arg conversion type %d\n", cb->conversion_flags[i]);
          break;
        }
      }
    }

    if (cb->rflag == CVT_STRUCTURE_BYVAL) {
      resp = alloca(sizeof(jobject));
    }
    else if (cb->cif.rtype->size > cif->rtype->size) {
      resp = alloca(cb->cif.rtype->size);
    }
#define FPTR(ENV,OFFSET) (*(void **)((char *)(*(ENV)) + OFFSET))
#define JNI_FN(X) ((void (*)(void))(X))
    ffi_call(&cb->java_cif, JNI_FN(FPTR(env, cb->fptr_offset)), resp, args);
    if ((*env)->ExceptionCheck(env)) {
      jthrowable throwable = (*env)->ExceptionOccurred(env);
      (*env)->ExceptionClear(env);
      if (!handle_exception(env, self, throwable)) {
        fprintf(stderr, "JNA: error handling callback exception, continuing\n");
      }
      if (cif->rtype->type != FFI_TYPE_VOID) {
        memset(oldresp, 0, cif->rtype->size);
      }
    }
    else switch(cb->rflag) {
    case CVT_INTEGER_TYPE:
      if (cb->cif.rtype->size > sizeof(ffi_arg)) {
        *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp);
      }
      else {
        *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp);
      }
      break;
    case CVT_POINTER_TYPE:
      *(void **)resp = getPointerTypeAddress(env, *(void **)resp);
      break;
    case CVT_NATIVE_MAPPED:
      toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding);
      break;
    case CVT_NATIVE_MAPPED_STRING:
    case CVT_NATIVE_MAPPED_WSTRING:
      // TODO: getNativeString rather than allocated memory
      fprintf(stderr, "JNA: Likely memory leak here\n");
      toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE, cb->encoding);
      break;
    case CVT_POINTER:
      *(void **)resp = getNativeAddress(env, *(void **)resp);
      break;
    case CVT_STRING: 
      *(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE);
      break;
    case CVT_WSTRING: 
      *(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE);
      break;
    case CVT_STRUCTURE:
      writeStructure(env, *(void **)resp);
      *(void **)resp = getStructureAddress(env, *(void **)resp);
      break;
    case CVT_STRUCTURE_BYVAL:
      writeStructure(env, *(void **)resp);
      memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size);
      break;
    case CVT_CALLBACK: 
      *(void **)resp = getCallbackAddress(env, *(void **)resp);
      break;
    case CVT_DEFAULT:
      break;
    default:
      fprintf(stderr, "JNA: Unhandled result conversion: %d\n", cb->rflag);
      break;
    }
    if (cb->conversion_flags) {
      for (i=0;i < cif->nargs;i++) {
        if (cb->conversion_flags[i] == CVT_STRUCTURE) {
          writeStructure(env, *(void **)cbargs[i]);
        }
      }
    }
  }
  else {
    jobject result;
    jobjectArray params =
      (*env)->NewObjectArray(env, cif->nargs, classObject, NULL);
    unsigned int i;

    for (i=0;i < cif->nargs;i++) {
      jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE, cb->encoding);
      (*env)->SetObjectArrayElement(env, params, i, arg);
    }
    result = (*env)->CallObjectMethod(env, self, cb->methodID, params);
    if ((*env)->ExceptionCheck(env)) {
      jthrowable throwable = (*env)->ExceptionOccurred(env);
      (*env)->ExceptionClear(env);
      if (!handle_exception(env, self, throwable)) {
        fprintf(stderr, "JNA: error while handling callback exception, continuing\n");
      }
      if (cif->rtype->type != FFI_TYPE_VOID)
        memset(resp, 0, cif->rtype->size);
    }
    else {
      extract_value(env, result, resp, cif->rtype->size, JNI_TRUE, cb->encoding);
    }
  }
}
Example #2
0
File: callback.c Project: miho/jna
static void
callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) {
  jobject self;
  void *oldresp = resp;

  self = (*env)->NewLocalRef(env, cb->object);
  // Avoid calling back to a GC'd object
  if ((*env)->IsSameObject(env, self, NULL)) {
    fprintf(stderr, "JNA: callback object has been garbage collected\n");
    if (cif->rtype->type != FFI_TYPE_VOID) {
      memset(resp, 0, cif->rtype->size); 
    }
  }
  else if (cb->direct) {
    unsigned int i;
    void **args = alloca((cif->nargs + 3) * sizeof(void *));
    args[0] = (void *)&env;
    args[1] = &self;
    args[2] = &cb->methodID;
    memcpy(&args[3], cbargs, cif->nargs * sizeof(void *));

    if (cb->flags) {
      for (i=0;i < cif->nargs;i++) {
        switch(cb->flags[i]) {
        case CVT_INTEGER_TYPE:
        case CVT_POINTER_TYPE:
        case CVT_NATIVE_MAPPED:
          *((void **)args[i+3]) = fromNative(env, cb->arg_classes[i], cif->arg_types[i], args[i+3], JNI_FALSE);
          break;
        case CVT_POINTER:
          *((void **)args[i+3]) = newJavaPointer(env, *(void **)args[i+3]);
          break;
        case CVT_STRING:
          *((void **)args[i+3]) = newJavaString(env, *(void **)args[i+3], JNI_FALSE);
          break;
        case CVT_WSTRING:
          *((void **)args[i+3]) = newJavaWString(env, *(void **)args[i+3]);
          break;
        case CVT_STRUCTURE:
          *((void **)args[i+3]) = newJavaStructure(env, *(void **)args[i+3], cb->arg_classes[i], JNI_FALSE);
          break;
        case CVT_STRUCTURE_BYVAL:
          { 
            void *ptr = args[i+3];
            args[i+3] = alloca(sizeof(void *));
            *((void **)args[i+3]) = newJavaStructure(env, ptr, cb->arg_classes[i], JNI_TRUE);
          }
          break;
        case CVT_CALLBACK:
          *((void **)args[i+3]) = newJavaCallback(env, *(void **)args[i+3], cb->arg_classes[i]);
          break;
        case CVT_FLOAT:
          {
            void *ptr = alloca(sizeof(double));
            *(double *)ptr = *(float*)args[i+3];
            args[i+3] = ptr;
          }
          break;
        }
      }
    }

    if (cb->rflag == CVT_STRUCTURE_BYVAL) {
      resp = alloca(sizeof(jobject));
    }
    else if (cb->cif.rtype->size > cif->rtype->size) {
      resp = alloca(cb->cif.rtype->size);
    }
    ffi_call(&cb->java_cif, FFI_FN(cb->fptr), resp, args);
    if ((*env)->ExceptionCheck(env)) {
      jthrowable throwable = (*env)->ExceptionOccurred(env);
      (*env)->ExceptionClear(env);
      if (!handle_exception(env, self, throwable)) {
        fprintf(stderr, "JNA: error handling callback exception, continuing\n");
      }
      if (cif->rtype->type != FFI_TYPE_VOID)
        memset(oldresp, 0, cif->rtype->size);
    }
    else switch(cb->rflag) {
    case CVT_INTEGER_TYPE:
      if (cb->cif.rtype->size > sizeof(ffi_arg)) {
        *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp);
      }
      else {
        *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp);
      }
      break;
    case CVT_POINTER_TYPE:
      *(void **)resp = getPointerTypeAddress(env, *(void **)resp);
      break;
    case CVT_NATIVE_MAPPED:
      toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE);
      break;
    case CVT_POINTER:
      *(void **)resp = getNativeAddress(env, *(void **)resp);
      break;
    case CVT_STRING: 
      *(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE);
      break;
    case CVT_WSTRING: 
      *(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE);
      break;
    case CVT_STRUCTURE:
      writeStructure(env, *(void **)resp);
      *(void **)resp = getStructureAddress(env, *(void **)resp);
      break;
    case CVT_STRUCTURE_BYVAL:
      writeStructure(env, *(void **)resp);
      memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size);
      break;
    case CVT_CALLBACK: 
      *(void **)resp = getCallbackAddress(env, *(void **)resp);
      break;
    default: break;
    }
    if (cb->flags) {
      for (i=0;i < cif->nargs;i++) {
        if (cb->flags[i] == CVT_STRUCTURE) {
          writeStructure(env, *(void **)args[i+3]);
        }
      }
    }
  }
  else {
    jobject result;
    jobjectArray array =
      (*env)->NewObjectArray(env, cif->nargs, classObject, NULL);
    unsigned int i;

    for (i=0;i < cif->nargs;i++) {
      jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE);
      (*env)->SetObjectArrayElement(env, array, i, arg);
    }
    result = (*env)->CallObjectMethod(env, self, cb->methodID, array);
    if ((*env)->ExceptionCheck(env)) {
      jthrowable throwable = (*env)->ExceptionOccurred(env);
      (*env)->ExceptionClear(env);
      if (!handle_exception(env, self, throwable)) {
        fprintf(stderr, "JNA: error handling callback exception, continuing\n");
      }
      if (cif->rtype->type != FFI_TYPE_VOID)
        memset(resp, 0, cif->rtype->size);
    }
    else {
      extract_value(env, result, resp, cif->rtype->size, JNI_TRUE);
    }
  }
}