This fixes a performance issue with zip files that appeared because we
used to open the zip files for _every_ class that we wanted to load.

Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com>
---
 vm/classloader.c |  186 +++++++++++++++++++++++++++++++-----------------------
 1 files changed, 107 insertions(+), 79 deletions(-)

diff --git a/vm/classloader.c b/vm/classloader.c
index a615fa3..13fbc9d 100644
--- a/vm/classloader.c
+++ b/vm/classloader.c
@@ -34,26 +34,34 @@ static inline void trace_pop()
        --trace_classloader_level;
 }
 
+enum classpath_type {
+       CLASSPATH_DIR,
+       CLASSPATH_ZIP,
+};
+
 struct classpath {
        struct list_head node;
 
-       /* This can contain several paths separated by colons */
-       const char *paths;
+       enum classpath_type type;
+
+       union {
+               const char *dir;
+               struct zip *zip;
+       };
 };
 
 /* These are the directories we search for classes */
 struct list_head classpaths = LIST_HEAD_INIT(classpaths);
 
-int classloader_add_to_classpath(const char *classpath)
+static int add_dir_to_classpath(const char *dir)
 {
-       assert(classpath);
-
        struct classpath *cp = malloc(sizeof *cp);
        if (!cp)
                return -ENOMEM;
 
-       cp->paths = strdup(classpath);
-       if (!cp->paths) {
+       cp->type = CLASSPATH_DIR;
+       cp->dir= strdup(dir);
+       if (!cp->dir) {
                NOT_IMPLEMENTED;
                return -ENOMEM;
        }
@@ -62,6 +70,73 @@ int classloader_add_to_classpath(const char *classpath)
        return 0;
 }
 
+static int add_zip_to_classpath(const char *zip)
+{
+       int zip_error;
+
+       struct classpath *cp = malloc(sizeof *cp);
+       if (!cp)
+               return -ENOMEM;
+
+       cp->type = CLASSPATH_ZIP;
+       cp->zip = zip_open(zip, 0, &zip_error);
+       if (!cp->zip) {
+               NOT_IMPLEMENTED;
+               return -1;
+       }
+
+       list_add(&cp->node, &classpaths);
+       return 0;
+}
+
+int classloader_add_to_classpath(const char *classpath)
+{
+       int i = 0;
+
+       assert(classpath);
+
+       while (classpath[i]) {
+               size_t n;
+               char *classpath_element;
+               struct stat st;
+
+               n = strspn(classpath + i, ":");
+               i += n;
+
+               n = strcspn(classpath + i, ":");
+               if (n == 0)
+                       continue;
+
+               classpath_element = strndup(classpath + i, n);
+               if (!classpath_element) {
+                       NOT_IMPLEMENTED;
+                       break;
+               }
+
+               i += n;
+
+               if (!stat(classpath_element, &st)) {
+                       /* XXX: We need to figure out what the semantics for
+                        * this function should be on error. IIRC, regular
+                        * java just ignores invalid classpath components.
+                        * We probably _shouldn't_ ignore those that we
+                        * couldn't add because we are out of memory. Also,
+                        * do we return error even if _some_ paths were
+                        * added successfully? */
+
+                       if (S_ISDIR(st.st_mode))
+                               add_dir_to_classpath(classpath_element);
+
+                       if (S_ISREG(st.st_mode))
+                               add_zip_to_classpath(classpath_element);
+               }
+
+               free(classpath_element);
+       }
+
+       return 0;
+}
+
 struct classloader_class {
        struct vm_class *class;
 };
@@ -134,10 +209,23 @@ out:
        return NULL;
 }
 
