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
Copyright (c) 2004 - 2008 Mike Johnson.
Copyright (c) 2004 - 2011 Mike Johnson.
This file is licenced under the the zlib/libpng License.
@ -26,13 +26,6 @@
distribution.
*/
/*
August 2, 2012
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
Modifications marked and described by 'njensen'
*/
#ifdef WIN32
# include "winconfig.h"
#endif
@ -75,7 +68,6 @@ 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) {
@ -83,13 +75,10 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
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;
int i;
if(PyType_Ready(&PyJclass_Type) < 0)
return NULL;
@ -131,7 +120,7 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
goto EXIT_ERROR;
}
// then, call method
// then, call getConstructors()
initArray = (jobjectArray) (*env)->CallObjectMethod(env,
pyjobject->clazz,
classGetConstructors);
@ -141,12 +130,12 @@ 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);
@ -154,7 +143,7 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
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;
@ -168,7 +157,6 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
if(process_java_exception(env) || !classGetParmTypes)
goto EXIT_ERROR;
}
parmArray = (jobjectArray) (*env)->CallObjectMethod(env,
constructor,
classGetParmTypes);
@ -176,32 +164,9 @@ PyJclass_Object* pyjclass_new(JNIEnv *env, PyObject *pyjob) {
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;
}
}
// 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;
@ -222,18 +187,10 @@ int pyjclass_check(PyObject *obj) {
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);
free(self->numArgsPerInit);
PyObject_Del(self);
#endif
}
@ -247,16 +204,14 @@ PyObject* pyjclass_call(PyJclass_Object *self,
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;
Py_ssize_t pyArgLength = 0;
classCallCount = classCallCount + 1;
if(!PyTuple_Check(args)) {
PyErr_Format(PyExc_RuntimeError, "args is not a valid tuple");
return NULL;
@ -270,19 +225,18 @@ PyObject* pyjclass_call(PyJclass_Object *self,
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
// make sure if this method errors out, that this is popped 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)
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,
@ -290,9 +244,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(process_java_exception(env) || !constructor)
goto EXIT_ERROR;
// we need to get the parameters, first
// get the class java.lang.reflect.Constructor first
initClass = (*env)->GetObjectClass(env, constructor);
if(process_java_exception(env) || !initClass)
goto EXIT_ERROR;
@ -313,7 +265,6 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(process_java_exception(env) || !parmArray)
goto EXIT_ERROR;
parmLen = self->numArgsPerConstructor[initPos];
// next, find matching constructor for args
// the counts match but maybe not the args themselves.
jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * parmLen);
@ -324,7 +275,8 @@ PyObject* pyjclass_call(PyJclass_Object *self,
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,
@ -333,6 +285,14 @@ PyObject* pyjclass_call(PyJclass_Object *self,
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;
@ -346,7 +306,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
if(PyErr_Occurred() || process_java_exception(env))
goto EXIT_ERROR;
continue;
continue; // continue checking parameters
}
break;
@ -355,6 +315,7 @@ PyObject* pyjclass_call(PyJclass_Object *self,
// did they match?
if(parmPos == parmLen) {
jmethodID methodId = NULL;
jobject obj = NULL;
PyObject *pobj = NULL;
@ -395,9 +356,11 @@ PyObject* pyjclass_call(PyJclass_Object *self,
(*env)->PopLocalFrame(env, NULL);
return pobj;
}
// we already closed the local frame, so make
// sure to delete this local ref.
// prevent memory leak
if(jargs) {
PyMem_Free(jargs);
}
foundArray = 0;
} // for each constructor

View file

@ -2,7 +2,7 @@
/*
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.
@ -26,13 +26,6 @@
distribution.
*/
/*
August 2, 2012
Modified by Raytheon (c) 2012 Raytheon Company. All Rights Reserved.
Modifications marked and described by 'njensen'
*/
// shut up the compiler
#ifdef _POSIX_C_SOURCE
# undef _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