web/lib/arch/osx/jcc/sources/JCCEnv.cpp
changeset 29 cc9b7e14412b
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
       
     1 /*
       
     2  *   Licensed under the Apache License, Version 2.0 (the "License");
       
     3  *   you may not use this file except in compliance with the License.
       
     4  *   You may obtain a copy of the License at
       
     5  *
       
     6  *       http://www.apache.org/licenses/LICENSE-2.0
       
     7  *
       
     8  *   Unless required by applicable law or agreed to in writing, software
       
     9  *   distributed under the License is distributed on an "AS IS" BASIS,
       
    10  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    11  *   See the License for the specific language governing permissions and
       
    12  *   limitations under the License.
       
    13  */
       
    14 
       
    15 #include <map>
       
    16 #include <string.h>
       
    17 #include <jni.h>
       
    18 
       
    19 #include "JCCEnv.h"
       
    20 
       
    21 
       
    22 #if defined(_MSC_VER) || defined(__WIN32)
       
    23 _DLL_EXPORT DWORD VM_ENV = 0;
       
    24 #else
       
    25 pthread_key_t JCCEnv::VM_ENV = (pthread_key_t) NULL;
       
    26 #endif
       
    27 
       
    28 #if defined(_MSC_VER) || defined(__WIN32)
       
    29 
       
    30 static CRITICAL_SECTION *mutex = NULL;
       
    31 
       
    32 class lock {
       
    33 public:
       
    34     lock() {
       
    35         EnterCriticalSection(mutex);
       
    36     }
       
    37     virtual ~lock() {
       
    38         LeaveCriticalSection(mutex);
       
    39     }
       
    40 };
       
    41 
       
    42 #else
       
    43 
       
    44 static pthread_mutex_t *mutex = NULL;
       
    45 
       
    46 class lock {
       
    47 public:
       
    48     lock() {
       
    49         pthread_mutex_lock(mutex);
       
    50     }
       
    51     virtual ~lock() {
       
    52         pthread_mutex_unlock(mutex);
       
    53     }
       
    54 };
       
    55 
       
    56 #endif
       
    57 
       
    58 JCCEnv::JCCEnv(JavaVM *vm, JNIEnv *vm_env)
       
    59 {
       
    60 #if defined(_MSC_VER) || defined(__WIN32)
       
    61     if (!mutex)
       
    62     {
       
    63         mutex = new CRITICAL_SECTION();
       
    64         InitializeCriticalSection(mutex);
       
    65     }
       
    66 #else
       
    67     if (!mutex)
       
    68     {
       
    69         mutex = new pthread_mutex_t();
       
    70         pthread_mutex_init(mutex, NULL);
       
    71     }
       
    72 #endif
       
    73 
       
    74     if (vm)
       
    75         set_vm(vm, vm_env);
       
    76     else
       
    77         this->vm = NULL;
       
    78 }
       
    79 
       
    80 void JCCEnv::set_vm(JavaVM *vm, JNIEnv *vm_env)
       
    81 {
       
    82     this->vm = vm;
       
    83     set_vm_env(vm_env);
       
    84 
       
    85     _sys = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/System"));
       
    86     _obj = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/Object"));
       
    87 #ifdef _jcc_lib
       
    88     _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("org/apache/jcc/PythonException"));
       
    89 #else
       
    90     _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/RuntimeException"));
       
    91 #endif
       
    92     _mids = new jmethodID[max_mid];
       
    93 
       
    94     _mids[mid_sys_identityHashCode] =
       
    95         vm_env->GetStaticMethodID(_sys, "identityHashCode",
       
    96                                   "(Ljava/lang/Object;)I");
       
    97     _mids[mid_sys_setProperty] =
       
    98         vm_env->GetStaticMethodID(_sys, "setProperty",
       
    99                                   "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
       
   100     _mids[mid_sys_getProperty] =
       
   101         vm_env->GetStaticMethodID(_sys, "getProperty",
       
   102                                   "(Ljava/lang/String;)Ljava/lang/String;");
       
   103     _mids[mid_obj_toString] =
       
   104         vm_env->GetMethodID(_obj, "toString",
       
   105                             "()Ljava/lang/String;");
       
   106     _mids[mid_obj_hashCode] =
       
   107         vm_env->GetMethodID(_obj, "hashCode",
       
   108                             "()I");
       
   109     _mids[mid_obj_getClass] =
       
   110         vm_env->GetMethodID(_obj, "getClass",
       
   111                             "()Ljava/lang/Class;");
       
   112 
       
   113     _mids[mid_iterator_next] =
       
   114         vm_env->GetMethodID(vm_env->FindClass("java/util/Iterator"),
       
   115                             "next", "()Ljava/lang/Object;");
       
   116     _mids[mid_enumeration_nextElement] =
       
   117         vm_env->GetMethodID(vm_env->FindClass("java/util/Enumeration"),
       
   118                             "nextElement", "()Ljava/lang/Object;");
       
   119 }
       
   120 
       
   121 #if defined(_MSC_VER) || defined(__WIN32)
       
   122 
       
   123 void JCCEnv::set_vm_env(JNIEnv *vm_env)
       
   124 {
       
   125     if (!VM_ENV)
       
   126         VM_ENV = TlsAlloc();
       
   127     TlsSetValue(VM_ENV, (LPVOID) vm_env);
       
   128 }
       
   129 
       
   130 #else
       
   131 
       
   132 void JCCEnv::set_vm_env(JNIEnv *vm_env)
       
   133 {
       
   134     if (!VM_ENV)
       
   135         pthread_key_create(&VM_ENV, NULL);
       
   136     pthread_setspecific(VM_ENV, (void *) vm_env);
       
   137 }
       
   138 
       
   139 #endif
       
   140 
       
   141 jint JCCEnv::getJNIVersion() const
       
   142 {
       
   143     return get_vm_env()->GetVersion();
       
   144 }
       
   145 
       
   146 jstring JCCEnv::getJavaVersion() const
       
   147 {
       
   148     return (jstring)
       
   149         callStaticObjectMethod(_sys, _mids[mid_sys_getProperty],
       
   150                                get_vm_env()->NewStringUTF("java.version"));
       
   151 }
       
   152 
       
   153 jobject JCCEnv::iteratorNext(jobject obj) const
       
   154 {
       
   155     return callObjectMethod(obj, _mids[mid_iterator_next]);
       
   156 }
       
   157 
       
   158 jobject JCCEnv::enumerationNext(jobject obj) const
       
   159 {
       
   160     return callObjectMethod(obj, _mids[mid_enumeration_nextElement]);
       
   161 }
       
   162 
       
   163 jclass JCCEnv::findClass(const char *className) const
       
   164 {
       
   165     jclass cls = NULL;
       
   166 
       
   167     if (vm)
       
   168     {
       
   169         JNIEnv *vm_env = get_vm_env();
       
   170 
       
   171         if (vm_env)
       
   172             cls = vm_env->FindClass(className);
       
   173 #ifdef PYTHON
       
   174         else
       
   175         {
       
   176             PythonGIL gil;
       
   177 
       
   178             PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first");
       
   179             throw pythonError(NULL);
       
   180         }
       
   181 #else
       
   182         else
       
   183             throw exception(NULL);
       
   184 #endif
       
   185     }
       
   186 #ifdef PYTHON
       
   187     else
       
   188     {
       
   189         PythonGIL gil;
       
   190 
       
   191         PyErr_SetString(PyExc_RuntimeError, "initVM() must be called first");
       
   192         throw pythonError(NULL);
       
   193     }
       
   194 #else
       
   195     else
       
   196         throw exception(NULL);
       
   197 #endif
       
   198 
       
   199     reportException();
       
   200 
       
   201     return cls;
       
   202 }
       
   203 
       
   204 void JCCEnv::registerNatives(jclass cls, JNINativeMethod *methods, int n) const
       
   205 {
       
   206     get_vm_env()->RegisterNatives(cls, methods, n);
       
   207 }
       
   208 
       
   209 jobject JCCEnv::newGlobalRef(jobject obj, int id)
       
   210 {
       
   211     if (obj)
       
   212     {
       
   213         if (id)  /* zero when weak global ref is desired */
       
   214         {
       
   215             lock locked;
       
   216 
       
   217             for (std::multimap<int, countedRef>::iterator iter = refs.find(id);
       
   218                  iter != refs.end();
       
   219                  iter++) {
       
   220                 if (iter->first != id)
       
   221                     break;
       
   222                 if (isSame(obj, iter->second.global))
       
   223                 {
       
   224                     /* If it's in the table but not the same reference,
       
   225                      * it must be a local reference and must be deleted.
       
   226                      */
       
   227                     if (obj != iter->second.global)
       
   228                         get_vm_env()->DeleteLocalRef(obj);
       
   229                         
       
   230                     iter->second.count += 1;
       
   231                     return iter->second.global;
       
   232                 }
       
   233             }
       
   234 
       
   235             JNIEnv *vm_env = get_vm_env();
       
   236             countedRef ref;
       
   237 
       
   238             ref.global = vm_env->NewGlobalRef(obj);
       
   239             ref.count = 1;
       
   240             refs.insert(std::pair<const int, countedRef>(id, ref));
       
   241             vm_env->DeleteLocalRef(obj);
       
   242 
       
   243             return ref.global;
       
   244         }
       
   245         else
       
   246             return (jobject) get_vm_env()->NewWeakGlobalRef(obj);
       
   247     }
       
   248 
       
   249     return NULL;
       
   250 }
       
   251 
       
   252 jobject JCCEnv::deleteGlobalRef(jobject obj, int id)
       
   253 {
       
   254     if (obj)
       
   255     {
       
   256         if (id)  /* zero when obj is weak global ref */
       
   257         {
       
   258             lock locked;
       
   259 
       
   260             for (std::multimap<int, countedRef>::iterator iter = refs.find(id);
       
   261                  iter != refs.end();
       
   262                  iter++) {
       
   263                 if (iter->first != id)
       
   264                     break;
       
   265                 if (isSame(obj, iter->second.global))
       
   266                 {
       
   267                     if (iter->second.count == 1)
       
   268                     {
       
   269                         get_vm_env()->DeleteGlobalRef(iter->second.global);
       
   270                         refs.erase(iter);
       
   271                     }
       
   272                     else
       
   273                         iter->second.count -= 1;
       
   274 
       
   275                     return NULL;
       
   276                 }
       
   277             }
       
   278 
       
   279             printf("deleting non-existent ref: 0x%x\n", id);
       
   280         }
       
   281         else
       
   282             get_vm_env()->DeleteWeakGlobalRef((jweak) obj);
       
   283     }
       
   284 
       
   285     return NULL;
       
   286 }
       
   287 
       
   288 jobject JCCEnv::newObject(jclass (*initializeClass)(), jmethodID **mids,
       
   289                           int m, ...)
       
   290 {
       
   291     jclass cls = (*initializeClass)();
       
   292     JNIEnv *vm_env = get_vm_env();
       
   293     jobject obj;
       
   294 
       
   295     if (vm_env)
       
   296     {
       
   297         va_list ap;
       
   298 
       
   299         va_start(ap, m);
       
   300         obj = vm_env->NewObjectV(cls, (*mids)[m], ap);
       
   301         va_end(ap);
       
   302     }
       
   303 #ifdef PYTHON
       
   304     else
       
   305     {
       
   306         PythonGIL gil;
       
   307 
       
   308         PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first");
       
   309         throw pythonError(NULL);
       
   310     }
       
   311 #else
       
   312     else
       
   313         throw exception(NULL);
       
   314 #endif
       
   315 
       
   316     reportException();
       
   317 
       
   318     return obj;
       
   319 }
       
   320 
       
   321 jobjectArray JCCEnv::newObjectArray(jclass cls, int size)
       
   322 {
       
   323     jobjectArray array = get_vm_env()->NewObjectArray(size, cls, NULL);
       
   324 
       
   325     reportException();
       
   326     return array;
       
   327 }
       
   328 
       
   329 void JCCEnv::setObjectArrayElement(jobjectArray array, int n,
       
   330                                    jobject obj) const
       
   331 {
       
   332     get_vm_env()->SetObjectArrayElement(array, n, obj);
       
   333     reportException();
       
   334 }
       
   335 
       
   336 jobject JCCEnv::getObjectArrayElement(jobjectArray array, int n) const
       
   337 {
       
   338     jobject obj = get_vm_env()->GetObjectArrayElement(array, n);
       
   339 
       
   340     reportException();
       
   341     return obj;
       
   342 }
       
   343 
       
   344 int JCCEnv::getArrayLength(jarray array) const
       
   345 {
       
   346     int len = get_vm_env()->GetArrayLength(array);
       
   347 
       
   348     reportException();
       
   349     return len;
       
   350 }
       
   351 
       
   352 #ifdef PYTHON
       
   353 jclass JCCEnv::getPythonExceptionClass() const
       
   354 {
       
   355     return _thr;
       
   356 }
       
   357 #endif
       
   358 
       
   359 void JCCEnv::reportException() const
       
   360 {
       
   361     JNIEnv *vm_env = get_vm_env();
       
   362     jthrowable throwable = vm_env->ExceptionOccurred();
       
   363 
       
   364     if (throwable)
       
   365     {
       
   366         if (!env->handlers)
       
   367             vm_env->ExceptionDescribe();
       
   368 
       
   369         vm_env->ExceptionClear();
       
   370 
       
   371 #ifdef PYTHON
       
   372         PythonGIL gil;
       
   373 
       
   374         if (PyErr_Occurred())
       
   375         {
       
   376             /* _thr is PythonException ifdef _jcc_lib (shared mode)
       
   377              * if not shared mode, _thr is RuntimeException
       
   378              */
       
   379             jobject cls = (jobject) vm_env->GetObjectClass(throwable);
       
   380 
       
   381             if (vm_env->IsSameObject(cls, _thr))
       
   382                 throw pythonError(throwable);
       
   383         }
       
   384 #endif
       
   385 
       
   386         throw exception(throwable);
       
   387     }
       
   388 }
       
   389 
       
   390 
       
   391 #define DEFINE_CALL(jtype, Type)                                         \
       
   392     jtype JCCEnv::call##Type##Method(jobject obj,                        \
       
   393                                      jmethodID mid, ...) const           \
       
   394     {                                                                    \
       
   395         va_list ap;                                                      \
       
   396         jtype result;                                                    \
       
   397                                                                          \
       
   398         va_start(ap, mid);                                               \
       
   399         result = get_vm_env()->Call##Type##MethodV(obj, mid, ap);        \
       
   400         va_end(ap);                                                      \
       
   401                                                                          \
       
   402         reportException();                                               \
       
   403                                                                          \
       
   404         return result;                                                   \
       
   405     }
       
   406 
       
   407 #define DEFINE_NONVIRTUAL_CALL(jtype, Type)                              \
       
   408     jtype JCCEnv::callNonvirtual##Type##Method(jobject obj, jclass cls,  \
       
   409                                                jmethodID mid, ...) const \
       
   410     {                                                                    \
       
   411         va_list ap;                                                      \
       
   412         jtype result;                                                    \
       
   413                                                                          \
       
   414         va_start(ap, mid);                                               \
       
   415         result = get_vm_env()->CallNonvirtual##Type##MethodV(obj, cls,   \
       
   416                                                              mid, ap);   \
       
   417         va_end(ap);                                                      \
       
   418                                                                          \
       
   419         reportException();                                               \
       
   420                                                                          \
       
   421         return result;                                                   \
       
   422     }
       
   423 
       
   424 #define DEFINE_STATIC_CALL(jtype, Type)                                 \
       
   425     jtype JCCEnv::callStatic##Type##Method(jclass cls,                  \
       
   426                                            jmethodID mid, ...) const    \
       
   427     {                                                                   \
       
   428         va_list ap;                                                     \
       
   429         jtype result;                                                   \
       
   430                                                                         \
       
   431         va_start(ap, mid);                                              \
       
   432         result = get_vm_env()->CallStatic##Type##MethodV(cls, mid, ap); \
       
   433         va_end(ap);                                                     \
       
   434                                                                         \
       
   435         reportException();                                              \
       
   436                                                                         \
       
   437         return result;                                                  \
       
   438     }
       
   439         
       
   440 DEFINE_CALL(jobject, Object)
       
   441 DEFINE_CALL(jboolean, Boolean)
       
   442 DEFINE_CALL(jbyte, Byte)
       
   443 DEFINE_CALL(jchar, Char)
       
   444 DEFINE_CALL(jdouble, Double)
       
   445 DEFINE_CALL(jfloat, Float)
       
   446 DEFINE_CALL(jint, Int)
       
   447 DEFINE_CALL(jlong, Long)
       
   448 DEFINE_CALL(jshort, Short)
       
   449 
       
   450 DEFINE_NONVIRTUAL_CALL(jobject, Object)
       
   451 DEFINE_NONVIRTUAL_CALL(jboolean, Boolean)
       
   452 DEFINE_NONVIRTUAL_CALL(jbyte, Byte)
       
   453 DEFINE_NONVIRTUAL_CALL(jchar, Char)
       
   454 DEFINE_NONVIRTUAL_CALL(jdouble, Double)
       
   455 DEFINE_NONVIRTUAL_CALL(jfloat, Float)
       
   456 DEFINE_NONVIRTUAL_CALL(jint, Int)
       
   457 DEFINE_NONVIRTUAL_CALL(jlong, Long)
       
   458 DEFINE_NONVIRTUAL_CALL(jshort, Short)
       
   459 
       
   460 DEFINE_STATIC_CALL(jobject, Object)
       
   461 DEFINE_STATIC_CALL(jboolean, Boolean)
       
   462 DEFINE_STATIC_CALL(jbyte, Byte)
       
   463 DEFINE_STATIC_CALL(jchar, Char)
       
   464 DEFINE_STATIC_CALL(jdouble, Double)
       
   465 DEFINE_STATIC_CALL(jfloat, Float)
       
   466 DEFINE_STATIC_CALL(jint, Int)
       
   467 DEFINE_STATIC_CALL(jlong, Long)
       
   468 DEFINE_STATIC_CALL(jshort, Short)
       
   469 
       
   470 void JCCEnv::callVoidMethod(jobject obj, jmethodID mid, ...) const
       
   471 {
       
   472     va_list ap;
       
   473 
       
   474     va_start(ap, mid);
       
   475     get_vm_env()->CallVoidMethodV(obj, mid, ap);
       
   476     va_end(ap);
       
   477 
       
   478     reportException();
       
   479 }
       
   480 
       
   481 void JCCEnv::callNonvirtualVoidMethod(jobject obj, jclass cls,
       
   482                                       jmethodID mid, ...) const
       
   483 {
       
   484     va_list ap;
       
   485 
       
   486     va_start(ap, mid);
       
   487     get_vm_env()->CallNonvirtualVoidMethodV(obj, cls, mid, ap);
       
   488     va_end(ap);
       
   489 
       
   490     reportException();
       
   491 }
       
   492 
       
   493 void JCCEnv::callStaticVoidMethod(jclass cls, jmethodID mid, ...) const
       
   494 {
       
   495     va_list ap;
       
   496 
       
   497     va_start(ap, mid);
       
   498     get_vm_env()->CallStaticVoidMethodV(cls, mid, ap);
       
   499     va_end(ap);
       
   500 
       
   501     reportException();
       
   502 }
       
   503 
       
   504 
       
   505 jmethodID JCCEnv::getMethodID(jclass cls, const char *name,
       
   506                               const char *signature) const
       
   507 {
       
   508     jmethodID id = get_vm_env()->GetMethodID(cls, name, signature);
       
   509 
       
   510     reportException();
       
   511 
       
   512     return id;
       
   513 }
       
   514 
       
   515 jfieldID JCCEnv::getFieldID(jclass cls, const char *name,
       
   516                             const char *signature) const
       
   517 {
       
   518     jfieldID id = get_vm_env()->GetFieldID(cls, name, signature);
       
   519 
       
   520     reportException();
       
   521 
       
   522     return id;
       
   523 }
       
   524 
       
   525 
       
   526 jmethodID JCCEnv::getStaticMethodID(jclass cls, const char *name,
       
   527                                     const char *signature) const
       
   528 {
       
   529     jmethodID id = get_vm_env()->GetStaticMethodID(cls, name, signature);
       
   530 
       
   531     reportException();
       
   532 
       
   533     return id;
       
   534 }
       
   535 
       
   536 jobject JCCEnv::getStaticObjectField(jclass cls, const char *name,
       
   537                                      const char *signature) const
       
   538 {
       
   539     JNIEnv *vm_env = get_vm_env();
       
   540     jfieldID id = vm_env->GetStaticFieldID(cls, name, signature);
       
   541 
       
   542     reportException();
       
   543 
       
   544     return vm_env->GetStaticObjectField(cls, id);
       
   545 }
       
   546 
       
   547 #define DEFINE_GET_STATIC_FIELD(jtype, Type, signature)                 \
       
   548     jtype JCCEnv::getStatic##Type##Field(jclass cls,                    \
       
   549                                          const char *name) const        \
       
   550     {                                                                   \
       
   551         JNIEnv *vm_env = get_vm_env();                                  \
       
   552         jfieldID id = vm_env->GetStaticFieldID(cls, name, #signature);  \
       
   553         reportException();                                              \
       
   554         return vm_env->GetStatic##Type##Field(cls, id);                 \
       
   555     }
       
   556 
       
   557 DEFINE_GET_STATIC_FIELD(jboolean, Boolean, Z)
       
   558 DEFINE_GET_STATIC_FIELD(jbyte, Byte, B)
       
   559 DEFINE_GET_STATIC_FIELD(jchar, Char, C)
       
   560 DEFINE_GET_STATIC_FIELD(jdouble, Double, D)
       
   561 DEFINE_GET_STATIC_FIELD(jfloat, Float, F)
       
   562 DEFINE_GET_STATIC_FIELD(jint, Int, I)
       
   563 DEFINE_GET_STATIC_FIELD(jlong, Long, J)
       
   564 DEFINE_GET_STATIC_FIELD(jshort, Short, S)
       
   565 
       
   566 #define DEFINE_GET_FIELD(jtype, Type)                                   \
       
   567     jtype JCCEnv::get##Type##Field(jobject obj, jfieldID id) const      \
       
   568     {                                                                   \
       
   569         jtype value = get_vm_env()->Get##Type##Field(obj, id);          \
       
   570         reportException();                                              \
       
   571         return value;                                                   \
       
   572     }
       
   573 
       
   574 DEFINE_GET_FIELD(jobject, Object)
       
   575 DEFINE_GET_FIELD(jboolean, Boolean)
       
   576 DEFINE_GET_FIELD(jbyte, Byte)
       
   577 DEFINE_GET_FIELD(jchar, Char)
       
   578 DEFINE_GET_FIELD(jdouble, Double)
       
   579 DEFINE_GET_FIELD(jfloat, Float)
       
   580 DEFINE_GET_FIELD(jint, Int)
       
   581 DEFINE_GET_FIELD(jlong, Long)
       
   582 DEFINE_GET_FIELD(jshort, Short)
       
   583 
       
   584 #define DEFINE_SET_FIELD(jtype, Type)                                   \
       
   585     void JCCEnv::set##Type##Field(jobject obj, jfieldID id,             \
       
   586                                   jtype value) const                    \
       
   587     {                                                                   \
       
   588         get_vm_env()->Set##Type##Field(obj, id, value);                 \
       
   589         reportException();                                              \
       
   590     }
       
   591 
       
   592 DEFINE_SET_FIELD(jobject, Object)
       
   593 DEFINE_SET_FIELD(jboolean, Boolean)
       
   594 DEFINE_SET_FIELD(jbyte, Byte)
       
   595 DEFINE_SET_FIELD(jchar, Char)
       
   596 DEFINE_SET_FIELD(jdouble, Double)
       
   597 DEFINE_SET_FIELD(jfloat, Float)
       
   598 DEFINE_SET_FIELD(jint, Int)
       
   599 DEFINE_SET_FIELD(jlong, Long)
       
   600 DEFINE_SET_FIELD(jshort, Short)
       
   601 
       
   602 void JCCEnv::setClassPath(const char *classPath)
       
   603 {
       
   604     JNIEnv *vm_env = get_vm_env();
       
   605     jclass _ucl = (jclass) vm_env->FindClass("java/net/URLClassLoader");
       
   606     jclass _fil = (jclass) vm_env->FindClass("java/io/File");
       
   607     jmethodID mid = vm_env->GetStaticMethodID(_ucl, "getSystemClassLoader",
       
   608                                               "()Ljava/lang/ClassLoader;");
       
   609     jobject classLoader = vm_env->CallStaticObjectMethod(_ucl, mid);
       
   610     jmethodID mf = vm_env->GetMethodID(_fil, "<init>", "(Ljava/lang/String;)V");
       
   611     jmethodID mu = vm_env->GetMethodID(_fil, "toURL", "()Ljava/net/URL;");
       
   612     jmethodID ma = vm_env->GetMethodID(_ucl, "addURL", "(Ljava/net/URL;)V");
       
   613 #ifdef WINDOWS
       
   614     char *pathsep = ";";
       
   615 #else
       
   616     char *pathsep = ":";
       
   617 #endif
       
   618     char *path = strdup(classPath);
       
   619 
       
   620     for (char *cp = strtok(path, pathsep);
       
   621          cp != NULL;
       
   622          cp = strtok(NULL, pathsep)) {
       
   623         jstring string = vm_env->NewStringUTF(cp);
       
   624         jobject file = vm_env->NewObject(_fil, mf, string);
       
   625         jobject url = vm_env->CallObjectMethod(file, mu);
       
   626 
       
   627         vm_env->CallVoidMethod(classLoader, ma, url);
       
   628     }
       
   629     free(path);
       
   630 }
       
   631 
       
   632 jstring JCCEnv::fromUTF(const char *bytes) const
       
   633 {
       
   634     jstring str = get_vm_env()->NewStringUTF(bytes);
       
   635 
       
   636     reportException();
       
   637 
       
   638     return str;
       
   639 }
       
   640 
       
   641 char *JCCEnv::toUTF(jstring str) const
       
   642 {
       
   643     JNIEnv *vm_env = get_vm_env();
       
   644     int len = vm_env->GetStringUTFLength(str);
       
   645     char *bytes = new char[len + 1];
       
   646     jboolean isCopy = 0;
       
   647     const char *utf = vm_env->GetStringUTFChars(str, &isCopy);
       
   648 
       
   649     if (!bytes)
       
   650         return NULL;
       
   651 
       
   652     memcpy(bytes, utf, len);
       
   653     bytes[len] = '\0';
       
   654 
       
   655     vm_env->ReleaseStringUTFChars(str, utf);
       
   656 
       
   657     return bytes;
       
   658 }
       
   659 
       
   660 char *JCCEnv::toString(jobject obj) const
       
   661 {
       
   662     return obj
       
   663         ? toUTF((jstring) callObjectMethod(obj, _mids[mid_obj_toString]))
       
   664         : NULL;
       
   665 }
       
   666 
       
   667 char *JCCEnv::getClassName(jobject obj) const
       
   668 {
       
   669     return obj
       
   670         ? toString(callObjectMethod(obj, _mids[mid_obj_getClass]))
       
   671         : NULL;
       
   672 }
       
   673 
       
   674 #ifdef PYTHON
       
   675 
       
   676 jstring JCCEnv::fromPyString(PyObject *object) const
       
   677 {
       
   678     if (object == Py_None)
       
   679         return NULL;
       
   680 
       
   681     if (PyUnicode_Check(object))
       
   682     {
       
   683         if (sizeof(Py_UNICODE) == sizeof(jchar))
       
   684         {
       
   685             jchar *buf = (jchar *) PyUnicode_AS_UNICODE(object);
       
   686             jsize len = (jsize) PyUnicode_GET_SIZE(object);
       
   687 
       
   688             return get_vm_env()->NewString(buf, len);
       
   689         }
       
   690         else
       
   691         {
       
   692             jsize len = PyUnicode_GET_SIZE(object);
       
   693             Py_UNICODE *pchars = PyUnicode_AS_UNICODE(object);
       
   694             jchar *jchars = new jchar[len];
       
   695             jstring str;
       
   696 
       
   697             for (int i = 0; i < len; i++)
       
   698                 jchars[i] = (jchar) pchars[i];
       
   699 
       
   700             str = get_vm_env()->NewString(jchars, len);
       
   701             delete jchars;
       
   702 
       
   703             return str;
       
   704         }
       
   705     }
       
   706     else if (PyString_Check(object))
       
   707         return fromUTF(PyString_AS_STRING(object));
       
   708     else
       
   709     {
       
   710         PyObject *tuple = Py_BuildValue("(sO)", "expected a string", object);
       
   711 
       
   712         PyErr_SetObject(PyExc_TypeError, tuple);
       
   713         Py_DECREF(tuple);
       
   714 
       
   715         return NULL;
       
   716     }
       
   717 }
       
   718 
       
   719 PyObject *JCCEnv::fromJString(jstring js, int delete_local_ref) const
       
   720 {
       
   721     if (!js)
       
   722         Py_RETURN_NONE;
       
   723 
       
   724     JNIEnv *vm_env = get_vm_env();
       
   725     PyObject *string;
       
   726 
       
   727     if (sizeof(Py_UNICODE) == sizeof(jchar))
       
   728     {
       
   729         jboolean isCopy;
       
   730         const jchar *buf = vm_env->GetStringChars(js, &isCopy);
       
   731         jsize len = vm_env->GetStringLength(js);
       
   732 
       
   733         string = PyUnicode_FromUnicode((const Py_UNICODE *) buf, len);
       
   734         vm_env->ReleaseStringChars(js, buf);
       
   735     }
       
   736     else
       
   737     {
       
   738         jsize len = vm_env->GetStringLength(js);
       
   739 
       
   740         string = PyUnicode_FromUnicode(NULL, len);
       
   741         if (string)
       
   742         {
       
   743             jboolean isCopy;
       
   744             const jchar *jchars = vm_env->GetStringChars(js, &isCopy);
       
   745             Py_UNICODE *pchars = PyUnicode_AS_UNICODE(string);
       
   746 
       
   747             for (int i = 0; i < len; i++)
       
   748                 pchars[i] = (Py_UNICODE) jchars[i];
       
   749         
       
   750             vm_env->ReleaseStringChars(js, jchars);
       
   751         }
       
   752     }
       
   753 
       
   754     if (delete_local_ref)
       
   755         vm_env->DeleteLocalRef((jobject) js);
       
   756 
       
   757     return string;
       
   758 }
       
   759 
       
   760 
       
   761 /* may be called from finalizer thread which has no vm_env thread local */
       
   762 void JCCEnv::finalizeObject(JNIEnv *jenv, PyObject *obj)
       
   763 {
       
   764     PythonGIL gil;
       
   765 
       
   766     set_vm_env(jenv);
       
   767     Py_DECREF(obj);
       
   768 }
       
   769 
       
   770 #endif /* PYTHON */