Пример #1
0
static PyObject* pyjconstructor_call(PyJMethodObject *self, PyObject *args,
                                     PyObject *keywords)
{
    PyObject      *firstArg    = NULL;
    PyJObject     *clazz       = NULL;
    JNIEnv        *env         = NULL;
    int            pos         = 0;
    jvalue        *jargs       = NULL;
    int           foundArray   = 0; /* if params includes pyjarray instance */
    PyThreadState *_save       = NULL;
    jobject   obj  = NULL;
    PyObject *pobj = NULL;

    if (keywords != NULL) {
        PyErr_Format(PyExc_TypeError, "Keywords are not supported.");
        return NULL;
    }

    if (self->lenParameters != PyTuple_GET_SIZE(args) - 1) {
        PyErr_Format(PyExc_RuntimeError,
                     "Invalid number of arguments: %i, expected %i.", (int) PyTuple_GET_SIZE(args),
                     self->lenParameters + 1);
        return NULL;
    }

    firstArg = PyTuple_GetItem(args, 0);
    if (!pyjclass_check(firstArg)) {
        PyErr_SetString(PyExc_RuntimeError,
                        "First argument to a java constructor must be a java class.");
        return NULL;

    }
    clazz = (PyJObject*) firstArg;


    // ------------------------------ build jargs off python values
    env = pyembed_get_env();
    if ((*env)->PushLocalFrame(env, JLOCAL_REFS + self->lenParameters) != 0) {
        process_java_exception(env);
        return NULL;
    }

    jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * self->lenParameters);

    for (pos = 0; pos < self->lenParameters; pos++) {
        PyObject *param = NULL;
        int paramTypeId = -1;
        jclass paramType = (jclass) (*env)->GetObjectArrayElement(env,
                           self->parameters, pos);

        param = PyTuple_GetItem(args, pos + 1); /* borrowed */
        if (PyErr_Occurred()) {
            goto EXIT_ERROR;
        }

        paramTypeId = get_jtype(env, paramType);
        if (paramTypeId == JARRAY_ID) {
            foundArray = 1;
        }

        jargs[pos] = convert_pyarg_jvalue(env, param, paramType, paramTypeId, pos);
        if (PyErr_Occurred()) {
            goto EXIT_ERROR;
        }

        (*env)->DeleteLocalRef(env, paramType);
    }

    Py_UNBLOCK_THREADS;
    obj = (*env)->NewObjectA(env,
                             clazz->clazz,
                             self->methodId,
                             jargs);
    Py_BLOCK_THREADS;
    if (process_java_exception(env) || !obj) {
        goto EXIT_ERROR;
    }

    // finally, make pyjobject and return
    pobj = pyjobject_new(env, obj);

    // we already closed the local frame, so make
    // sure to delete this local ref.
    PyMem_Free(jargs);

    // re pin array if needed
    if (foundArray) {
        for (pos = 0; pos < self->lenParameters; pos++) {
            PyObject *param = PyTuple_GetItem(args, pos);
            if (param && pyjarray_check(param)) {
                pyjarray_pin((PyJArrayObject *) param);
            }
        }
    }

    (*env)->PopLocalFrame(env, NULL);
    return pobj;

