* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / native / vm / VMClassLoader.c
index 395f17f56e50cfcdc2aa3a86d03c259da2aabd42..db996ca16774c9b218ab1e8b4c235cf5478b9314 100644 (file)
@@ -1,9 +1,9 @@
-/* native/vm/VMClassLoader.c - java/lang/VMClassLoader
+/* src/native/vm/VMClassLoader.c - java/lang/VMClassLoader
 
-   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Roman Obermaiser
 
    Changes: Joseph Wenninger
             Christian Thalinger
+            Edwin Steiner
 
-   $Id: VMClassLoader.c 2201 2005-04-03 21:48:11Z twisti $
+   $Id: VMClassLoader.c 4357 2006-01-22 23:33:38Z twisti $
 
 */
 
@@ -37,7 +38,8 @@
 #include <sys/stat.h>
 
 #include "config.h"
-#include "types.h"
+#include "vm/types.h"
+
 #include "mm/memory.h"
 #include "native/jni.h"
 #include "native/native.h"
 #include "native/include/java_security_ProtectionDomain.h"
 #include "native/include/java_util_Vector.h"
 #include "toolbox/logging.h"
+#include "vm/builtin.h"
 #include "vm/class.h"
 #include "vm/classcache.h"
 #include "vm/exceptions.h"
-#include "vm/builtin.h"
+#include "vm/initialize.h"
+#include "vm/linker.h"
 #include "vm/loader.h"
 #include "vm/options.h"
 #include "vm/statistics.h"
 #include "vm/stringlocal.h"
-#include "vm/tables.h"
+#include "vm/suck.h"
+#include "vm/zip.h"
 #include "vm/jit/asmpart.h"
 
 
  * Method:    defineClass
  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;
  */
-JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *this, java_lang_String *name, java_bytearray *buf, s4 off, s4 len, java_security_ProtectionDomain *pd)
+JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name, java_bytearray *data, s4 offset, s4 len, java_security_ProtectionDomain *pd)
 {
        classinfo   *c;
        classinfo   *r;
        classbuffer *cb;
        utf         *utfname;
 
-       if ((off < 0) || (len < 0) || ((off + len) > buf->header.size)) {
-               *exceptionptr =
-                       new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
-               return NULL;
-       }
+       /* check if data was passed */
 
-       /* thrown by SUN jdk */
-       if (len == 0) {
-               *exceptionptr = new_classformaterror(NULL, "Truncated class file");
+       if (data == NULL) {
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
-       if (!name) {
-               /* XXX we have to support this case (name is read from classbuffer) */
-               log_text("defineClass(name == NULL,...) is not implemented, yet");
-               *exceptionptr = new_nullpointerexception();
+       /* check the indexes passed */
+
+       if ((offset < 0) || (len < 0) || ((offset + len) > data->header.size)) {
+               exceptions_throw_arrayindexoutofboundsexception();
                return NULL;
        }
 
-       /* convert '.' to '/' in java string */
-       utfname = javastring_toutf(name, true);
-       
-       /* check if this class has already been defined */
-       c = classcache_lookup_defined((java_objectheader *) this, utfname);
-       if (c)
-               return (java_lang_Class *) c;
+       if (name) {
+               /* convert '.' to '/' in java string */
+
+               utfname = javastring_toutf(name, true);
+               
+               /* check if this class has already been defined */
+
+               c = classcache_lookup_defined_or_initiated((java_objectheader *) cl, utfname);
+               if (c) {
+                       *exceptionptr =
+                               exceptions_new_linkageerror("duplicate class definition: ",c);
+                       return NULL;
+               }
+       } 
+       else {
+               utfname = NULL;
+       }
 
        /* create a new classinfo struct */
-       c = class_create_classinfo(utfname);
 
-#if defined(USE_THREADS)
-       /* enter a monitor on the class */
-       builtin_monitorenter((java_objectheader *) c);
-#endif
+       c = class_create_classinfo(utfname);
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        /* measure time */
 
        if (getloadingtime)
@@ -117,13 +123,13 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE
 
        cb = NEW(classbuffer);
        cb->class = c;
-       cb->size = len;
-       cb->data = (u1 *) &buf->data[off];
-       cb->pos = cb->data - 1;
+       cb->size  = len;
+       cb->data  = (u1 *) &data->data[offset];
+       cb->pos   = cb->data;
 
        /* preset the defining classloader */
 
-       c->classloader = (java_objectheader *) this;
+       c->classloader = (java_objectheader *) cl;
 
        /* load the class from this buffer */
 
@@ -133,25 +139,17 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE
 
        FREE(cb, classbuffer);
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        /* measure time */
 
        if (getloadingtime)
                loadingtime_stop();
 #endif
 
-#if defined(USE_THREADS)
-       /* leave the monitor */
-
-       builtin_monitorexit((java_objectheader *) c);
-#endif
-
-       /* exception? return! */
-
        if (!r) {
-               /* If return value is NULL, we had a problem and the class is not     */
+               /* If return value is NULL, we had a problem and the class is not   */
                /* loaded. */
-               /* now free the allocated memory, otherwise we could ran into a DOS */
+               /* now free the allocated memory, otherwise we could run into a DOS */
 
                class_free(c);
 
@@ -160,9 +158,18 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE
 
        /* set ProtectionDomain */
 
-       c->pd = pd;
+       c->object.pd = pd;
+
+       /* Store the newly defined class in the class cache. This call also       */
+       /* checks whether a class of the same name has already been defined by    */
+       /* the same defining loader, and if so, replaces the newly created class  */
+       /* by the one defined earlier.                                            */
+       /* Important: The classinfo given to classcache_store_defined must be     */
+       /*            fully prepared because another thread may return this       */
+       /*            pointer after the lookup at to top of this function         */
+       /*            directly after the class cache lock has been released.      */
 
-       use_class_as_object(c);
+       c = classcache_store_defined(c);
 
        return (java_lang_Class *) c;
 }
@@ -171,29 +178,47 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE
 /*
  * Class:     java/lang/VMClassLoader
  * Method:    getPrimitiveClass
- * Signature: (Ljava/lang/String;)Ljava/lang/Class;
+ * Signature: (C)Ljava/lang/Class;
  */
-JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, java_lang_String *type)
+JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, s4 type)
 {
        classinfo *c;
-       utf       *u;
-
-       u = javastring_toutf(type, false);
 
-       /* illegal primitive classname specified */
+       /* get primitive class */
 
-       if (!u) {
+       switch (type) {
+       case 'I':
+               c = primitivetype_table[PRIMITIVETYPE_INT].class_primitive;
+               break;
+       case 'J':
+               c = primitivetype_table[PRIMITIVETYPE_LONG].class_primitive;
+               break;
+       case 'F':
+               c = primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive;
+               break;
+       case 'D':
+               c = primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive;
+               break;
+       case 'B':
+               c = primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive;
+               break;
+       case 'C':
+               c = primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive;
+               break;
+       case 'S':
+               c = primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive;
+               break;
+       case 'Z':
+               c = primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive;
+               break;
+       case 'V':
+               c = primitivetype_table[PRIMITIVETYPE_VOID].class_primitive;
+               break;
+       default:
                *exceptionptr = new_exception(string_java_lang_ClassNotFoundException);
-               return NULL;
+               c = NULL;
        }
 
-       /* get primitive class */
-
-       if (!load_class_bootstrap(u, &c) || !initialize_class(c))
-               return NULL;
-
-       use_class_as_object(c);
-
        return (java_lang_Class *) c;
 }
 
@@ -210,14 +235,14 @@ JNIEXPORT void JNICALL Java_java_lang_VMClassLoader_resolveClass(JNIEnv *env, jc
        ci = (classinfo *) c;
 
        if (!ci) {
-               *exceptionptr = new_nullpointerexception();
+               exceptions_throw_nullpointerexception();
                return;
        }
 
        /* link the class */
 
-       if (!ci->linked)
-               link_class(ci);
+       if (!(ci->state & CLASS_LINKED))
+               (void) link_class(ci);
 
        return;
 }
@@ -234,7 +259,7 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv
        utf *u;
 
        if (!name) {
-               *exceptionptr = new_nullpointerexception();
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
@@ -244,7 +269,7 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv
 
        /* load class */
 
-       if (!load_class_bootstrap(u,&c))
+       if (!(c = load_class_bootstrap(u)))
                goto exception;
 
        /* resolve class -- if requested */
@@ -252,8 +277,6 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv
 /*     if (resolve) { */
                if (!link_class(c))
                        goto exception;
-
-               use_class_as_object(c);
 /*     } */
 
        return (java_lang_Class *) c;
@@ -284,17 +307,18 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv
  */
 JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResources(JNIEnv *env, jclass clazz, java_lang_String *name)
 {
-       jobject           o;
-       methodinfo       *m;
-       java_lang_String *path;
-       classpath_info   *cpi;
-       utf              *utfname;
-       char             *charname;
-       char             *tmppath;
-       s4                namelen;
-       s4                pathlen;
-       struct stat       buf;
-       jboolean          ret;
+       jobject               o;
+       methodinfo           *m;
+       java_lang_String     *path;
+       list_classpath_entry *lce;
+       utf                  *utfname;
+       char                 *charname;
+       char                 *end;
+       char                 *tmppath;
+       s4                    namelen;
+       s4                    pathlen;
+       struct stat           buf;
+       jboolean              ret;
 
        /* get the resource name as utf string */
 
@@ -305,6 +329,16 @@ JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResour
 
        utf_sprint(charname, utfname);
 
+       /* search for `.class', if found remove it */
+
+       if ((end = strstr(charname, ".class"))) {
+               *end = '\0';
+               utfname = utf_new_char(charname);
+
+               /* little hack, but it should work */
+               *end = '.';
+       }
+
        /* new Vector() */
 
        o = native_new_and_init(class_java_util_Vector);
@@ -312,10 +346,10 @@ JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResour
        if (!o)
                return NULL;
 
-       /* get v.add() method */
+       /* get Vector.add() method */
 
        m = class_resolveclassmethod(class_java_util_Vector,
-                                                                utf_new_char("add"),
+                                                                utf_add,
                                                                 utf_new_char("(Ljava/lang/Object;)Z"),
                                                                 NULL,
                                                                 true);
@@ -323,57 +357,46 @@ JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResour
        if (!m)
                return NULL;
 
-       for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) {
+       for (lce = list_first(list_classpath_entries); lce != NULL;
+                lce = list_next(list_classpath_entries, lce)) {
                /* clear path pointer */
                path = NULL;
 
-#if defined(USE_ZLIB)
-               if (cpi->type == CLASSPATH_ARCHIVE) {
-
-#if defined(USE_THREADS)
-                       /* enter a monitor on zip/jar archives */
-
-                       builtin_monitorenter((java_objectheader *) cpi);
-#endif
+#if defined(ENABLE_ZLIB)
+               if (lce->type == CLASSPATH_ARCHIVE) {
 
-                       if (cacao_locate(cpi->uf, utfname) == UNZ_OK) {
-                               pathlen = strlen("jar:file://") + cpi->pathlen + strlen("!/") +
+                       if (zip_find(lce, utfname)) {
+                               pathlen = strlen("jar:file://") + lce->pathlen + strlen("!/") +
                                        namelen + strlen("0");
 
                                tmppath = MNEW(char, pathlen);
 
-                               sprintf(tmppath, "jar:file://%s!/%s", cpi->path, charname);
+                               sprintf(tmppath, "jar:file://%s!/%s", lce->path, charname);
                                path = javastring_new_char(tmppath),
 
                                MFREE(tmppath, char, pathlen);
                        }
 
-#if defined(USE_THREADS)
-                       /* leave the monitor */
-
-                       builtin_monitorexit((java_objectheader *) cpi);
-#endif
-
                } else {
-#endif /* defined(USE_ZLIB) */
-                       pathlen = strlen("file://") + cpi->pathlen + namelen + strlen("0");
+#endif /* defined(ENABLE_ZLIB) */
+                       pathlen = strlen("file://") + lce->pathlen + namelen + strlen("0");
 
                        tmppath = MNEW(char, pathlen);
 
-                       sprintf(tmppath, "file://%s%s", cpi->path, charname);
+                       sprintf(tmppath, "file://%s%s", lce->path, charname);
 
                        if (stat(tmppath + strlen("file://") - 1, &buf) == 0)
                                path = javastring_new_char(tmppath),
 
                        MFREE(tmppath, char, pathlen);
-#if defined(USE_ZLIB)
+#if defined(ENABLE_ZLIB)
                }
 #endif
 
                /* if a resource was found, add it to the vector */
 
                if (path) {
-                       ret = (jboolean) asm_calljavafunction_int(m, o, path, NULL, NULL);
+                       ASM_CALLJAVAFUNCTION_INT(ret, m, o, path, NULL, NULL);
 
                        if (!ret)
                                return NULL;
@@ -384,6 +407,33 @@ JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResour
 }
 
 
+/*
+ * Class:     java/lang/VMClassLoader
+ * Method:    findLoadedClass
+ * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;
+ */
+JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_findLoadedClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name)
+{
+       classinfo *c;
+       utf       *u;
+
+       /* replace `.' by `/', this is required by the classcache */
+
+       u = javastring_toutf(name, true);
+
+       /* lookup for defining classloader */
+
+       c = classcache_lookup_defined((classloader *) cl, u);
+
+       /* if not found, lookup for initiating classloader */
+
+       if (c == NULL)
+               c = classcache_lookup((classloader *) cl, u);
+
+       return (java_lang_Class *) c;
+}
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where