diff -r b758351d191f -r cc9b7e14412b web/lib/arch/osx/jcc/sources/JCCEnv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/arch/osx/jcc/sources/JCCEnv.cpp Tue May 25 02:43:45 2010 +0200 @@ -0,0 +1,770 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "JCCEnv.h" + + +#if defined(_MSC_VER) || defined(__WIN32) +_DLL_EXPORT DWORD VM_ENV = 0; +#else +pthread_key_t JCCEnv::VM_ENV = (pthread_key_t) NULL; +#endif + +#if defined(_MSC_VER) || defined(__WIN32) + +static CRITICAL_SECTION *mutex = NULL; + +class lock { +public: + lock() { + EnterCriticalSection(mutex); + } + virtual ~lock() { + LeaveCriticalSection(mutex); + } +}; + +#else + +static pthread_mutex_t *mutex = NULL; + +class lock { +public: + lock() { + pthread_mutex_lock(mutex); + } + virtual ~lock() { + pthread_mutex_unlock(mutex); + } +}; + +#endif + +JCCEnv::JCCEnv(JavaVM *vm, JNIEnv *vm_env) +{ +#if defined(_MSC_VER) || defined(__WIN32) + if (!mutex) + { + mutex = new CRITICAL_SECTION(); + InitializeCriticalSection(mutex); + } +#else + if (!mutex) + { + mutex = new pthread_mutex_t(); + pthread_mutex_init(mutex, NULL); + } +#endif + + if (vm) + set_vm(vm, vm_env); + else + this->vm = NULL; +} + +void JCCEnv::set_vm(JavaVM *vm, JNIEnv *vm_env) +{ + this->vm = vm; + set_vm_env(vm_env); + + _sys = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/System")); + _obj = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/Object")); +#ifdef _jcc_lib + _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("org/apache/jcc/PythonException")); +#else + _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/RuntimeException")); +#endif + _mids = new jmethodID[max_mid]; + + _mids[mid_sys_identityHashCode] = + vm_env->GetStaticMethodID(_sys, "identityHashCode", + "(Ljava/lang/Object;)I"); + _mids[mid_sys_setProperty] = + vm_env->GetStaticMethodID(_sys, "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); + _mids[mid_sys_getProperty] = + vm_env->GetStaticMethodID(_sys, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;"); + _mids[mid_obj_toString] = + vm_env->GetMethodID(_obj, "toString", + "()Ljava/lang/String;"); + _mids[mid_obj_hashCode] = + vm_env->GetMethodID(_obj, "hashCode", + "()I"); + _mids[mid_obj_getClass] = + vm_env->GetMethodID(_obj, "getClass", + "()Ljava/lang/Class;"); + + _mids[mid_iterator_next] = + vm_env->GetMethodID(vm_env->FindClass("java/util/Iterator"), + "next", "()Ljava/lang/Object;"); + _mids[mid_enumeration_nextElement] = + vm_env->GetMethodID(vm_env->FindClass("java/util/Enumeration"), + "nextElement", "()Ljava/lang/Object;"); +} + +#if defined(_MSC_VER) || defined(__WIN32) + +void JCCEnv::set_vm_env(JNIEnv *vm_env) +{ + if (!VM_ENV) + VM_ENV = TlsAlloc(); + TlsSetValue(VM_ENV, (LPVOID) vm_env); +} + +#else + +void JCCEnv::set_vm_env(JNIEnv *vm_env) +{ + if (!VM_ENV) + pthread_key_create(&VM_ENV, NULL); + pthread_setspecific(VM_ENV, (void *) vm_env); +} + +#endif + +jint JCCEnv::getJNIVersion() const +{ + return get_vm_env()->GetVersion(); +} + +jstring JCCEnv::getJavaVersion() const +{ + return (jstring) + callStaticObjectMethod(_sys, _mids[mid_sys_getProperty], + get_vm_env()->NewStringUTF("java.version")); +} + +jobject JCCEnv::iteratorNext(jobject obj) const +{ + return callObjectMethod(obj, _mids[mid_iterator_next]); +} + +jobject JCCEnv::enumerationNext(jobject obj) const +{ + return callObjectMethod(obj, _mids[mid_enumeration_nextElement]); +} + +jclass JCCEnv::findClass(const char *className) const +{ + jclass cls = NULL; + + if (vm) + { + JNIEnv *vm_env = get_vm_env(); + + if (vm_env) + cls = vm_env->FindClass(className); +#ifdef PYTHON + else + { + PythonGIL gil; + + PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first"); + throw pythonError(NULL); + } +#else + else + throw exception(NULL); +#endif + } +#ifdef PYTHON + else + { + PythonGIL gil; + + PyErr_SetString(PyExc_RuntimeError, "initVM() must be called first"); + throw pythonError(NULL); + } +#else + else + throw exception(NULL); +#endif + + reportException(); + + return cls; +} + +void JCCEnv::registerNatives(jclass cls, JNINativeMethod *methods, int n) const +{ + get_vm_env()->RegisterNatives(cls, methods, n); +} + +jobject JCCEnv::newGlobalRef(jobject obj, int id) +{ + if (obj) + { + if (id) /* zero when weak global ref is desired */ + { + lock locked; + + for (std::multimap::iterator iter = refs.find(id); + iter != refs.end(); + iter++) { + if (iter->first != id) + break; + if (isSame(obj, iter->second.global)) + { + /* If it's in the table but not the same reference, + * it must be a local reference and must be deleted. + */ + if (obj != iter->second.global) + get_vm_env()->DeleteLocalRef(obj); + + iter->second.count += 1; + return iter->second.global; + } + } + + JNIEnv *vm_env = get_vm_env(); + countedRef ref; + + ref.global = vm_env->NewGlobalRef(obj); + ref.count = 1; + refs.insert(std::pair(id, ref)); + vm_env->DeleteLocalRef(obj); + + return ref.global; + } + else + return (jobject) get_vm_env()->NewWeakGlobalRef(obj); + } + + return NULL; +} + +jobject JCCEnv::deleteGlobalRef(jobject obj, int id) +{ + if (obj) + { + if (id) /* zero when obj is weak global ref */ + { + lock locked; + + for (std::multimap::iterator iter = refs.find(id); + iter != refs.end(); + iter++) { + if (iter->first != id) + break; + if (isSame(obj, iter->second.global)) + { + if (iter->second.count == 1) + { + get_vm_env()->DeleteGlobalRef(iter->second.global); + refs.erase(iter); + } + else + iter->second.count -= 1; + + return NULL; + } + } + + printf("deleting non-existent ref: 0x%x\n", id); + } + else + get_vm_env()->DeleteWeakGlobalRef((jweak) obj); + } + + return NULL; +} + +jobject JCCEnv::newObject(jclass (*initializeClass)(), jmethodID **mids, + int m, ...) +{ + jclass cls = (*initializeClass)(); + JNIEnv *vm_env = get_vm_env(); + jobject obj; + + if (vm_env) + { + va_list ap; + + va_start(ap, m); + obj = vm_env->NewObjectV(cls, (*mids)[m], ap); + va_end(ap); + } +#ifdef PYTHON + else + { + PythonGIL gil; + + PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first"); + throw pythonError(NULL); + } +#else + else + throw exception(NULL); +#endif + + reportException(); + + return obj; +} + +jobjectArray JCCEnv::newObjectArray(jclass cls, int size) +{ + jobjectArray array = get_vm_env()->NewObjectArray(size, cls, NULL); + + reportException(); + return array; +} + +void JCCEnv::setObjectArrayElement(jobjectArray array, int n, + jobject obj) const +{ + get_vm_env()->SetObjectArrayElement(array, n, obj); + reportException(); +} + +jobject JCCEnv::getObjectArrayElement(jobjectArray array, int n) const +{ + jobject obj = get_vm_env()->GetObjectArrayElement(array, n); + + reportException(); + return obj; +} + +int JCCEnv::getArrayLength(jarray array) const +{ + int len = get_vm_env()->GetArrayLength(array); + + reportException(); + return len; +} + +#ifdef PYTHON +jclass JCCEnv::getPythonExceptionClass() const +{ + return _thr; +} +#endif + +void JCCEnv::reportException() const +{ + JNIEnv *vm_env = get_vm_env(); + jthrowable throwable = vm_env->ExceptionOccurred(); + + if (throwable) + { + if (!env->handlers) + vm_env->ExceptionDescribe(); + + vm_env->ExceptionClear(); + +#ifdef PYTHON + PythonGIL gil; + + if (PyErr_Occurred()) + { + /* _thr is PythonException ifdef _jcc_lib (shared mode) + * if not shared mode, _thr is RuntimeException + */ + jobject cls = (jobject) vm_env->GetObjectClass(throwable); + + if (vm_env->IsSameObject(cls, _thr)) + throw pythonError(throwable); + } +#endif + + throw exception(throwable); + } +} + + +#define DEFINE_CALL(jtype, Type) \ + jtype JCCEnv::call##Type##Method(jobject obj, \ + jmethodID mid, ...) const \ + { \ + va_list ap; \ + jtype result; \ + \ + va_start(ap, mid); \ + result = get_vm_env()->Call##Type##MethodV(obj, mid, ap); \ + va_end(ap); \ + \ + reportException(); \ + \ + return result; \ + } + +#define DEFINE_NONVIRTUAL_CALL(jtype, Type) \ + jtype JCCEnv::callNonvirtual##Type##Method(jobject obj, jclass cls, \ + jmethodID mid, ...) const \ + { \ + va_list ap; \ + jtype result; \ + \ + va_start(ap, mid); \ + result = get_vm_env()->CallNonvirtual##Type##MethodV(obj, cls, \ + mid, ap); \ + va_end(ap); \ + \ + reportException(); \ + \ + return result; \ + } + +#define DEFINE_STATIC_CALL(jtype, Type) \ + jtype JCCEnv::callStatic##Type##Method(jclass cls, \ + jmethodID mid, ...) const \ + { \ + va_list ap; \ + jtype result; \ + \ + va_start(ap, mid); \ + result = get_vm_env()->CallStatic##Type##MethodV(cls, mid, ap); \ + va_end(ap); \ + \ + reportException(); \ + \ + return result; \ + } + +DEFINE_CALL(jobject, Object) +DEFINE_CALL(jboolean, Boolean) +DEFINE_CALL(jbyte, Byte) +DEFINE_CALL(jchar, Char) +DEFINE_CALL(jdouble, Double) +DEFINE_CALL(jfloat, Float) +DEFINE_CALL(jint, Int) +DEFINE_CALL(jlong, Long) +DEFINE_CALL(jshort, Short) + +DEFINE_NONVIRTUAL_CALL(jobject, Object) +DEFINE_NONVIRTUAL_CALL(jboolean, Boolean) +DEFINE_NONVIRTUAL_CALL(jbyte, Byte) +DEFINE_NONVIRTUAL_CALL(jchar, Char) +DEFINE_NONVIRTUAL_CALL(jdouble, Double) +DEFINE_NONVIRTUAL_CALL(jfloat, Float) +DEFINE_NONVIRTUAL_CALL(jint, Int) +DEFINE_NONVIRTUAL_CALL(jlong, Long) +DEFINE_NONVIRTUAL_CALL(jshort, Short) + +DEFINE_STATIC_CALL(jobject, Object) +DEFINE_STATIC_CALL(jboolean, Boolean) +DEFINE_STATIC_CALL(jbyte, Byte) +DEFINE_STATIC_CALL(jchar, Char) +DEFINE_STATIC_CALL(jdouble, Double) +DEFINE_STATIC_CALL(jfloat, Float) +DEFINE_STATIC_CALL(jint, Int) +DEFINE_STATIC_CALL(jlong, Long) +DEFINE_STATIC_CALL(jshort, Short) + +void JCCEnv::callVoidMethod(jobject obj, jmethodID mid, ...) const +{ + va_list ap; + + va_start(ap, mid); + get_vm_env()->CallVoidMethodV(obj, mid, ap); + va_end(ap); + + reportException(); +} + +void JCCEnv::callNonvirtualVoidMethod(jobject obj, jclass cls, + jmethodID mid, ...) const +{ + va_list ap; + + va_start(ap, mid); + get_vm_env()->CallNonvirtualVoidMethodV(obj, cls, mid, ap); + va_end(ap); + + reportException(); +} + +void JCCEnv::callStaticVoidMethod(jclass cls, jmethodID mid, ...) const +{ + va_list ap; + + va_start(ap, mid); + get_vm_env()->CallStaticVoidMethodV(cls, mid, ap); + va_end(ap); + + reportException(); +} + + +jmethodID JCCEnv::getMethodID(jclass cls, const char *name, + const char *signature) const +{ + jmethodID id = get_vm_env()->GetMethodID(cls, name, signature); + + reportException(); + + return id; +} + +jfieldID JCCEnv::getFieldID(jclass cls, const char *name, + const char *signature) const +{ + jfieldID id = get_vm_env()->GetFieldID(cls, name, signature); + + reportException(); + + return id; +} + + +jmethodID JCCEnv::getStaticMethodID(jclass cls, const char *name, + const char *signature) const +{ + jmethodID id = get_vm_env()->GetStaticMethodID(cls, name, signature); + + reportException(); + + return id; +} + +jobject JCCEnv::getStaticObjectField(jclass cls, const char *name, + const char *signature) const +{ + JNIEnv *vm_env = get_vm_env(); + jfieldID id = vm_env->GetStaticFieldID(cls, name, signature); + + reportException(); + + return vm_env->GetStaticObjectField(cls, id); +} + +#define DEFINE_GET_STATIC_FIELD(jtype, Type, signature) \ + jtype JCCEnv::getStatic##Type##Field(jclass cls, \ + const char *name) const \ + { \ + JNIEnv *vm_env = get_vm_env(); \ + jfieldID id = vm_env->GetStaticFieldID(cls, name, #signature); \ + reportException(); \ + return vm_env->GetStatic##Type##Field(cls, id); \ + } + +DEFINE_GET_STATIC_FIELD(jboolean, Boolean, Z) +DEFINE_GET_STATIC_FIELD(jbyte, Byte, B) +DEFINE_GET_STATIC_FIELD(jchar, Char, C) +DEFINE_GET_STATIC_FIELD(jdouble, Double, D) +DEFINE_GET_STATIC_FIELD(jfloat, Float, F) +DEFINE_GET_STATIC_FIELD(jint, Int, I) +DEFINE_GET_STATIC_FIELD(jlong, Long, J) +DEFINE_GET_STATIC_FIELD(jshort, Short, S) + +#define DEFINE_GET_FIELD(jtype, Type) \ + jtype JCCEnv::get##Type##Field(jobject obj, jfieldID id) const \ + { \ + jtype value = get_vm_env()->Get##Type##Field(obj, id); \ + reportException(); \ + return value; \ + } + +DEFINE_GET_FIELD(jobject, Object) +DEFINE_GET_FIELD(jboolean, Boolean) +DEFINE_GET_FIELD(jbyte, Byte) +DEFINE_GET_FIELD(jchar, Char) +DEFINE_GET_FIELD(jdouble, Double) +DEFINE_GET_FIELD(jfloat, Float) +DEFINE_GET_FIELD(jint, Int) +DEFINE_GET_FIELD(jlong, Long) +DEFINE_GET_FIELD(jshort, Short) + +#define DEFINE_SET_FIELD(jtype, Type) \ + void JCCEnv::set##Type##Field(jobject obj, jfieldID id, \ + jtype value) const \ + { \ + get_vm_env()->Set##Type##Field(obj, id, value); \ + reportException(); \ + } + +DEFINE_SET_FIELD(jobject, Object) +DEFINE_SET_FIELD(jboolean, Boolean) +DEFINE_SET_FIELD(jbyte, Byte) +DEFINE_SET_FIELD(jchar, Char) +DEFINE_SET_FIELD(jdouble, Double) +DEFINE_SET_FIELD(jfloat, Float) +DEFINE_SET_FIELD(jint, Int) +DEFINE_SET_FIELD(jlong, Long) +DEFINE_SET_FIELD(jshort, Short) + +void JCCEnv::setClassPath(const char *classPath) +{ + JNIEnv *vm_env = get_vm_env(); + jclass _ucl = (jclass) vm_env->FindClass("java/net/URLClassLoader"); + jclass _fil = (jclass) vm_env->FindClass("java/io/File"); + jmethodID mid = vm_env->GetStaticMethodID(_ucl, "getSystemClassLoader", + "()Ljava/lang/ClassLoader;"); + jobject classLoader = vm_env->CallStaticObjectMethod(_ucl, mid); + jmethodID mf = vm_env->GetMethodID(_fil, "", "(Ljava/lang/String;)V"); + jmethodID mu = vm_env->GetMethodID(_fil, "toURL", "()Ljava/net/URL;"); + jmethodID ma = vm_env->GetMethodID(_ucl, "addURL", "(Ljava/net/URL;)V"); +#ifdef WINDOWS + char *pathsep = ";"; +#else + char *pathsep = ":"; +#endif + char *path = strdup(classPath); + + for (char *cp = strtok(path, pathsep); + cp != NULL; + cp = strtok(NULL, pathsep)) { + jstring string = vm_env->NewStringUTF(cp); + jobject file = vm_env->NewObject(_fil, mf, string); + jobject url = vm_env->CallObjectMethod(file, mu); + + vm_env->CallVoidMethod(classLoader, ma, url); + } + free(path); +} + +jstring JCCEnv::fromUTF(const char *bytes) const +{ + jstring str = get_vm_env()->NewStringUTF(bytes); + + reportException(); + + return str; +} + +char *JCCEnv::toUTF(jstring str) const +{ + JNIEnv *vm_env = get_vm_env(); + int len = vm_env->GetStringUTFLength(str); + char *bytes = new char[len + 1]; + jboolean isCopy = 0; + const char *utf = vm_env->GetStringUTFChars(str, &isCopy); + + if (!bytes) + return NULL; + + memcpy(bytes, utf, len); + bytes[len] = '\0'; + + vm_env->ReleaseStringUTFChars(str, utf); + + return bytes; +} + +char *JCCEnv::toString(jobject obj) const +{ + return obj + ? toUTF((jstring) callObjectMethod(obj, _mids[mid_obj_toString])) + : NULL; +} + +char *JCCEnv::getClassName(jobject obj) const +{ + return obj + ? toString(callObjectMethod(obj, _mids[mid_obj_getClass])) + : NULL; +} + +#ifdef PYTHON + +jstring JCCEnv::fromPyString(PyObject *object) const +{ + if (object == Py_None) + return NULL; + + if (PyUnicode_Check(object)) + { + if (sizeof(Py_UNICODE) == sizeof(jchar)) + { + jchar *buf = (jchar *) PyUnicode_AS_UNICODE(object); + jsize len = (jsize) PyUnicode_GET_SIZE(object); + + return get_vm_env()->NewString(buf, len); + } + else + { + jsize len = PyUnicode_GET_SIZE(object); + Py_UNICODE *pchars = PyUnicode_AS_UNICODE(object); + jchar *jchars = new jchar[len]; + jstring str; + + for (int i = 0; i < len; i++) + jchars[i] = (jchar) pchars[i]; + + str = get_vm_env()->NewString(jchars, len); + delete jchars; + + return str; + } + } + else if (PyString_Check(object)) + return fromUTF(PyString_AS_STRING(object)); + else + { + PyObject *tuple = Py_BuildValue("(sO)", "expected a string", object); + + PyErr_SetObject(PyExc_TypeError, tuple); + Py_DECREF(tuple); + + return NULL; + } +} + +PyObject *JCCEnv::fromJString(jstring js, int delete_local_ref) const +{ + if (!js) + Py_RETURN_NONE; + + JNIEnv *vm_env = get_vm_env(); + PyObject *string; + + if (sizeof(Py_UNICODE) == sizeof(jchar)) + { + jboolean isCopy; + const jchar *buf = vm_env->GetStringChars(js, &isCopy); + jsize len = vm_env->GetStringLength(js); + + string = PyUnicode_FromUnicode((const Py_UNICODE *) buf, len); + vm_env->ReleaseStringChars(js, buf); + } + else + { + jsize len = vm_env->GetStringLength(js); + + string = PyUnicode_FromUnicode(NULL, len); + if (string) + { + jboolean isCopy; + const jchar *jchars = vm_env->GetStringChars(js, &isCopy); + Py_UNICODE *pchars = PyUnicode_AS_UNICODE(string); + + for (int i = 0; i < len; i++) + pchars[i] = (Py_UNICODE) jchars[i]; + + vm_env->ReleaseStringChars(js, jchars); + } + } + + if (delete_local_ref) + vm_env->DeleteLocalRef((jobject) js); + + return string; +} + + +/* may be called from finalizer thread which has no vm_env thread local */ +void JCCEnv::finalizeObject(JNIEnv *jenv, PyObject *obj) +{ + PythonGIL gil; + + set_vm_env(jenv); + Py_DECREF(obj); +} + +#endif /* PYTHON */