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:
Nate Jensen 2015-03-23 17:28:11 -05:00 committed by Gerrit Code Review
commit 64a82afdc9
2 changed files with 171 additions and 218 deletions

View file

@ -2,7 +2,7 @@
/* /*
jep - Java Embedded Python 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 file is licenced under the the zlib/libpng License.
@ -26,13 +26,6 @@
distribution. distribution.
*/ */
/*
August 2, 2012
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
Modifications marked and described by 'njensen'
*/
#ifdef WIN32 #ifdef WIN32
# include "winconfig.h" # include "winconfig.h"
#endif #endif
@ -75,21 +68,17 @@ static void pyjclass_dealloc(PyJclass_Object*);
static jmethodID classGetConstructors = 0; static jmethodID classGetConstructors = 0;
static jmethodID classGetParmTypes = 0; static jmethodID classGetParmTypes = 0;
static jmethodID classGetExceptions = 0;
PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) { PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
PyJclass_Object *pyc = NULL; PyJclass_Object *pyc = NULL;
jobject langClass = NULL; jobject langClass = NULL;
jobjectArray initArray = NULL; jobjectArray initArray = NULL;
PyJobject_Object *pyjobject = NULL; PyJobject_Object *pyjobject = NULL;
jobject constructor = NULL;
// added by njensen jclass initClass = NULL;
int i, k; jobjectArray parmArray = NULL;
jobject constructor = NULL; int i;
jclass initClass = NULL;
jobjectArray parmArray = NULL;
int parmLen;
if(PyType_Ready(&PyJclass_Type) < 0) if(PyType_Ready(&PyJclass_Type) < 0)
return NULL; return NULL;
@ -131,7 +120,7 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
goto EXIT_ERROR; goto EXIT_ERROR;
} }
// then, call method // then, call getConstructors()
initArray = (jobjectArray) (*env)->CallObjectMethod(env, initArray = (jobjectArray) (*env)->CallObjectMethod(env,
pyjobject->clazz, pyjobject->clazz,
classGetConstructors); classGetConstructors);
@ -141,67 +130,43 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
pyc->initArray = (*env)->NewGlobalRef(env, initArray); pyc->initArray = (*env)->NewGlobalRef(env, initArray);
pyc->initLen = (*env)->GetArrayLength(env, pyc->initArray); pyc->initLen = (*env)->GetArrayLength(env, pyc->initArray);
// caching below added by njensen /*
pyc->numArgsPerConstructor = malloc(sizeof(int) * pyc->initLen); * Optimization for faster performance. Cache number of arguments
pyc->constructorArgTypes = (int **) malloc(sizeof(int*) * pyc->initLen); * for each constructor to avoid repeated reflection lookups.
*/
pyc->numArgsPerInit = malloc(sizeof(int) * pyc->initLen);
for(i = 0; i < pyc->initLen; i++) { for(i = 0; i < pyc->initLen; i++) {
jmethodID methodId; constructor = (*env)->GetObjectArrayElement(env,
pyc->initArray,
constructor = (*env)->GetObjectArrayElement(env, i);
pyc->initArray, if(process_java_exception(env) || !constructor)
i); goto EXIT_ERROR;
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); initClass = (*env)->GetObjectClass(env, constructor);
if(process_java_exception(env) || !initClass) if(process_java_exception(env) || !initClass)
goto EXIT_ERROR; goto EXIT_ERROR;
// next, get parameters for constructor // next, get parameters for constructor
if(classGetParmTypes == 0) { if(classGetParmTypes == 0) {
classGetParmTypes = (*env)->GetMethodID(env, classGetParmTypes = (*env)->GetMethodID(env,
initClass, initClass,
"getParameterTypes", "getParameterTypes",
"()[Ljava/lang/Class;"); "()[Ljava/lang/Class;");
if(process_java_exception(env) || !classGetParmTypes) if(process_java_exception(env) || !classGetParmTypes)
goto EXIT_ERROR; goto EXIT_ERROR;
} }
parmArray = (jobjectArray) (*env)->CallObjectMethod(env,
parmArray = (jobjectArray) (*env)->CallObjectMethod(env, constructor,
constructor, classGetParmTypes);
classGetParmTypes); if(process_java_exception(env) || !parmArray)
if(process_java_exception(env) || !parmArray) goto EXIT_ERROR;
goto EXIT_ERROR;
// okay, we know how many parameters we need. // now we know how many parameters this constructor receives
// just discard the constructors with different counts. pyc->numArgsPerInit[i] = (*env)->GetArrayLength(env, parmArray);
parmLen = (*env)->GetArrayLength(env, parmArray); } // end of optimization
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); (*env)->PopLocalFrame(env, NULL);
return pyc; return pyc;
@ -222,18 +187,10 @@ int pyjclass_check(PyObject *obj) {
static void pyjclass_dealloc(PyJclass_Object *self) { static void pyjclass_dealloc(PyJclass_Object *self) {
#if USE_DEALLOC #if USE_DEALLOC
int i;
JNIEnv *env = pyembed_get_env(); JNIEnv *env = pyembed_get_env();
if(self->initArray) if(self->initArray)
(*env)->DeleteGlobalRef(env, self->initArray); (*env)->DeleteGlobalRef(env, self->initArray);
free(self->numArgsPerInit);
free(self->numArgsPerConstructor);
for(i=0; i < self->initLen; i++)
{
free(self->constructorArgTypes[i]);
}
free(self->constructorArgTypes);
PyObject_Del(self); PyObject_Del(self);
#endif #endif
} }
@ -247,16 +204,14 @@ PyObject* pyjclass_call(PyJclass_Object *self,
int parmPos = 0; int parmPos = 0;
int parmLen = 0; int parmLen = 0;
jobjectArray parmArray = NULL; jobjectArray parmArray = NULL;
jobjectArray exceptions = NULL;
JNIEnv *env; JNIEnv *env;
jclass initClass = NULL; jclass initClass = NULL;
jobject constructor = NULL; jobject constructor = NULL;
jvalue *jargs = NULL; jvalue *jargs = NULL;
int foundArray = 0; int foundArray = 0;
PyThreadState *_save; PyThreadState *_save;
int pyArgLength; Py_ssize_t pyArgLength = 0;
classCallCount = classCallCount + 1;
if(!PyTuple_Check(args)) { if(!PyTuple_Check(args)) {
PyErr_Format(PyExc_RuntimeError, "args is not a valid tuple"); PyErr_Format(PyExc_RuntimeError, "args is not a valid tuple");
return NULL; return NULL;
@ -270,19 +225,18 @@ PyObject* pyjclass_call(PyJclass_Object *self,
env = pyembed_get_env(); env = pyembed_get_env();
// use a local frame so we don't have to worry too much about references. // 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 // make sure if this method errors out, that this is popped off again
(*env)->PushLocalFrame(env, 20); (*env)->PushLocalFrame(env, 20);
if(process_java_exception(env)) if(process_java_exception(env))
return NULL; return NULL;
// njensen changed below to use cached constructor arguments
pyArgLength = PyTuple_Size(args); pyArgLength = PyTuple_Size(args);
for(initPos = 0; initPos < self->initLen; initPos++) { for(initPos = 0; initPos < self->initLen; initPos++) {
jmethodID methodId; parmLen = self->numArgsPerInit[initPos];
// skip constructors that don't match the correct number of args
if(self->numArgsPerConstructor[initPos] != pyArgLength) if(parmLen != pyArgLength) {
continue; continue;
}
constructor = (*env)->GetObjectArrayElement(env, constructor = (*env)->GetObjectArrayElement(env,
self->initArray, self->initArray,
@ -290,9 +244,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(process_java_exception(env) || !constructor) if(process_java_exception(env) || !constructor)
goto EXIT_ERROR; goto EXIT_ERROR;
// get the class java.lang.reflect.Constructor first
// we need to get the parameters, first
initClass = (*env)->GetObjectClass(env, constructor); initClass = (*env)->GetObjectClass(env, constructor);
if(process_java_exception(env) || !initClass) if(process_java_exception(env) || !initClass)
goto EXIT_ERROR; goto EXIT_ERROR;
@ -313,7 +265,6 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(process_java_exception(env) || !parmArray) if(process_java_exception(env) || !parmArray)
goto EXIT_ERROR; goto EXIT_ERROR;
parmLen = self->numArgsPerConstructor[initPos];
// next, find matching constructor for args // next, find matching constructor for args
// the counts match but maybe not the args themselves. // the counts match but maybe not the args themselves.
jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * parmLen); jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * parmLen);
@ -324,7 +275,8 @@ PyObject* pyjclass_call(PyJclass_Object *self,
for(parmPos = 0; parmPos < parmLen; parmPos++) { for(parmPos = 0; parmPos < parmLen; parmPos++) {
PyObject *param = PyTuple_GetItem(args, parmPos); PyObject *param = PyTuple_GetItem(args, parmPos);
int paramTypeId = self->constructorArgTypes[initPos][parmPos]; int paramTypeId = -1;
jclass pclazz;
jobject paramType = jobject paramType =
(jclass) (*env)->GetObjectArrayElement(env, (jclass) (*env)->GetObjectArrayElement(env,
parmArray, parmArray,
@ -333,6 +285,14 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(process_java_exception(env) || !paramType) if(process_java_exception(env) || !paramType)
break; 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) if(paramTypeId == JARRAY_ID)
foundArray = 1; foundArray = 1;
@ -346,7 +306,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(PyErr_Occurred() || process_java_exception(env)) if(PyErr_Occurred() || process_java_exception(env))
goto EXIT_ERROR; goto EXIT_ERROR;
continue; continue; // continue checking parameters
} }
break; break;
@ -355,6 +315,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
// did they match? // did they match?
if(parmPos == parmLen) { if(parmPos == parmLen) {
jmethodID methodId = NULL;
jobject obj = NULL; jobject obj = NULL;
PyObject *pobj = NULL; PyObject *pobj = NULL;
@ -395,9 +356,11 @@ PyObject* pyjclass_call(PyJclass_Object *self,
(*env)->PopLocalFrame(env, NULL); (*env)->PopLocalFrame(env, NULL);
return pobj; return pobj;
} }
// we already closed the local frame, so make
// sure to delete this local ref. // prevent memory leak
PyMem_Free(jargs); if(jargs) {
PyMem_Free(jargs);
}
foundArray = 0; foundArray = 0;
} // for each constructor } // for each constructor

View file

@ -2,7 +2,7 @@
/* /*
jep - Java Embedded Python 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 file is licenced under the the zlib/libpng License.
@ -26,13 +26,6 @@
distribution. distribution.
*/ */
/*
August 2, 2012
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
Modifications marked and described by 'njensen'
*/
// shut up the compiler // shut up the compiler
#ifdef _POSIX_C_SOURCE #ifdef _POSIX_C_SOURCE
# undef _POSIX_C_SOURCE # undef _POSIX_C_SOURCE
@ -48,14 +41,11 @@ typedef struct {
jobjectArray initArray; /* constructor array */ jobjectArray initArray; /* constructor array */
int initLen; /* length of initArray */ int initLen; /* length of initArray */
PyObject *pyjobject; /* pointer to parent */ PyObject *pyjobject; /* pointer to parent */
int *numArgsPerInit; /* pointer to init arg count */
int **constructorArgTypes; // added by njensen
int *numArgsPerConstructor; // added by njensen
} PyJclass_Object; } PyJclass_Object;
PyJclass_Object* pyjclass_new(JNIEnv*, PyObject*); PyJclass_Object* pyjclass_new(JNIEnv*, PyObject*);
PyObject* pyjclass_call(PyJclass_Object*, PyObject*, PyObject*); PyObject* pyjclass_call(PyJclass_Object*, PyObject*, PyObject*);
int pyjclass_check(PyObject*); int pyjclass_check(PyObject*);
extern long classCallCount;
#endif // ndef pyjclass #endif // ndef pyjclass