Merge "Omaha #4259 clean up pyjclass optimization for inclusion in jep" into omaha_16.1.1
Former-commit-id: 5d1b229924399e16617347162e97e3210608a8f8
This commit is contained in:
commit
64a82afdc9
2 changed files with 171 additions and 218 deletions
|
@ -1,15 +1,15 @@
|
|||
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 c-style: "K&R" -*- */
|
||||
/*
|
||||
/*
|
||||
jep - Java Embedded Python
|
||||
|
||||
Copyright (c) 2004 - 2008 Mike Johnson.
|
||||
Copyright (c) 2004 - 2011 Mike Johnson.
|
||||
|
||||
This file is licenced under the the zlib/libpng License.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
@ -23,15 +23,8 @@
|
|||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
August 2, 2012
|
||||
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
|
||||
Modifications marked and described by 'njensen'
|
||||
*/
|
||||
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
# include "winconfig.h"
|
||||
|
@ -75,21 +68,17 @@ static void pyjclass_dealloc(PyJclass_Object*);
|
|||
|
||||
static jmethodID classGetConstructors = 0;
|
||||
static jmethodID classGetParmTypes = 0;
|
||||
static jmethodID classGetExceptions = 0;
|
||||
|
||||
|
||||
PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
|
||||
PyJclass_Object *pyc = NULL;
|
||||
jobject langClass = NULL;
|
||||
jobjectArray initArray = NULL;
|
||||
PyJobject_Object *pyjobject = NULL;
|
||||
|
||||
// added by njensen
|
||||
int i, k;
|
||||
jobject constructor = NULL;
|
||||
jclass initClass = NULL;
|
||||
jobjectArray parmArray = NULL;
|
||||
int parmLen;
|
||||
PyJobject_Object *pyjobject = NULL;
|
||||
jobject constructor = NULL;
|
||||
jclass initClass = NULL;
|
||||
jobjectArray parmArray = NULL;
|
||||
int i;
|
||||
|
||||
if(PyType_Ready(&PyJclass_Type) < 0)
|
||||
return NULL;
|
||||
|
@ -97,30 +86,30 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
|
|||
pyc = PyObject_NEW(PyJclass_Object, &PyJclass_Type);
|
||||
pyc->initArray = NULL;
|
||||
pyc->pyjobject = pyjob;
|
||||
|
||||
|
||||
pyjobject = (PyJobject_Object *) pyjob;
|
||||
|
||||
(*env)->PushLocalFrame(env, 5);
|
||||
if(process_java_exception(env))
|
||||
return NULL;
|
||||
|
||||
|
||||
// ------------------------------ call Class.getConstructors()
|
||||
|
||||
// well, first call getClass()
|
||||
if(classGetConstructors == 0) {
|
||||
jmethodID methodId;
|
||||
|
||||
|
||||
methodId = (*env)->GetMethodID(env,
|
||||
pyjobject->clazz,
|
||||
"getClass",
|
||||
"()Ljava/lang/Class;");
|
||||
if(process_java_exception(env) || !methodId)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
langClass = (*env)->CallObjectMethod(env, pyjobject->clazz, methodId);
|
||||
if(process_java_exception(env) || !langClass)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
// then, find getContructors()
|
||||
classGetConstructors =
|
||||
(*env)->GetMethodID(env,
|
||||
|
@ -130,8 +119,8 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
|
|||
if(process_java_exception(env) || !classGetConstructors)
|
||||
goto EXIT_ERROR;
|
||||
}
|
||||
|
||||
// then, call method
|
||||
|
||||
// then, call getConstructors()
|
||||
initArray = (jobjectArray) (*env)->CallObjectMethod(env,
|
||||
pyjobject->clazz,
|
||||
classGetConstructors);
|
||||
|
@ -141,158 +130,20 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
|
|||
pyc->initArray = (*env)->NewGlobalRef(env, initArray);
|
||||
pyc->initLen = (*env)->GetArrayLength(env, pyc->initArray);
|
||||
|
||||
// caching below added by njensen
|
||||
pyc->numArgsPerConstructor = malloc(sizeof(int) * pyc->initLen);
|
||||
pyc->constructorArgTypes = (int **) malloc(sizeof(int*) * pyc->initLen);
|
||||
/*
|
||||
* Optimization for faster performance. Cache number of arguments
|
||||
* for each constructor to avoid repeated reflection lookups.
|
||||
*/
|
||||
pyc->numArgsPerInit = malloc(sizeof(int) * pyc->initLen);
|
||||
for(i = 0; i < pyc->initLen; i++) {
|
||||
jmethodID methodId;
|
||||
|
||||
constructor = (*env)->GetObjectArrayElement(env,
|
||||
pyc->initArray,
|
||||
i);
|
||||
if(process_java_exception(env) || !constructor)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
// we need to get the parameters, first
|
||||
initClass = (*env)->GetObjectClass(env, constructor);
|
||||
if(process_java_exception(env) || !initClass)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
// next, get parameters for constructor
|
||||
if(classGetParmTypes == 0) {
|
||||
classGetParmTypes = (*env)->GetMethodID(env,
|
||||
initClass,
|
||||
"getParameterTypes",
|
||||
"()[Ljava/lang/Class;");
|
||||
if(process_java_exception(env) || !classGetParmTypes)
|
||||
goto EXIT_ERROR;
|
||||
}
|
||||
|
||||
parmArray = (jobjectArray) (*env)->CallObjectMethod(env,
|
||||
constructor,
|
||||
classGetParmTypes);
|
||||
if(process_java_exception(env) || !parmArray)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
// okay, we know how many parameters we need.
|
||||
// just discard the constructors with different counts.
|
||||
parmLen = (*env)->GetArrayLength(env, parmArray);
|
||||
pyc->numArgsPerConstructor[i] = parmLen;
|
||||
pyc->constructorArgTypes[i] = malloc(sizeof(int) * parmLen);
|
||||
|
||||
for(k = 0; k < parmLen; k++) {
|
||||
int paramTypeId = -1;
|
||||
jclass pclazz;
|
||||
jobject paramType =
|
||||
(jclass) (*env)->GetObjectArrayElement(env,
|
||||
parmArray,
|
||||
k);
|
||||
|
||||
if(process_java_exception(env) || !paramType)
|
||||
break;
|
||||
|
||||
pclazz = (*env)->GetObjectClass(env, paramType);
|
||||
if(process_java_exception(env) || !pclazz)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
paramTypeId = get_jtype(env, paramType, pclazz);
|
||||
pyc->constructorArgTypes[i][k] = paramTypeId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return pyc;
|
||||
|
||||
EXIT_ERROR:
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
if(pyc)
|
||||
pyjclass_dealloc(pyc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int pyjclass_check(PyObject *obj) {
|
||||
return pyjobject_check(obj) && ((PyJobject_Object *) obj)->pyjclass != NULL;
|
||||
}
|
||||
|
||||
|
||||
static void pyjclass_dealloc(PyJclass_Object *self) {
|
||||
#if USE_DEALLOC
|
||||
int i;
|
||||
JNIEnv *env = pyembed_get_env();
|
||||
if(self->initArray)
|
||||
(*env)->DeleteGlobalRef(env, self->initArray);
|
||||
|
||||
free(self->numArgsPerConstructor);
|
||||
for(i=0; i < self->initLen; i++)
|
||||
{
|
||||
free(self->constructorArgTypes[i]);
|
||||
}
|
||||
free(self->constructorArgTypes);
|
||||
|
||||
PyObject_Del(self);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// call constructor as a method and return pyjobject.
|
||||
PyObject* pyjclass_call(PyJclass_Object *self,
|
||||
PyObject *args,
|
||||
PyObject *keywords) {
|
||||
int initPos = 0;
|
||||
int parmPos = 0;
|
||||
int parmLen = 0;
|
||||
jobjectArray parmArray = NULL;
|
||||
jobjectArray exceptions = NULL;
|
||||
JNIEnv *env;
|
||||
jclass initClass = NULL;
|
||||
jobject constructor = NULL;
|
||||
jvalue *jargs = NULL;
|
||||
int foundArray = 0;
|
||||
PyThreadState *_save;
|
||||
int pyArgLength;
|
||||
|
||||
classCallCount = classCallCount + 1;
|
||||
if(!PyTuple_Check(args)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "args is not a valid tuple");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(keywords != NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Keywords are not supported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env = pyembed_get_env();
|
||||
|
||||
// use a local frame so we don't have to worry too much about references.
|
||||
// make sure if this method errors out, that this is poped off again
|
||||
(*env)->PushLocalFrame(env, 20);
|
||||
if(process_java_exception(env))
|
||||
return NULL;
|
||||
|
||||
|
||||
// njensen changed below to use cached constructor arguments
|
||||
pyArgLength = PyTuple_Size(args);
|
||||
for(initPos = 0; initPos < self->initLen; initPos++) {
|
||||
jmethodID methodId;
|
||||
|
||||
if(self->numArgsPerConstructor[initPos] != pyArgLength)
|
||||
continue;
|
||||
|
||||
constructor = (*env)->GetObjectArrayElement(env,
|
||||
self->initArray,
|
||||
initPos);
|
||||
pyc->initArray,
|
||||
i);
|
||||
if(process_java_exception(env) || !constructor)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
// we need to get the parameters, first
|
||||
|
||||
// we need to get the class java.lang.reflect.Constructor first
|
||||
initClass = (*env)->GetObjectClass(env, constructor);
|
||||
if(process_java_exception(env) || !initClass)
|
||||
goto EXIT_ERROR;
|
||||
|
@ -306,14 +157,114 @@ PyObject* pyjclass_call(PyJclass_Object *self,
|
|||
if(process_java_exception(env) || !classGetParmTypes)
|
||||
goto EXIT_ERROR;
|
||||
}
|
||||
|
||||
parmArray = (jobjectArray) (*env)->CallObjectMethod(env,
|
||||
constructor,
|
||||
classGetParmTypes);
|
||||
if(process_java_exception(env) || !parmArray)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
parmLen = self->numArgsPerConstructor[initPos];
|
||||
|
||||
// now we know how many parameters this constructor receives
|
||||
pyc->numArgsPerInit[i] = (*env)->GetArrayLength(env, parmArray);
|
||||
} // end of optimization
|
||||
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return pyc;
|
||||
|
||||
EXIT_ERROR:
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
if(pyc)
|
||||
pyjclass_dealloc(pyc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int pyjclass_check(PyObject *obj) {
|
||||
return pyjobject_check(obj) && ((PyJobject_Object *) obj)->pyjclass != NULL;
|
||||
}
|
||||
|
||||
|
||||
static void pyjclass_dealloc(PyJclass_Object *self) {
|
||||
#if USE_DEALLOC
|
||||
JNIEnv *env = pyembed_get_env();
|
||||
if(self->initArray)
|
||||
(*env)->DeleteGlobalRef(env, self->initArray);
|
||||
free(self->numArgsPerInit);
|
||||
PyObject_Del(self);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// call constructor as a method and return pyjobject.
|
||||
PyObject* pyjclass_call(PyJclass_Object *self,
|
||||
PyObject *args,
|
||||
PyObject *keywords) {
|
||||
int initPos = 0;
|
||||
int parmPos = 0;
|
||||
int parmLen = 0;
|
||||
jobjectArray parmArray = NULL;
|
||||
JNIEnv *env;
|
||||
jclass initClass = NULL;
|
||||
jobject constructor = NULL;
|
||||
jvalue *jargs = NULL;
|
||||
int foundArray = 0;
|
||||
PyThreadState *_save;
|
||||
Py_ssize_t pyArgLength = 0;
|
||||
|
||||
if(!PyTuple_Check(args)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "args is not a valid tuple");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(keywords != NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Keywords are not supported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env = pyembed_get_env();
|
||||
|
||||
// use a local frame so we don't have to worry too much about references.
|
||||
// make sure if this method errors out, that this is popped off again
|
||||
(*env)->PushLocalFrame(env, 20);
|
||||
if(process_java_exception(env))
|
||||
return NULL;
|
||||
|
||||
pyArgLength = PyTuple_Size(args);
|
||||
for(initPos = 0; initPos < self->initLen; initPos++) {
|
||||
parmLen = self->numArgsPerInit[initPos];
|
||||
// skip constructors that don't match the correct number of args
|
||||
if(parmLen != pyArgLength) {
|
||||
continue;
|
||||
}
|
||||
|
||||
constructor = (*env)->GetObjectArrayElement(env,
|
||||
self->initArray,
|
||||
initPos);
|
||||
if(process_java_exception(env) || !constructor)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
// get the class java.lang.reflect.Constructor first
|
||||
initClass = (*env)->GetObjectClass(env, constructor);
|
||||
if(process_java_exception(env) || !initClass)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
// next, get parameters for constructor
|
||||
if(classGetParmTypes == 0) {
|
||||
classGetParmTypes = (*env)->GetMethodID(env,
|
||||
initClass,
|
||||
"getParameterTypes",
|
||||
"()[Ljava/lang/Class;");
|
||||
if(process_java_exception(env) || !classGetParmTypes)
|
||||
goto EXIT_ERROR;
|
||||
}
|
||||
|
||||
parmArray = (jobjectArray) (*env)->CallObjectMethod(env,
|
||||
constructor,
|
||||
classGetParmTypes);
|
||||
if(process_java_exception(env) || !parmArray)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
// next, find matching constructor for args
|
||||
// the counts match but maybe not the args themselves.
|
||||
jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * parmLen);
|
||||
|
@ -321,21 +272,30 @@ PyObject* pyjclass_call(PyJclass_Object *self,
|
|||
THROW_JEP(env, "Out of memory.");
|
||||
goto EXIT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
for(parmPos = 0; parmPos < parmLen; parmPos++) {
|
||||
PyObject *param = PyTuple_GetItem(args, parmPos);
|
||||
int paramTypeId = self->constructorArgTypes[initPos][parmPos];
|
||||
int paramTypeId = -1;
|
||||
jclass pclazz;
|
||||
jobject paramType =
|
||||
(jclass) (*env)->GetObjectArrayElement(env,
|
||||
parmArray,
|
||||
parmPos);
|
||||
|
||||
|
||||
if(process_java_exception(env) || !paramType)
|
||||
break;
|
||||
|
||||
|
||||
pclazz = (*env)->GetObjectClass(env, paramType);
|
||||
if(process_java_exception(env) || !pclazz)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
paramTypeId = get_jtype(env, paramType, pclazz);
|
||||
if(PyErr_Occurred() || process_java_exception(env))
|
||||
goto EXIT_ERROR;
|
||||
|
||||
if(paramTypeId == JARRAY_ID)
|
||||
foundArray = 1;
|
||||
|
||||
|
||||
// if java and python agree, continue checking
|
||||
if(pyarg_matches_jtype(env, param, paramType, paramTypeId)) {
|
||||
jargs[parmPos] = convert_pyarg_jvalue(env,
|
||||
|
@ -345,28 +305,29 @@ PyObject* pyjclass_call(PyJclass_Object *self,
|
|||
parmPos);
|
||||
if(PyErr_Occurred() || process_java_exception(env))
|
||||
goto EXIT_ERROR;
|
||||
|
||||
continue;
|
||||
|
||||
continue; // continue checking parameters
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
} // for each parameter type
|
||||
|
||||
|
||||
// did they match?
|
||||
if(parmPos == parmLen) {
|
||||
jmethodID methodId = NULL;
|
||||
jobject obj = NULL;
|
||||
PyObject *pobj = NULL;
|
||||
|
||||
|
||||
if(PyErr_Occurred() || process_java_exception(env))
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
// worked out, create new object
|
||||
methodId = (*env)->FromReflectedMethod(env,
|
||||
constructor);
|
||||
if(process_java_exception(env) || !methodId)
|
||||
goto EXIT_ERROR;
|
||||
|
||||
|
||||
Py_UNBLOCK_THREADS;
|
||||
obj = (*env)->NewObjectA(env,
|
||||
((PyJobject_Object* ) self->pyjobject)->clazz,
|
||||
|
@ -375,14 +336,14 @@ PyObject* pyjclass_call(PyJclass_Object *self,
|
|||
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(parmPos = 0; parmPos < parmLen; parmPos++) {
|
||||
|
@ -391,28 +352,30 @@ PyObject* pyjclass_call(PyJclass_Object *self,
|
|||
pyjarray_pin((PyJarray_Object *) param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return pobj;
|
||||
}
|
||||
// we already closed the local frame, so make
|
||||
// sure to delete this local ref.
|
||||
PyMem_Free(jargs);
|
||||
|
||||
// prevent memory leak
|
||||
if(jargs) {
|
||||
PyMem_Free(jargs);
|
||||
}
|
||||
foundArray = 0;
|
||||
} // for each constructor
|
||||
|
||||
|
||||
|
||||
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
PyErr_Format(PyExc_RuntimeError, "Couldn't find matching constructor.");
|
||||
return NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
EXIT_ERROR:
|
||||
if(jargs)
|
||||
PyMem_Free(jargs);
|
||||
|
||||
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 c-style: "K&R" -*- */
|
||||
/*
|
||||
/*
|
||||
jep - Java Embedded Python
|
||||
|
||||
Copyright (c) 2004 - 2008 Mike Johnson.
|
||||
Copyright (c) 2004 - 2011 Mike Johnson.
|
||||
|
||||
This file is licenced under the the zlib/libpng License.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
@ -23,15 +23,8 @@
|
|||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
August 2, 2012
|
||||
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
|
||||
Modifications marked and described by 'njensen'
|
||||
*/
|
||||
|
||||
distribution.
|
||||
*/
|
||||
|
||||
// shut up the compiler
|
||||
#ifdef _POSIX_C_SOURCE
|
||||
|
@ -48,14 +41,11 @@ typedef struct {
|
|||
jobjectArray initArray; /* constructor array */
|
||||
int initLen; /* length of initArray */
|
||||
PyObject *pyjobject; /* pointer to parent */
|
||||
|
||||
int **constructorArgTypes; // added by njensen
|
||||
int *numArgsPerConstructor; // added by njensen
|
||||
int *numArgsPerInit; /* pointer to init arg count */
|
||||
} PyJclass_Object;
|
||||
|
||||
PyJclass_Object* pyjclass_new(JNIEnv*, PyObject*);
|
||||
PyObject* pyjclass_call(PyJclass_Object*, PyObject*, PyObject*);
|
||||
int pyjclass_check(PyObject*);
|
||||
extern long classCallCount;
|
||||
|
||||
#endif // ndef pyjclass
|
||||
|
|
Loading…
Add table
Reference in a new issue