EXIT_ERROR:
    PyMem_Free(jargs);
    (*env)->PopLocalFrame(env, NULL);
    return NULL;
}
Пример #2
0
// 1 if successful, 0 if failed.
int pyjmethod_init(JNIEnv *env, PyJmethod_Object *self) {
    jmethodID         methodId;
    jobject           returnType             = NULL;
    jobjectArray      paramArray             = NULL;
    jclass            modClass               = NULL;
    jint              modifier               = -1;
    jboolean          isStatic               = JNI_FALSE;
    jclass            rmethodClass           = NULL;
    
    // use a local frame so we don't have to worry too much about local refs.
    // make sure if this method errors out, that this is poped off again
    (*env)->PushLocalFrame(env, 20);
    if(process_java_exception(env))
        return 0;
    
    rmethodClass = (*env)->GetObjectClass(env, self->rmethod);
    if(process_java_exception(env) || !rmethodClass)
        goto EXIT_ERROR;
    
    // ------------------------------ get methodid
    
    methodId = (*env)->FromReflectedMethod(env,
                                           self->rmethod);
    if(process_java_exception(env) || !methodId)
        goto EXIT_ERROR;
    
    self->methodId = methodId;
    
    
    // ------------------------------ get return type
    
    if(methodGetType == 0) {
        methodGetType = (*env)->GetMethodID(env,
                                            rmethodClass,
                                            "getReturnType",
                                            "()Ljava/lang/Class;");
        if(process_java_exception(env) || !methodGetType)
            goto EXIT_ERROR;
    }
    
    returnType = (*env)->CallObjectMethod(env,
                                          self->rmethod,
                                          methodGetType);
    if(process_java_exception(env) || !returnType)
        goto EXIT_ERROR;
    
    self->returnTypeId = get_jtype(env, returnType);
    if(process_java_exception(env))
        goto EXIT_ERROR;

    
    // ------------------------------ get parameter array

    if(methodGetParmTypes == 0) {
        methodGetParmTypes = (*env)->GetMethodID(env,
                                                 rmethodClass,
                                                 "getParameterTypes",
                                                 "()[Ljava/lang/Class;");
        if(process_java_exception(env) || !methodGetParmTypes)
            goto EXIT_ERROR;
    }
    
    paramArray = (jobjectArray) (*env)->CallObjectMethod(env,
                                                         self->rmethod,
                                                         methodGetParmTypes);
    if(process_java_exception(env) || !paramArray)
        goto EXIT_ERROR;
    
    self->parameters    = (*env)->NewGlobalRef(env, paramArray);
    self->lenParameters = (*env)->GetArrayLength(env, paramArray);
    
    // ------------------------------ get isStatic
    if(self->isStatic != 1) { // may already know that
        
        // call getModifers()
        if(methodGetModifiers == 0) {
            methodGetModifiers = (*env)->GetMethodID(env,
                                                     rmethodClass,
                                                     "getModifiers",
                                                     "()I");
            if(process_java_exception(env) || !methodGetModifiers)
                goto EXIT_ERROR;
        }
        
        modifier = (*env)->CallIntMethod(env,
                                         self->rmethod,
                                         methodGetModifiers);
        if(process_java_exception(env) || !modifier)
            goto EXIT_ERROR;
        
        modClass = (*env)->FindClass(env, "java/lang/reflect/Modifier");
        if(process_java_exception(env) || !modClass)
            goto EXIT_ERROR;
        
        // caching this methodid caused a crash on the mac
        methodId = (*env)->GetStaticMethodID(env,
                                             modClass,
                                             "isStatic",
                                             "(I)Z");
        if(process_java_exception(env) || !methodId)
            goto EXIT_ERROR;
        
        isStatic = (*env)->CallStaticBooleanMethod(env,
                                                   modClass,
                                                   methodId,
                                                   modifier);
        if(process_java_exception(env))
            goto EXIT_ERROR;
        
        if(isStatic == JNI_TRUE)
            self->isStatic = 1;
        else
            self->isStatic = 0;
    } // is static
    
    
    (*env)->PopLocalFrame(env, NULL);
    return 1;
    
    
EXIT_ERROR:
    (*env)->PopLocalFrame(env, NULL);
    
    if(!PyErr_Occurred())
        PyErr_SetString(PyExc_RuntimeError, "Unknown");
    return -1;
}
Пример #3
0
// pyjmethod_call_internal. where the magic happens.
// 
// okay, some of the magic -- we already the methodId, so we don't have
// to reflect. we just have to parse the arguments from python,
// check them against the java args, and call the java function.
// 
// easy. :-)
PyObject* pyjmethod_call_internal(PyJmethod_Object *self,
                                  PyJobject_Object *instance,
                                  PyObject *args) {
    PyObject      *result     = NULL;
    const char    *str        = NULL;
    JNIEnv        *env        = NULL;
    int            pos        = 0;
    jvalue        *jargs      = NULL;
    int            foundArray = 0;   /* if params includes pyjarray instance */
    PyThreadState *_save;
    
    env = pyembed_get_env();
    
    if(!self->parameters) {
        if(!pyjmethod_init(env, self) || PyErr_Occurred())
            return NULL;
        return pyjmethod_call_internal(self, instance, args);
    }
    
    // validate we can call this method
    if(!instance->object && self->isStatic != JNI_TRUE) {
        PyErr_Format(PyExc_RuntimeError,
                     "Instantiate this class before "
                     "calling an object method.");
        return NULL;
    }
    
    // shouldn't happen
    if(self->lenParameters != PyTuple_GET_SIZE(args)) {
        PyErr_Format(PyExc_RuntimeError,
                     "Invalid number of arguments: %i, expected %i.",
                     (int) PyTuple_GET_SIZE(args),
                     self->lenParameters);
        return NULL;
    }

    jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * self->lenParameters);
    
    // ------------------------------ build jargs off python values

    // hopefully 40 local references are enough per method call
    (*env)->PushLocalFrame(env, 40);
    for(pos = 0; pos < self->lenParameters; pos++) {
        PyObject *param = NULL;
        int paramTypeId = -1;
        jclass paramType = (jclass) (*env)->GetObjectArrayElement(env,
                self->parameters, pos);

        param = PyTuple_GetItem(args, pos);                   /* borrowed */
        if(PyErr_Occurred()) {                                /* borrowed */
            goto EXIT_ERROR;
        }

        paramTypeId = get_jtype(env, paramType);
        if(paramTypeId == JARRAY_ID)
            foundArray = 1;
        
        jargs[pos] = convert_pyarg_jvalue(env,
                                          param,
                                          paramType,
                                          paramTypeId,
                                          pos);
        if(PyErr_Occurred()) {                                /* borrowed */
            goto EXIT_ERROR;
        }

        (*env)->DeleteLocalRef(env, paramType);
    } // for parameters

    
    // ------------------------------ call based off return type

    switch(self->returnTypeId) {

    case JSTRING_ID: {
        jstring jstr;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            jstr = (jstring) (*env)->CallStaticObjectMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            // not static, a method on class then.
            if(!instance->object)
                jstr = (jstring) (*env)->CallObjectMethodA(
                    env,
                    instance->clazz,
                    self->methodId,
                    jargs);
            else
                jstr = (jstring) (*env)->CallObjectMethodA(
                    env,
                    instance->object,
                    self->methodId,
                    jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env) && jstr != NULL) {
            str    = (*env)->GetStringUTFChars(env, jstr, 0);
            result = PyString_FromString(str);
            
            (*env)->ReleaseStringUTFChars(env, jstr, str);
            (*env)->DeleteLocalRef(env, jstr);
        }
        
        break;
    }

    case JARRAY_ID: {
        jobjectArray obj;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            obj = (jobjectArray) (*env)->CallStaticObjectMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                obj = (jobjectArray) (*env)->CallObjectMethodA(
                    env,
                    instance->clazz,
                    self->methodId,
                    jargs);
            else
                obj = (jobjectArray) (*env)->CallObjectMethodA(
                    env,
                    instance->object,
                    self->methodId,
                    jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env) && obj != NULL)
            result = pyjarray_new(env, obj);
        
        break;
    }

    case JCLASS_ID: {
        jobject obj;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            obj = (*env)->CallStaticObjectMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                obj = (*env)->CallObjectMethodA(env,
                                                instance->clazz,
                                                self->methodId,
                                                jargs);
            else
                obj = (*env)->CallObjectMethodA(env,
                                                instance->object,
                                                self->methodId,
                                                jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env) && obj != NULL)
            result = pyjobject_new_class(env, obj);
        
        break;
    }

    case JOBJECT_ID: {
        jobject obj;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            obj = (*env)->CallStaticObjectMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                obj = (*env)->CallObjectMethodA(env,
                                                instance->clazz,
                                                self->methodId,
                                                jargs);
            else
                obj = (*env)->CallObjectMethodA(env,
                                                instance->object,
                                                self->methodId,
                                                jargs);
        }

        Py_BLOCK_THREADS;
        if(!process_java_exception(env) && obj != NULL) {
            result = pyjobject_new(env, obj);
        }
        
        break;
    }

    case JINT_ID: {
        jint ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticIntMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallIntMethodA(env,
                                             instance->clazz,
                                             self->methodId,
                                             jargs);
            else
                ret = (*env)->CallIntMethodA(env,
                                             instance->object,
                                             self->methodId,
                                             jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = Py_BuildValue("i", ret);
        
        break;
    }

    case JBYTE_ID: {
        jbyte ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticByteMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallByteMethodA(env,
                                              instance->clazz,
                                              self->methodId,
                                              jargs);
            else
                ret = (*env)->CallByteMethodA(env,
                                              instance->object,
                                              self->methodId,
                                              jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = Py_BuildValue("i", ret);
        
        break;
    }

    case JCHAR_ID: {
        jchar ret;
        char  val[2];
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticCharMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallCharMethodA(env,
                                              instance->clazz,
                                              self->methodId,
                                              jargs);
            else
                ret = (*env)->CallCharMethodA(env,
                                              instance->object,
                                              self->methodId,
                                              jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env)) {
            val[0] = (char) ret;
            val[1] = '\0';
            result = PyString_FromString(val);
        }
        break;
    }

    case JSHORT_ID: {
        jshort ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticShortMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallShortMethodA(env,
                                               instance->clazz,
                                               self->methodId,
                                               jargs);
            else
                ret = (*env)->CallShortMethodA(env,
                                               instance->object,
                                               self->methodId,
                                               jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = Py_BuildValue("i", (int) ret);
        
        break;
    }

    case JDOUBLE_ID: {
        jdouble ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticDoubleMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallDoubleMethodA(env,
                                                instance->clazz,
                                                self->methodId,
                                                jargs);
            else
                ret = (*env)->CallDoubleMethodA(env,
                                                instance->object,
                                                self->methodId,
                                                jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = PyFloat_FromDouble(ret);
        
        break;
    }

    case JFLOAT_ID: {
        jfloat ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticFloatMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallFloatMethodA(env,
                                               instance->clazz,
                                               self->methodId,
                                               jargs);
            else
                ret = (*env)->CallFloatMethodA(env,
                                               instance->object,
                                               self->methodId,
                                               jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = PyFloat_FromDouble((double) ret);
        
        break;
    }

    case JLONG_ID: {
        jlong ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticLongMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallLongMethodA(env,
                                              instance->clazz,
                                              self->methodId,
                                              jargs);
            else
                ret = (*env)->CallLongMethodA(env,
                                              instance->object,
                                              self->methodId,
                                              jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = PyLong_FromLongLong(ret);
        
        break;
    }

    case JBOOLEAN_ID: {
        jboolean ret;
        Py_UNBLOCK_THREADS;
        
        if(self->isStatic)
            ret = (*env)->CallStaticBooleanMethodA(
                env,
                instance->clazz,
                self->methodId,
                jargs);
        else {
            if(!instance->object)
                ret = (*env)->CallBooleanMethodA(env,
                                                 instance->clazz,
                                                 self->methodId,
                                                 jargs);
            else
                ret = (*env)->CallBooleanMethodA(env,
                                                 instance->object,
                                                 self->methodId,
                                                 jargs);
        }
        
        Py_BLOCK_THREADS;
        if(!process_java_exception(env))
            result = Py_BuildValue("i", ret);
        
        break;
    }

    default:
        Py_UNBLOCK_THREADS;

        // i hereby anoint thee a void method
        if(self->isStatic)
            (*env)->CallStaticVoidMethodA(env,
                                          instance->clazz,
                                          self->methodId,
                                          jargs);
        else
            (*env)->CallVoidMethodA(env,
                                    instance->object,
                                    self->methodId,
                                    jargs);

        Py_BLOCK_THREADS;
        process_java_exception(env);
        break;
    }
    
    PyMem_Free(jargs);
    (*env)->PopLocalFrame(env, NULL);
    
    if(PyErr_Occurred())
        return NULL;
    
    // re pin array objects if needed
    if(foundArray) {
        for(pos = 0; pos < self->lenParameters; pos++) {
            PyObject *param = PyTuple_GetItem(args, pos);     /* borrowed */
            if(param && pyjarray_check(param))
                pyjarray_pin((PyJarray_Object *) param);
        }
    }
    
    if(result == NULL) {
        Py_RETURN_NONE;
    }
    
    return result;

EXIT_ERROR:
   PyMem_Free(jargs);
   (*env)->PopLocalFrame(env, NULL);
   return NULL;
}
Пример #4
0
// called internally to make new PyJObject instances
PyObject* pyjobject_new(JNIEnv *env, jobject obj)
{
    PyJObject    *pyjob;
    jclass        objClz;
    int           jtype;

    if (!subtypes_initialized) {
        pyjobject_init_subtypes();
    }
    if (!obj) {
        PyErr_Format(PyExc_RuntimeError, "Invalid object.");
        return NULL;
    }

    objClz = (*env)->GetObjectClass(env, obj);

    /*
     * There exist situations where a Java method signature has a return
     * type of Object but actually returns a Class or array.  Also if you
     * call Jep.set(String, Object[]) it should be treated as an array, not
     * an object.  Hence this check here to build the optimal jep type in
     * the interpreter regardless of signature.
     */
    jtype = get_jtype(env, objClz);
    if (jtype == JARRAY_ID) {
        return pyjarray_new(env, obj);
    } else if (jtype == JCLASS_ID) {
        return pyjobject_new_class(env, obj);
    } else {
#if JEP_NUMPY_ENABLED
        /*
         * check for jep/NDArray and autoconvert to numpy.ndarray instead of
         * pyjobject
         */
        if (jndarray_check(env, obj)) {
            return convert_jndarray_pyndarray(env, obj);
        }
        if (PyErr_Occurred()) {
            return NULL;
        }
#endif

        // check for some of our extensions to pyjobject
        if ((*env)->IsInstanceOf(env, obj, JITERABLE_TYPE)) {
            if ((*env)->IsInstanceOf(env, obj, JCOLLECTION_TYPE)) {
                if ((*env)->IsInstanceOf(env, obj, JLIST_TYPE)) {
                    pyjob = (PyJObject*) pyjlist_new();
                } else {
                    // a Collection we have less support for
                    pyjob = (PyJObject*) pyjcollection_new();
                }
            } else {
                // an Iterable we have less support for
                pyjob = (PyJObject*) pyjiterable_new();
            }
        } else if ((*env)->IsInstanceOf(env, obj, JMAP_TYPE)) {
            pyjob = (PyJObject*) pyjmap_new();
        } else if ((*env)->IsInstanceOf(env, obj, JITERATOR_TYPE)) {
            pyjob = (PyJObject*) pyjiterator_new();
        } else if ((*env)->IsInstanceOf(env, obj, JNUMBER_TYPE)) {
            pyjob = (PyJObject*) pyjnumber_new();
        } else {
            pyjob = PyObject_NEW(PyJObject, &PyJObject_Type);
        }
    }


    pyjob->object      = (*env)->NewGlobalRef(env, obj);
    pyjob->clazz       = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env,
                         obj));
    pyjob->attr        = PyList_New(0);
    pyjob->methods     = PyList_New(0);
    pyjob->fields      = PyList_New(0);
    pyjob->finishAttr  = 0;

    if (pyjobject_init(env, pyjob)) {
        return (PyObject *) pyjob;
    }
    return NULL;
}
Пример #5
0
static int pyjfield_init(JNIEnv *env, PyJfield_Object *self) {
    jfieldID         fieldId;
    jclass           rfieldClass = NULL;
    jobject          fieldType   = NULL;
    jclass           modClass    = NULL;
    jint             modifier    = -1;
    jboolean         isStatic    = JNI_TRUE;

    // use a local frame so we don't have to worry too much about local refs.
    // make sure if this method errors out, that this is poped off again
    (*env)->PushLocalFrame(env, 20);
    if(process_java_exception(env))
        return 0;
    
    rfieldClass = (*env)->GetObjectClass(env, self->rfield);
    if(process_java_exception(env) || !rfieldClass)
        goto EXIT_ERROR;
    
    
    // ------------------------------ get fieldid
    
    fieldId = (*env)->FromReflectedField(env,
                                         self->rfield);
    if(process_java_exception(env) || !fieldId)
        goto EXIT_ERROR;
    
    self->fieldId = fieldId;
    
    
    // ------------------------------ get return type
    
    if(classGetType == 0) {
        classGetType = (*env)->GetMethodID(env,
                                           rfieldClass,
                                           "getType",
                                           "()Ljava/lang/Class;");
        if(process_java_exception(env) || !classGetType)
            goto EXIT_ERROR;
    }
    
    fieldType = (*env)->CallObjectMethod(env,
                                         self->rfield,
                                         classGetType);
    if(process_java_exception(env) || !fieldType)
        goto EXIT_ERROR;
    
    {
        self->fieldTypeId = get_jtype(env, fieldType);

        if(process_java_exception(env))
            goto EXIT_ERROR;
    }
    
    // ------------------------------ get isStatic
    
    // call getModifers()
    if(classGetMod == 0) {
        classGetMod = (*env)->GetMethodID(env,
                                          rfieldClass,
                                          "getModifiers",
                                          "()I");
        if(process_java_exception(env) || !classGetMod)
            goto EXIT_ERROR;
    }
    
    modifier = (*env)->CallIntMethod(env,
                                     self->rfield,
                                     classGetMod);
    if(process_java_exception(env))
        goto EXIT_ERROR;
    
    modClass = (*env)->FindClass(env, "java/lang/reflect/Modifier");
    if(process_java_exception(env) || !modClass)
        goto EXIT_ERROR;
    
    if(modIsStatic == 0) {
        modIsStatic = (*env)->GetStaticMethodID(env,
                                                modClass,
                                                "isStatic",
                                                "(I)Z");
        if(process_java_exception(env) || !modIsStatic)
            goto EXIT_ERROR;
    }
    
    isStatic = (*env)->CallStaticBooleanMethod(env,
                                               modClass,
                                               modIsStatic,
                                               modifier);
    if(process_java_exception(env))
        goto EXIT_ERROR;
    
    if(!self->pyjobject->object && !isStatic) {
        PyErr_SetString(PyExc_TypeError, "Field is not static.");
        goto EXIT_ERROR;
    }
    if(isStatic == JNI_TRUE)
        self->isStatic = 1;
    else
        self->isStatic = 0;
    
    (*env)->PopLocalFrame(env, NULL);
    self->init = 1;
    return 1;
    
EXIT_ERROR:
    (*env)->PopLocalFrame(env, NULL);
    
    if(!PyErr_Occurred())
        PyErr_SetString(PyExc_RuntimeError, "Unknown");
    
    return 0;
}
Пример #6
0
// find and call a method on this object that matches the python args.
// typically called by way of pyjmethod when python invokes __call__.
//
// steals reference to self, methodname and args.
PyObject* find_method(JNIEnv *env,
                      PyObject *methodName,
                      Py_ssize_t methodCount,
                      PyObject *attr,
                      PyObject *args) {
    // all possible method candidates
    PyJmethod_Object **cand = NULL;
    Py_ssize_t         pos, i, listSize, argsSize;
    
    pos = i = listSize = argsSize = 0;

    // not really likely if we were called from pyjmethod, but hey...
    if(methodCount < 1) {
        PyErr_Format(PyExc_RuntimeError, "I have no methods.");
        return NULL;
    }

    if(!attr || !PyList_CheckExact(attr)) {
        PyErr_Format(PyExc_RuntimeError, "Invalid attr list.");
        return NULL;
    }
    
    cand = (PyJmethod_Object **)
        PyMem_Malloc(sizeof(PyJmethod_Object*) * methodCount);
    
    // just for safety
    for(i = 0; i < methodCount; i++)
        cand[i] = NULL;
    
    listSize = PyList_GET_SIZE(attr);
    for(i = 0; i < listSize; i++) {
        PyObject *tuple = PyList_GetItem(attr, i);               /* borrowed */

        if(PyErr_Occurred())
            break;
        
        if(!tuple || tuple == Py_None || !PyTuple_CheckExact(tuple))
            continue;

        if(PyTuple_Size(tuple) == 2) {
            PyObject *key = PyTuple_GetItem(tuple, 0);           /* borrowed */
            
            if(PyErr_Occurred())
                break;
            
            if(!key || !PyString_Check(key))
                continue;
            
            if(PyObject_Compare(key, methodName) == 0) {
                PyObject *method = PyTuple_GetItem(tuple, 1);    /* borrowed */
                if(pyjmethod_check(method))
                    cand[pos++] = (PyJmethod_Object *) method;
            }
        }
    }
    
    if(PyErr_Occurred())
        goto EXIT_ERROR;
    
    // makes more sense to work with...
    pos--;
    
    if(pos < 0) {
        // didn't find a method by that name....
        // that shouldn't happen unless the search above is broken.
        PyErr_Format(PyExc_NameError, "No such method.");
        goto EXIT_ERROR;
    }
    if(pos == 0) {
        // we're done, call that one
        PyObject *ret = pyjmethod_call_internal(cand[0], args);
        PyMem_Free(cand);
        return ret;
    }

    // first, find out if there's only one method that
    // has the correct number of args
    argsSize = PyTuple_Size(args);
    {
        PyJmethod_Object *matching = NULL;
        int               count    = 0;
        
        for(i = 0; i <= pos && cand[i]; i++) {
            // make sure method is fully initialized
            if(!cand[i]->parameters) {
                if(!pyjmethod_init(env, cand[i])) {
                    // init failed, that's not good.
                    cand[i] = NULL;
                    PyErr_Warn(PyExc_Warning, "pyjmethod init failed.");
                    continue;
                }
            }

            if(cand[i]->lenParameters == argsSize) {
                matching = cand[i];
                count++;
            }
            else
                cand[i] = NULL; // eliminate non-matching
        }
        
        if(matching && count == 1) {
            PyMem_Free(cand);
            return pyjmethod_call_internal(matching, args);
        }
    } // local scope
    
    for(i = 0; i <= pos; i++) {
        int parmpos = 0;
        
        // already eliminated?
        if(!cand[i])
            continue;
        
        // check if argument types match
        (*env)->PushLocalFrame(env, 20);
        for(parmpos = 0; parmpos < cand[i]->lenParameters; parmpos++) {
            PyObject *param       = PyTuple_GetItem(args, parmpos);
            int       paramTypeId = -1;
            jclass    pclazz;
            jclass    paramType =
                (jclass) (*env)->GetObjectArrayElement(env,
                                                       cand[i]->parameters,
                                                       parmpos);

            if(process_java_exception(env) || !paramType)
                break;
            
            pclazz = (*env)->GetObjectClass(env, paramType);
            if(process_java_exception(env) || !pclazz)
                break;
            
            paramTypeId = get_jtype(env, paramType, pclazz);
            
            if(pyarg_matches_jtype(env, param, paramType, paramTypeId)) {
                if(PyErr_Occurred())
                    break;
                continue;
            }
            
            // args don't match
            break;
        }
        (*env)->PopLocalFrame(env, NULL);
        
        // this method matches?
        if(parmpos == cand[i]->lenParameters) {
            PyObject *ret = pyjmethod_call_internal(cand[i], args);
            PyMem_Free(cand);
            return ret;
        }
    }


EXIT_ERROR:
    PyMem_Free(cand);
    if(!PyErr_Occurred())
        PyErr_Format(PyExc_NameError,
                     "Matching overloaded method not found.");
    return NULL;
}
Пример #7
0
callback*
create_callback(JNIEnv* env, jobject obj, jobject method,
                jobjectArray param_types, jclass return_type,
                callconv_t calling_convention, jboolean direct) {
  callback* cb;
  ffi_abi abi = FFI_DEFAULT_ABI;
  ffi_abi java_abi = FFI_DEFAULT_ABI;
  ffi_type* ffi_rtype;
  ffi_status status;
  jsize argc;
  JavaVM* vm;
  int rtype;
  char msg[64];
  int i;
  int cvt = 0;
  const char* throw_type = NULL;
  const char* throw_msg = NULL;

  if ((*env)->GetJavaVM(env, &vm) != JNI_OK) {
    throwByName(env, EUnsatisfiedLink, "Can't get Java VM");
    return NULL;
  }
  argc = (*env)->GetArrayLength(env, param_types);

  cb = (callback *)malloc(sizeof(callback));
  cb->closure = ffi_closure_alloc(sizeof(ffi_closure), &cb->x_closure);
  cb->object = (*env)->NewWeakGlobalRef(env, obj);
  cb->methodID = (*env)->FromReflectedMethod(env, method);
  cb->vm = vm;
  cb->arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * argc);
  cb->java_arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * (argc + 3));
  cb->arg_jtypes = (char*)malloc(sizeof(char) * argc);
  cb->flags = (int *)malloc(sizeof(int) * argc);
  cb->rflag = CVT_DEFAULT;
  cb->arg_classes = (jobject*)malloc(sizeof(jobject) * argc);
 
  cb->direct = direct;
  cb->java_arg_types[0] = cb->java_arg_types[1] = cb->java_arg_types[2] = &ffi_type_pointer;

  for (i=0;i < argc;i++) {
    int jtype;
    jclass cls = (*env)->GetObjectArrayElement(env, param_types, i);
    if ((cb->flags[i] = get_conversion_flag(env, cls)) != CVT_DEFAULT) {
      cb->arg_classes[i] = (*env)->NewWeakGlobalRef(env, cls);
      cvt = 1;
    }

    jtype = get_jtype(env, cls);
    if (jtype == -1) {
      snprintf(msg, sizeof(msg), "Unsupported argument at index %d", i);
      throw_type = EIllegalArgument;
      throw_msg = msg;
      goto failure_cleanup;
    }
    cb->arg_jtypes[i] = (char)jtype;
    cb->java_arg_types[i+3] = cb->arg_types[i] = get_ffi_type(env, cls, cb->arg_jtypes[i]);
    if (cb->flags[i] == CVT_NATIVE_MAPPED
        || cb->flags[i] == CVT_POINTER_TYPE
        || cb->flags[i] == CVT_INTEGER_TYPE) {
      jclass ncls;
      ncls = getNativeType(env, cls);
      jtype = get_jtype(env, ncls);
      if (jtype == -1) {
        snprintf(msg, sizeof(msg), "Unsupported NativeMapped argument native type at argument %d", i);
        throw_type = EIllegalArgument;
        throw_msg = msg;
        goto failure_cleanup;
      }
      cb->arg_jtypes[i] = (char)jtype;
      cb->java_arg_types[i+3] = &ffi_type_pointer;
      cb->arg_types[i] = get_ffi_type(env, ncls, cb->arg_jtypes[i]);
    }

    if (cb->arg_types[i]->type == FFI_TYPE_FLOAT) {
      // Java method is varargs, so promote floats to double
      cb->java_arg_types[i+3] = &ffi_type_double;
      cb->flags[i] = CVT_FLOAT;
      cvt = 1;
    }
    else if (cb->java_arg_types[i+3]->type == FFI_TYPE_STRUCT) {
      // All callback structure arguments are passed as a jobject
      cb->java_arg_types[i+3] = &ffi_type_pointer;
    }
  }
  if (!direct || !cvt) {
    free(cb->flags);
    cb->flags = NULL;
    free(cb->arg_classes);
    cb->arg_classes = NULL;
  }
  if (direct) {
    cb->rflag = get_conversion_flag(env, return_type);
    if (cb->rflag == CVT_NATIVE_MAPPED
        || cb->rflag == CVT_INTEGER_TYPE
        || cb->rflag == CVT_POINTER_TYPE) {
      return_type = getNativeType(env, return_type);
    }
  }