-struct vm_class *load_class_from_zip(const char *zipfile, const char *file)
+struct vm_class *load_class_from_dir(const char *dir, const char *file)
+{
+       struct vm_class *vmc;
+       char *full_filename;
+
+       if (asprintf(&full_filename, "%s/%s", dir, file) == -1) {
+               NOT_IMPLEMENTED;
+               return NULL;
+       }
+
+       vmc = load_class_from_file(full_filename);
+       free(full_filename);
+       return vmc;
+}
+
+struct vm_class *load_class_from_zip(struct zip *zip, const char *file)
 {
-       int zip_error;
-       struct zip *zip;
        int zip_file_index;
        struct zip_stat zip_stat;
        struct zip_file *zip_file;
@@ -147,12 +235,6 @@ struct vm_class *load_class_from_zip(const char *zipfile, 
const char *file)
        struct cafebabe_class *class;
        struct vm_class *result = NULL;
 
-       zip = zip_open(zipfile, 0, &zip_error);
-       if (!zip) {
-               NOT_IMPLEMENTED;
-               return NULL;
-       }
-
        zip_file_index = zip_name_locate(zip, file, 0);
        if (zip_file_index == -1) {
                NOT_IMPLEMENTED;
@@ -193,7 +275,6 @@ struct vm_class *load_class_from_zip(const char *zipfile, 
const char *file)
        /* If this returns error, what can we do? We've got all the data we
         * wanted, so there should be no point in returning the error. */
        zip_fclose(zip_file);
-       zip_close(zip);
 
        cafebabe_stream_open_buffer(&stream, zip_file_buf, zip_stat.size);
 
@@ -216,71 +297,18 @@ struct vm_class *load_class_from_zip(const char *zipfile, 
const char *file)
        return result;
 }
 
-struct vm_class *load_class_from_path_file(const char *path, const char *file)
-{
-       struct stat st;
-
-       if (stat(path, &st) == -1) {
-               /* Doesn't exist or not accessible */
-               return NULL;
-       }
-
-       if (S_ISDIR(st.st_mode)) {
-               /* Directory */
-               struct vm_class *vmc;
-               char *full_filename;
-
-               if (asprintf(&full_filename, "%s/%s", path, file) == -1) {
-                       NOT_IMPLEMENTED;
-                       return NULL;
-               }
-
-               vmc = load_class_from_file(full_filename);
-               free(full_filename);
-               return vmc;
-       }
-
-       if (S_ISREG(st.st_mode)) {
-               /* Regular file; could be .zip or .jar */
-               return load_class_from_zip(path, file);
-       }
-
-       return NULL;
-}
-
-struct vm_class *load_class_from_classpath_file(const char *classpath,
+struct vm_class *load_class_from_classpath_file(const struct classpath *cp,
        const char *file)
 {
-       struct vm_class *result = NULL;
-       size_t i = 0;
-
-       while (classpath[i]) {
-               size_t n;
-               char *classpath_element;
-
-               n = strspn(classpath + i, ":");
-               i += n;
-
-               n = strcspn(classpath + i, ":");
-               if (n == 0)
-                       continue;
-
-               classpath_element = strndup(classpath + i, n);
-               if (!classpath_element) {
-                       NOT_IMPLEMENTED;
-                       break;
-               }
-
-               i += n;
-
-               result = load_class_from_path_file(classpath_element, file);
-               free(classpath_element);
-
-               if (result)
-                       break;
+       switch (cp->type) {
+       case CLASSPATH_DIR:
+               return load_class_from_dir(cp->dir, file);
+       case CLASSPATH_ZIP:
+               return load_class_from_zip(cp->zip, file);
        }
 
-       return result;
+       /* Should never reach this. */
+       return NULL;
 }
 
 static struct vm_class *primitive_class_cache[VM_TYPE_MAX];
@@ -377,7 +405,7 @@ struct vm_class *load_class(const char *class_name)
 
        struct classpath *cp;
        list_for_each_entry(cp, &classpaths, node) {
-               result = load_class_from_classpath_file(cp->paths, filename);
+               result = load_class_from_classpath_file(cp, filename);
                if (result)
                        break;
        }
-- 
1.6.0.4


------------------------------------------------------------------------------
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to