diff -r b758351d191f -r cc9b7e14412b web/lib/arch/osx/jcc/sources/jcc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/arch/osx/jcc/sources/jcc.cpp Tue May 25 02:43:45 2010 +0200 @@ -0,0 +1,690 @@ +/* + * 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 +#ifdef linux +#include +#endif + +#include +#include "structmember.h" + +#include "JObject.h" +#include "JCCEnv.h" +#include "macros.h" + +_DLL_EXPORT JCCEnv *env; + + +/* JCCEnv */ + +class t_jccenv { +public: + PyObject_HEAD + JCCEnv *env; +}; + +static void t_jccenv_dealloc(t_jccenv *self); +static PyObject *t_jccenv_attachCurrentThread(PyObject *self, PyObject *args); +static PyObject *t_jccenv_detachCurrentThread(PyObject *self); +static PyObject *t_jccenv_isCurrentThreadAttached(PyObject *self); +static PyObject *t_jccenv_strhash(PyObject *self, PyObject *arg); +static PyObject *t_jccenv__dumpRefs(PyObject *self, + PyObject *args, PyObject *kwds); +static PyObject *t_jccenv__get_jni_version(PyObject *self, void *data); +static PyObject *t_jccenv__get_java_version(PyObject *self, void *data); + +static PyGetSetDef t_jccenv_properties[] = { + { "jni_version", (getter) t_jccenv__get_jni_version, NULL, NULL, NULL }, + { "java_version", (getter) t_jccenv__get_java_version, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL } +}; + +static PyMemberDef t_jccenv_members[] = { + { NULL, 0, 0, 0, NULL } +}; + +static PyMethodDef t_jccenv_methods[] = { + { "attachCurrentThread", (PyCFunction) t_jccenv_attachCurrentThread, + METH_VARARGS, NULL }, + { "detachCurrentThread", (PyCFunction) t_jccenv_detachCurrentThread, + METH_NOARGS, NULL }, + { "isCurrentThreadAttached", (PyCFunction) t_jccenv_isCurrentThreadAttached, + METH_NOARGS, NULL }, + { "strhash", (PyCFunction) t_jccenv_strhash, + METH_O, NULL }, + { "_dumpRefs", (PyCFunction) t_jccenv__dumpRefs, + METH_VARARGS | METH_KEYWORDS, NULL }, + { NULL, NULL, 0, NULL } +}; + +PyTypeObject JCCEnv$$Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "jcc.JCCEnv", /* tp_name */ + sizeof(t_jccenv), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)t_jccenv_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "JCCEnv", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + t_jccenv_methods, /* tp_methods */ + t_jccenv_members, /* tp_members */ + t_jccenv_properties, /* tp_getset */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +static void t_jccenv_dealloc(t_jccenv *self) +{ + self->ob_type->tp_free((PyObject *) self); +} + +static void add_option(char *name, char *value, JavaVMOption *option) +{ + char *buf = new char[strlen(name) + strlen(value) + 1]; + + sprintf(buf, "%s%s", name, value); + option->optionString = buf; +} + +#ifdef _jcc_lib +static void add_paths(char *name, char *p0, char *p1, JavaVMOption *option) +{ +#if defined(_MSC_VER) || defined(__WIN32) + char pathsep = ';'; +#else + char pathsep = ':'; +#endif + char *buf = new char[strlen(name) + strlen(p0) + strlen(p1) + 4]; + + sprintf(buf, "%s%s%c%s", name, p0, pathsep, p1); + option->optionString = buf; +} +#endif + + +static PyObject *t_jccenv_attachCurrentThread(PyObject *self, PyObject *args) +{ + char *name = NULL; + int asDaemon = 0, result; + JNIEnv *jenv = NULL; + + if (!PyArg_ParseTuple(args, "|si", &name, &asDaemon)) + return NULL; + + JavaVMAttachArgs attach = { + JNI_VERSION_1_4, name, NULL + }; + + if (asDaemon) + result = env->vm->AttachCurrentThreadAsDaemon((void **) &jenv, &attach); + else + result = env->vm->AttachCurrentThread((void **) &jenv, &attach); + + env->set_vm_env(jenv); + + return PyInt_FromLong(result); +} + +static PyObject *t_jccenv_detachCurrentThread(PyObject *self) +{ + int result = env->vm->DetachCurrentThread(); + + env->set_vm_env(NULL); + + return PyInt_FromLong(result); +} + +static PyObject *t_jccenv_isCurrentThreadAttached(PyObject *self) +{ + if (env->get_vm_env() != NULL) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +static PyObject *t_jccenv_strhash(PyObject *self, PyObject *arg) +{ + int hash = PyObject_Hash(arg); + char buffer[10]; + + sprintf(buffer, "%08x", (unsigned int) hash); + return PyString_FromStringAndSize(buffer, 8); +} + +static PyObject *t_jccenv__dumpRefs(PyObject *self, + PyObject *args, PyObject *kwds) +{ + static char *kwnames[] = { + "classes", "values", NULL + }; + int classes = 0, values = 0; + PyObject *result; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwnames, + &classes, &values)) + return NULL; + + if (classes) + result = PyDict_New(); + else + result = PyList_New(env->refs.size()); + + int count = 0; + + for (std::multimap::iterator iter = env->refs.begin(); + iter != env->refs.end(); + iter++) { + if (classes) // return dict of { class name: instance count } + { + char *name = env->getClassName(iter->second.global); + PyObject *key = PyString_FromString(name); + PyObject *value = PyDict_GetItem(result, key); + + if (value == NULL) + value = PyInt_FromLong(1); + else + value = PyInt_FromLong(PyInt_AS_LONG(value) + 1); + + PyDict_SetItem(result, key, value); + Py_DECREF(key); + Py_DECREF(value); + + delete name; + } + else if (values) // return list of (value string, ref count) + { + char *str = env->toString(iter->second.global); + PyObject *key = PyString_FromString(str); + PyObject *value = PyInt_FromLong(iter->second.count); + +#if PY_VERSION_HEX < 0x02040000 + PyList_SET_ITEM(result, count++, Py_BuildValue("(OO)", key, value)); +#else + PyList_SET_ITEM(result, count++, PyTuple_Pack(2, key, value)); +#endif + Py_DECREF(key); + Py_DECREF(value); + + delete str; + } + else // return list of (id hash code, ref count) + { + PyObject *key = PyInt_FromLong(iter->first); + PyObject *value = PyInt_FromLong(iter->second.count); + +#if PY_VERSION_HEX < 0x02040000 + PyList_SET_ITEM(result, count++, Py_BuildValue("(OO)", key, value)); +#else + PyList_SET_ITEM(result, count++, PyTuple_Pack(2, key, value)); +#endif + Py_DECREF(key); + Py_DECREF(value); + } + } + + return result; +} + + +static PyObject *t_jccenv__get_jni_version(PyObject *self, void *data) +{ + return PyInt_FromLong(env->getJNIVersion()); +} + +static PyObject *t_jccenv__get_java_version(PyObject *self, void *data) +{ + return env->fromJString(env->getJavaVersion(), 1); +} + +_DLL_EXPORT PyObject *getVMEnv(PyObject *self) +{ + if (env->vm != NULL) + { + t_jccenv *jccenv = (t_jccenv *) JCCEnv$$Type.tp_alloc(&JCCEnv$$Type, 0); + jccenv->env = env; + + return (PyObject *) jccenv; + } + + Py_RETURN_NONE; +} + +#ifdef _jcc_lib +static void registerNatives(JNIEnv *vm_env); +#endif + +_DLL_EXPORT PyObject *initJCC(PyObject *module) +{ + static int _once_only = 1; + + if (_once_only) + { + PyEval_InitThreads(); + INSTALL_TYPE(JCCEnv, module); + + if (env == NULL) + env = new JCCEnv(NULL, NULL); + + _once_only = 0; + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + +_DLL_EXPORT PyObject *initVM(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwnames[] = { + "classpath", "initialheap", "maxheap", "maxstack", + "vmargs", NULL + }; + char *classpath = NULL; + char *initialheap = NULL, *maxheap = NULL, *maxstack = NULL; + char *vmargs = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzzzz", kwnames, + &classpath, + &initialheap, &maxheap, &maxstack, + &vmargs)) + return NULL; + + if (env->vm) + { + PyObject *module_cp = NULL; + + if (initialheap || maxheap || maxstack || vmargs) + { + PyErr_SetString(PyExc_ValueError, + "JVM is already running, options are ineffective"); + return NULL; + } + + if (classpath == NULL && self != NULL) + { + module_cp = PyObject_GetAttrString(self, "CLASSPATH"); + if (module_cp != NULL) + classpath = PyString_AsString(module_cp); + } + + if (classpath && classpath[0]) + env->setClassPath(classpath); + + Py_XDECREF(module_cp); + + return getVMEnv(self); + } + else + { + JavaVMInitArgs vm_args; + JavaVMOption vm_options[32]; + JNIEnv *vm_env; + JavaVM *vm; + unsigned int nOptions = 0; + PyObject *module_cp = NULL; + + vm_args.version = JNI_VERSION_1_4; + JNI_GetDefaultJavaVMInitArgs(&vm_args); + + if (classpath == NULL && self != NULL) + { + module_cp = PyObject_GetAttrString(self, "CLASSPATH"); + if (module_cp != NULL) + classpath = PyString_AsString(module_cp); + } + +#ifdef _jcc_lib + PyObject *jcc = PyImport_ImportModule("jcc"); + PyObject *cp = PyObject_GetAttrString(jcc, "CLASSPATH"); + + if (classpath) + add_paths("-Djava.class.path=", PyString_AsString(cp), classpath, + &vm_options[nOptions++]); + else + add_option("-Djava.class.path=", PyString_AsString(cp), + &vm_options[nOptions++]); + + Py_DECREF(cp); + Py_DECREF(jcc); +#else + if (classpath) + add_option("-Djava.class.path=", classpath, + &vm_options[nOptions++]); +#endif + + Py_XDECREF(module_cp); + + if (initialheap) + add_option("-Xms", initialheap, &vm_options[nOptions++]); + if (maxheap) + add_option("-Xmx", maxheap, &vm_options[nOptions++]); + if (maxstack) + add_option("-Xss", maxstack, &vm_options[nOptions++]); + + if (vmargs) + { + char *buf = strdup(vmargs); + char *sep = ","; + char *option; + + for (option = strtok(buf, sep); option; option = strtok(NULL, sep)) + { + if (nOptions < sizeof(vm_options) / sizeof(JavaVMOption)) + add_option("", option, &vm_options[nOptions++]); + else + { + free(buf); + for (unsigned int i = 0; i < nOptions; i++) + delete vm_options[i].optionString; + PyErr_Format(PyExc_ValueError, "Too many options (> %d)", + nOptions); + return NULL; + } + } + free(buf); + } + + //vm_options[nOptions++].optionString = "-verbose:gc"; + //vm_options[nOptions++].optionString = "-Xcheck:jni"; + + vm_args.nOptions = nOptions; + vm_args.ignoreUnrecognized = JNI_FALSE; + vm_args.options = vm_options; + + if (JNI_CreateJavaVM(&vm, (void **) &vm_env, &vm_args) < 0) + { + for (unsigned int i = 0; i < nOptions; i++) + delete vm_options[i].optionString; + + PyErr_Format(PyExc_ValueError, + "An error occurred while creating Java VM"); + return NULL; + } + + env->set_vm(vm, vm_env); + + for (unsigned int i = 0; i < nOptions; i++) + delete vm_options[i].optionString; + + t_jccenv *jccenv = (t_jccenv *) JCCEnv$$Type.tp_alloc(&JCCEnv$$Type, 0); + jccenv->env = env; + +#ifdef _jcc_lib + registerNatives(vm_env); +#endif + + return (PyObject *) jccenv; + } +} + +extern "C" { + +#ifdef _jcc_lib + static void raise_error(JNIEnv *vm_env, const char *message) + { + jclass cls = vm_env->FindClass("org/apache/jcc/PythonException"); + vm_env->ThrowNew(cls, message); + } + + JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) + { + JNIEnv *vm_env; + + if (!vm->GetEnv((void **) &vm_env, JNI_VERSION_1_4)) + env = new JCCEnv(vm, vm_env); + + registerNatives(vm_env); + + return JNI_VERSION_1_4; + } + + JNIEXPORT void JNICALL Java_org_apache_jcc_PythonVM_init(JNIEnv *vm_env, jobject self, jstring programName, jobjectArray args) + { + const char *str = vm_env->GetStringUTFChars(programName, JNI_FALSE); +#ifdef linux + char buf[32]; + + // load python runtime for other .so modules to link (such as _time.so) + sprintf(buf, "libpython%d.%d.so", PY_MAJOR_VERSION, PY_MINOR_VERSION); + dlopen(buf, RTLD_NOW | RTLD_GLOBAL); +#endif + + Py_SetProgramName((char *) str); + + PyEval_InitThreads(); + Py_Initialize(); + + if (args) + { + int argc = vm_env->GetArrayLength(args); + char **argv = (char **) calloc(argc + 1, sizeof(char *)); + + argv[0] = (char *) str; + for (int i = 0; i < argc; i++) { + jstring arg = (jstring) vm_env->GetObjectArrayElement(args, i); + argv[i + 1] = (char *) vm_env->GetStringUTFChars(arg, JNI_FALSE); + } + + PySys_SetArgv(argc + 1, argv); + + for (int i = 0; i < argc; i++) { + jstring arg = (jstring) vm_env->GetObjectArrayElement(args, i); + vm_env->ReleaseStringUTFChars(arg, argv[i + 1]); + } + free(argv); + } + else + PySys_SetArgv(1, (char **) &str); + + vm_env->ReleaseStringUTFChars(programName, str); + PyEval_ReleaseLock(); + } + + JNIEXPORT jobject JNICALL Java_org_apache_jcc_PythonVM_instantiate(JNIEnv *vm_env, jobject self, jstring moduleName, jstring className) + { + PythonGIL gil(vm_env); + + const char *modStr = vm_env->GetStringUTFChars(moduleName, JNI_FALSE); + PyObject *module = + PyImport_ImportModule((char *) modStr); // python 2.4 cast + + vm_env->ReleaseStringUTFChars(moduleName, modStr); + + if (!module) + { + raise_error(vm_env, "import failed"); + return NULL; + } + + const char *clsStr = vm_env->GetStringUTFChars(className, JNI_FALSE); + PyObject *cls = + PyObject_GetAttrString(module, (char *) clsStr); // python 2.4 cast + PyObject *obj; + jobject jobj; + + vm_env->ReleaseStringUTFChars(className, clsStr); + Py_DECREF(module); + + if (!cls) + { + raise_error(vm_env, "class not found"); + return NULL; + } + + obj = PyObject_CallFunctionObjArgs(cls, NULL); + Py_DECREF(cls); + + if (!obj) + { + raise_error(vm_env, "instantiation failed"); + return NULL; + } + + PyObject *cObj = PyObject_GetAttrString(obj, "_jobject"); + + if (!cObj) + { + raise_error(vm_env, "instance does not proxy a java object"); + Py_DECREF(obj); + + return NULL; + } + + jobj = (jobject) PyCObject_AsVoidPtr(cObj); + Py_DECREF(cObj); + + jobj = vm_env->NewLocalRef(jobj); + Py_DECREF(obj); + + return jobj; + } +#endif + + void JNICALL PythonException_getErrorInfo(JNIEnv *vm_env, jobject self) + { + PythonGIL gil(vm_env); + + if (!PyErr_Occurred()) + return; + + PyObject *type, *value, *tb, *errorName; + jclass jcls = vm_env->GetObjectClass(self); + + PyErr_Fetch(&type, &value, &tb); + + errorName = PyObject_GetAttrString(type, "__name__"); + if (errorName != NULL) + { + jfieldID fid = + vm_env->GetFieldID(jcls, "errorName", "Ljava/lang/String;"); + jstring str = env->fromPyString(errorName); + + vm_env->SetObjectField(self, fid, str); + vm_env->DeleteLocalRef(str); + Py_DECREF(errorName); + } + + if (value != NULL) + { + PyObject *message = PyObject_Str(value); + + if (message != NULL) + { + jfieldID fid = + vm_env->GetFieldID(jcls, "message", "Ljava/lang/String;"); + jstring str = env->fromPyString(message); + + vm_env->SetObjectField(self, fid, str); + vm_env->DeleteLocalRef(str); + Py_DECREF(message); + } + } + + PyObject *module = NULL, *cls = NULL, *stringIO = NULL, *result = NULL; + PyObject *_stderr = PySys_GetObject("stderr"); + if (!_stderr) + goto err; + + module = PyImport_ImportModule("cStringIO"); + if (!module) + goto err; + + cls = PyObject_GetAttrString(module, "StringIO"); + Py_DECREF(module); + if (!cls) + goto err; + + stringIO = PyObject_CallObject(cls, NULL); + Py_DECREF(cls); + if (!stringIO) + goto err; + + Py_INCREF(_stderr); + PySys_SetObject("stderr", stringIO); + + PyErr_Restore(type, value, tb); + PyErr_Print(); + + result = PyObject_CallMethod(stringIO, "getvalue", NULL); + Py_DECREF(stringIO); + + if (result != NULL) + { + jfieldID fid = + vm_env->GetFieldID(jcls, "traceback", "Ljava/lang/String;"); + jstring str = env->fromPyString(result); + + vm_env->SetObjectField(self, fid, str); + vm_env->DeleteLocalRef(str); + Py_DECREF(result); + } + + PySys_SetObject("stderr", _stderr); + Py_DECREF(_stderr); + + return; + + err: + PyErr_Restore(type, value, tb); + } + + void JNICALL PythonException_clear(JNIEnv *vm_env, jobject self) + { + PythonGIL gil(vm_env); + PyErr_Clear(); + } +}; + +#ifdef _jcc_lib +static void registerNatives(JNIEnv *vm_env) +{ + jclass cls = vm_env->FindClass("org/apache/jcc/PythonException"); + JNINativeMethod methods[] = { + { "getErrorInfo", "()V", (void *) PythonException_getErrorInfo }, + { "clear", "()V", (void *) PythonException_clear }, + }; + + vm_env->RegisterNatives(cls, methods, 2); +} +#endif