#if defined(_WIN32) && !defined(_WIN64)
  if (calling_convention == CALLCONV_STDCALL) {
    abi = FFI_STDCALL;
  }
  java_abi = FFI_STDCALL;
#endif // _WIN32

  rtype = get_jtype(env, return_type);
  if (rtype == -1) {
    throw_type = EIllegalArgument;
    throw_msg = "Unsupported return type";
    goto failure_cleanup;
  }
  ffi_rtype = get_ffi_rtype(env, return_type, (char)rtype);
  if (!ffi_rtype) {
    throw_type = EIllegalArgument;
    throw_msg = "Error in return type";
    goto failure_cleanup;
  }
  status = ffi_prep_cif(&cb->cif, abi, argc, ffi_rtype, cb->arg_types);
  if (!ffi_error(env, "callback setup", status)) {
    ffi_type* java_ffi_rtype = ffi_rtype;

    if (cb->rflag == CVT_STRUCTURE_BYVAL
        || cb->rflag == CVT_NATIVE_MAPPED
        || cb->rflag == CVT_POINTER_TYPE
        || cb->rflag == CVT_INTEGER_TYPE) {
      // Java method returns a jobject, not a struct
      java_ffi_rtype = &ffi_type_pointer;
      rtype = '*';
    }
    switch(rtype) {
    case 'V': cb->fptr = (*env)->CallVoidMethod; break;
    case 'Z': cb->fptr = (*env)->CallBooleanMethod; break;
    case 'B': cb->fptr = (*env)->CallByteMethod; break;
    case 'S': cb->fptr = (*env)->CallShortMethod; break;
    case 'C': cb->fptr = (*env)->CallCharMethod; break;
    case 'I': cb->fptr = (*env)->CallIntMethod; break;
    case 'J': cb->fptr = (*env)->CallLongMethod; break;
    case 'F': cb->fptr = (*env)->CallFloatMethod; break;
    case 'D': cb->fptr = (*env)->CallDoubleMethod; break;
    default: cb->fptr = (*env)->CallObjectMethod; break;
    }
    status = ffi_prep_cif(&cb->java_cif, java_abi, argc+3, java_ffi_rtype, cb->java_arg_types);
    if (!ffi_error(env, "callback setup (2)", status)) {
      ffi_prep_closure_loc(cb->closure, &cb->cif, callback_dispatch, cb,
                           cb->x_closure);
      return cb;
    }
  }

 failure_cleanup:
  free_callback(env, cb);
  if (throw_type) {
    throwByName(env, throw_type, msg);
  }

  return NULL;
}
Пример #8
0
callback*
create_callback(JNIEnv* env, jobject obj, jobject method,
                jobjectArray param_types, jclass return_type,
                callconv_t calling_convention, jint options,
                jstring encoding) {
  jboolean direct = options & CB_OPTION_DIRECT;
  jboolean in_dll = options & CB_OPTION_IN_DLL;
  callback* cb;
  ffi_abi abi = FFI_DEFAULT_ABI;
  ffi_abi java_abi = FFI_DEFAULT_ABI;
  ffi_type* ffi_rtype;
  ffi_status status;
  jsize argc;
  JavaVM* vm;
  int rtype;
  char msg[MSG_SIZE];
  int i;
  int cvt = 0;
  const char* throw_type = NULL;
  const char* throw_msg = NULL;

  if ((*env)->GetJavaVM(env, &vm) != JNI_OK) {
    throwByName(env, EUnsatisfiedLink, "Can't get Java VM to create native callback");
    return NULL;
  }
  argc = (*env)->GetArrayLength(env, param_types);

  cb = (callback *)malloc(sizeof(callback));
  cb->closure = ffi_closure_alloc(sizeof(ffi_closure), &cb->x_closure);
  cb->saved_x_closure = cb->x_closure;
  cb->object = (*env)->NewWeakGlobalRef(env, obj);
  cb->methodID = (*env)->FromReflectedMethod(env, method);

  cb->vm = vm;
  cb->arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * argc);
  cb->java_arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * (argc + 3));
  cb->arg_jtypes = (char*)malloc(sizeof(char) * argc);
  cb->conversion_flags = (int *)malloc(sizeof(int) * argc);
  cb->rflag = CVT_DEFAULT;
  cb->arg_classes = (jobject*)malloc(sizeof(jobject) * argc);
 
  cb->direct = direct;
  cb->java_arg_types[0] = cb->java_arg_types[1] = cb->java_arg_types[2] = &ffi_type_pointer;
  cb->encoding = newCStringUTF8(env, encoding);

  for (i=0;i < argc;i++) {
    int jtype;
    jclass cls = (*env)->GetObjectArrayElement(env, param_types, i);
    if ((cb->conversion_flags[i] = get_conversion_flag(env, cls)) != CVT_DEFAULT) {
      cb->arg_classes[i] = (*env)->NewWeakGlobalRef(env, cls);
      cvt = 1;
    }
    else {
      cb->arg_classes[i] = NULL;
    }

    jtype = get_jtype(env, cls);
    if (jtype == -1) {
      snprintf(msg, sizeof(msg), "Unsupported callback argument at index %d", i);
      throw_type = EIllegalArgument;
      throw_msg = msg;
      goto failure_cleanup;
    }
    cb->arg_jtypes[i] = (char)jtype;
    cb->java_arg_types[i+3] = cb->arg_types[i] = get_ffi_type(env, cls, cb->arg_jtypes[i]);
    if (!cb->java_arg_types[i+3]) {
      goto failure_cleanup;
    }
    if (cb->conversion_flags[i] == CVT_NATIVE_MAPPED
        || cb->conversion_flags[i] == CVT_POINTER_TYPE
        || cb->conversion_flags[i] == CVT_INTEGER_TYPE) {
      jclass ncls;
      ncls = getNativeType(env, cls);
      jtype = get_jtype(env, ncls);
      if (jtype == -1) {
        snprintf(msg, sizeof(msg), "Unsupported NativeMapped callback argument native type at argument %d", i);
        throw_type = EIllegalArgument;
        throw_msg = msg;
        goto failure_cleanup;
      }
      cb->arg_jtypes[i] = (char)jtype;
      cb->java_arg_types[i+3] = &ffi_type_pointer;
      cb->arg_types[i] = get_ffi_type(env, ncls, cb->arg_jtypes[i]);
      if (!cb->arg_types[i]) {
        goto failure_cleanup;
      }
    }

    // Java callback method is called using varargs, so promote floats to 
    // double where appropriate for the platform
    if (cb->arg_types[i]->type == FFI_TYPE_FLOAT) {
      cb->java_arg_types[i+3] = &ffi_type_double;
      cb->conversion_flags[i] = CVT_FLOAT;
      cvt = 1;
    }
    else if (cb->java_arg_types[i+3]->type == FFI_TYPE_STRUCT) {
      // All callback structure arguments are passed as a jobject
      cb->java_arg_types[i+3] = &ffi_type_pointer;
    }
  }
  if (!direct || !cvt) {
    free(cb->conversion_flags);
    cb->conversion_flags = NULL;
    free(cb->arg_classes);
    cb->arg_classes = NULL;
  }
  if (direct) {
    cb->rflag = get_conversion_flag(env, return_type);
    if (cb->rflag == CVT_NATIVE_MAPPED
        || cb->rflag == CVT_INTEGER_TYPE
        || cb->rflag == CVT_POINTER_TYPE) {
      return_type = getNativeType(env, return_type);
    }
  }

#if defined(_WIN32) && !defined(_WIN64) && !defined(_WIN32_WCE)
  if (calling_convention == CALLCONV_STDCALL) {
    abi = FFI_STDCALL;
  }
  // Calling into Java on win32 *always* uses stdcall
  java_abi = FFI_STDCALL;
#endif // _WIN32

  rtype = get_jtype(env, return_type);
  if (rtype == -1) {
    throw_type = EIllegalArgument;
    throw_msg = "Unsupported callback return type";
    goto failure_cleanup;
  }
  ffi_rtype = get_ffi_rtype(env, return_type, (char)rtype);
  if (!ffi_rtype) {
    throw_type = EIllegalArgument;
    throw_msg = "Error in callback return type";
    goto failure_cleanup;
  }
  status = ffi_prep_cif(&cb->cif, abi, argc, ffi_rtype, cb->arg_types);
  if (!ffi_error(env, "callback setup", status)) {
    ffi_type* java_ffi_rtype = ffi_rtype;

    if (cb->rflag == CVT_STRUCTURE_BYVAL
        || cb->rflag == CVT_NATIVE_MAPPED
        || cb->rflag == CVT_POINTER_TYPE
        || cb->rflag == CVT_INTEGER_TYPE) {
      // Java method returns a jobject, not a struct
      java_ffi_rtype = &ffi_type_pointer;
      rtype = '*';
    }
    switch(rtype) {
#define OFFSETOF(ENV,METHOD) ((size_t)((char *)&(*(ENV))->METHOD - (char *)(*(ENV))))
    case 'V': cb->fptr_offset = OFFSETOF(env, CallVoidMethod); break;
    case 'Z': cb->fptr_offset = OFFSETOF(env, CallBooleanMethod); break;
    case 'B': cb->fptr_offset = OFFSETOF(env, CallByteMethod); break;
    case 'S': cb->fptr_offset = OFFSETOF(env, CallShortMethod); break;
    case 'C': cb->fptr_offset = OFFSETOF(env, CallCharMethod); break;
    case 'I': cb->fptr_offset = OFFSETOF(env, CallIntMethod); break;
    case 'J': cb->fptr_offset = OFFSETOF(env, CallLongMethod); break;
    case 'F': cb->fptr_offset = OFFSETOF(env, CallFloatMethod); break;
    case 'D': cb->fptr_offset = OFFSETOF(env, CallDoubleMethod); break;
    default: cb->fptr_offset = OFFSETOF(env, CallObjectMethod); break;
    }
    status = ffi_prep_cif_var(&cb->java_cif, java_abi, 2, argc+3, java_ffi_rtype, cb->java_arg_types);
    if (!ffi_error(env, "callback setup (2)", status)) {
      ffi_prep_closure_loc(cb->closure, &cb->cif, callback_dispatch, cb,
                           cb->x_closure);
#ifdef DLL_FPTRS
      // Find an available function pointer and assign it
      if (in_dll) {
        for (i=0;i < DLL_FPTRS;i++) {
          if (fn[i] == NULL) {
            fn[i] = cb->x_closure;
            cb->x_closure = dll_fptrs[i];
            break;
          }
        }
        if (i == DLL_FPTRS) {
          throw_type = EOutOfMemory;
          throw_msg = "No more DLL callback slots available";
          goto failure_cleanup;
        }
      }
#endif
      return cb;
    }
  }

 failure_cleanup:
  free_callback(env, cb);
  if (throw_type) {
    throwByName(env, throw_type, throw_msg);
  }

  return NULL;
}