Initial commit
authorRobert Pengelly <robertapengelly@hotmail.com>
Fri, 26 Sep 2025 19:11:06 +0000 (20:11 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Fri, 26 Sep 2025 19:11:06 +0000 (20:11 +0100)
29 files changed:
LICENSE [new file with mode: 0644]
Makefile.unix [new file with mode: 0644]
Makefile.w32 [new file with mode: 0644]
README.md [new file with mode: 0644]
class.c [new file with mode: 0644]
class.h [new file with mode: 0644]
constant.c [new file with mode: 0644]
constant.h [new file with mode: 0644]
cstr.c [new file with mode: 0755]
cstr.h [new file with mode: 0755]
field.c [new file with mode: 0644]
hashtab.c [new file with mode: 0755]
hashtab.h [new file with mode: 0755]
interface.c [new file with mode: 0644]
java_lib.c [new file with mode: 0644]
jvm.c [new file with mode: 0644]
jvm.h [new file with mode: 0755]
lib.c [new file with mode: 0755]
lib.h [new file with mode: 0755]
method.c [new file with mode: 0644]
method.h [new file with mode: 0644]
report.c [new file with mode: 0644]
report.h [new file with mode: 0644]
stack.c [new file with mode: 0644]
stack.h [new file with mode: 0644]
vector.c [new file with mode: 0755]
vector.h [new file with mode: 0755]
vm.c [new file with mode: 0644]
vm.h [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..fdddb29
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <https://unlicense.org>
diff --git a/Makefile.unix b/Makefile.unix
new file mode 100644 (file)
index 0000000..36fb29f
--- /dev/null
@@ -0,0 +1,28 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+SRCDIR              ?=  $(CURDIR)
+
+CC                  :=  gcc
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90
+
+CSRC                :=  $(shell find $(SRCDIR) -type f -name '*.c')
+
+ifeq ($(OS), Windows_NT)
+all: lightjvm.exe
+
+lightjvm.exe: $(CSRC)
+
+       $(CC) $(CFLAGS) -o $@ $^
+else
+all: lightjvm
+
+lightjvm: $(CSRC)
+
+       $(CC) $(CFLAGS) -o $@ $^
+endif
+
+clean:
+
+       if [ -f lightjvm.exe ]; then rm -rf lightjvm.exe; fi
+       if [ -f lightjvm ]; then rm -rf lightjvm; fi
diff --git a/Makefile.w32 b/Makefile.w32
new file mode 100644 (file)
index 0000000..582d6c8
--- /dev/null
@@ -0,0 +1,19 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+SRCDIR              ?=  $(CURDIR)
+
+CC                  :=  gcc
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90
+
+CSRC                :=  $(subst \,/,$(shell dir /s /b "$(SRCDIR)\\*.c"))
+
+all: lightjvm.exe
+
+clean:
+
+       if exist lightjvm.exe ( del /q lightjvm.exe )
+       if exist lightjvm ( del /q lightjvm )
+
+lightjvm.exe: $(CSRC)
+       $(CC) $(CFLAGS) -o $@ $^
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..7ffb46d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+All source code is Public Domain.
+
+## Obtain the source code
+
+    git clone https://git.candlhat.org/lightjvm.git
+
+## Building
+
+    BSD:
+    
+        Make sure you have gcc and gmake installed then run gmake -f Makefile.unix.
+    
+    Linux:
+    
+        Make sure you have gcc and make installed then run make -f Makefile.unix.
+    
+    macOS:
+    
+        Make sure you have xcode command line tools installed then run make -f Makefile.unix.
+    
+    Windows:
+    
+        Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32.
diff --git a/class.c b/class.c
new file mode 100644 (file)
index 0000000..7b2c15a
--- /dev/null
+++ b/class.c
@@ -0,0 +1,352 @@
+/******************************************************************************
+ * @file            class.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "class.h"
+#include    "constant.h"
+#include    "hashtab.h"
+#include    "jvm.h"
+#include    "lib.h"
+#include    "method.h"
+#include    "report.h"
+
+static struct hashtab hashtab_class_names = { 0 };
+
+struct java_class *parse_java_class (const char *class_name) {
+
+    unsigned long magic;
+    long i;
+    
+    struct java_class *java_class;
+    struct hashtab_name *key;
+    
+    FILE *fp = 0;
+    
+    struct class_file_format *cff;
+    char *path;
+    
+    struct vector *method_pool;
+    void *constant_pool;
+    
+    if ((key = hashtab_get_key (&hashtab_class_names, class_name))) {
+        return hashtab_get (&hashtab_class_names, key);
+    }
+    
+    path = xmalloc (strlen (class_name) + 7);
+    sprintf (path, "%s.class", class_name);
+    
+    if (!(fp = fopen (path, "r+b"))) {
+    
+        free (path);
+        
+        for (i = 0; i < state->nb_class_paths; i++) {
+        
+            path = xmalloc (strlen (state->class_paths[i]) + 1 + strlen (class_name) + 7);
+#if     defined (unix) || defined (__unix) || defined (__unix__) || defined (__APPLE__)
+            sprintf (path, "%s/%s.class", state->class_paths[i], class_name);
+#elif   defined (_WIN32)
+            sprintf (path, "%s\\%s.class", state->class_paths[i], class_name);
+#endif
+            
+            if (!(fp = fopen (path, "r+b"))) {
+            
+                free (path);
+                continue;
+            
+            }
+            
+            break;
+        
+        }
+    
+    }
+    
+    if (!fp) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open class '%s'", class_name);
+        return 0;
+    
+    }
+    
+    if (!(java_class = malloc (sizeof (*java_class)))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "not enough memory for the java class");
+        
+        free (path);
+        fclose (fp);
+        
+        return 0;
+    
+    }
+    
+    cff = &java_class->cff;
+    
+    if (fread (cff->magic_number, 1, 4, fp) != 4) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (((magic = array_to_integer (cff->magic_number, 4, 1))) != 0xCAFEBABE) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s is not a valid .class (%04x)", path, magic);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->minor_version, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->major_version, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (array_to_integer (cff->major_version, 2, 1) > 52) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "currently only up to Java 8 works");
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->constant_pool_count, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (!(constant_pool = parse_constant_pool (fp, array_to_integer (cff->constant_pool_count, 2, 1)))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->access_flags, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->this_class, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->super_class, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->interface_count, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (parse_interface_pool (fp, array_to_integer (cff->interface_count, 2, 1))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->fields_count, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (parse_field_pool (fp, array_to_integer (cff->fields_count, 2, 1))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (fread (cff->methods_count, 1, 2, fp) != 2) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    if (!(method_pool = parse_method_pool (fp, array_to_integer (cff->methods_count, 2, 1)))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path);
+        
+        free_constant_pool (constant_pool);
+        free (constant_pool);
+        
+        free (java_class);
+        free (path);
+        
+        fclose (fp);
+        return 0;
+    
+    }
+    
+    free (path);
+    fclose (fp);
+    
+    java_class->class_name    = xstrdup (class_name);
+    
+    java_class->constant_pool = constant_pool;
+    java_class->method_pool   = method_pool; 
+    
+    if ((key = hashtab_alloc_name (class_name))) {
+        hashtab_put (&hashtab_class_names, key, java_class);
+    }
+    
+    return java_class;
+
+}
+
+void free_classes (void) {
+
+    struct hashtab_entry *entry;
+    struct java_class *class;
+    
+    int i;
+    
+    for (i = 0; i < hashtab_class_names.capacity; i++) {
+    
+        if ((entry = &hashtab_class_names.entries[i])) {
+        
+            if (entry->key && entry->value) {
+            
+                class = entry->value;
+                
+                free_constant_pool (class->constant_pool);
+                free (class->constant_pool);
+                
+                free_method_pool (class->method_pool);
+                free (class->method_pool);
+                
+                free (class);
+                hashtab_remove (&hashtab_class_names, entry->key);
+            
+            }
+        
+        }
+    
+    }
+
+}
diff --git a/class.h b/class.h
new file mode 100644 (file)
index 0000000..14a5010
--- /dev/null
+++ b/class.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * @file            class.h
+ *****************************************************************************/
+#ifndef     _CLASS_H
+#define     _CLASS_H
+
+struct class_file_format {
+
+    unsigned char magic_number[4];
+    
+    unsigned char minor_version[2];
+    unsigned char major_version[2];
+    
+    unsigned char constant_pool_count[2];
+    unsigned char access_flags[2];
+    
+    unsigned char this_class[2];
+    unsigned char super_class[2];
+    
+    unsigned char interface_count[2];
+    unsigned char fields_count[2];
+    unsigned char methods_count[2];
+    unsigned char attributes_count[2];
+
+};
+
+#include    "constant.h"
+#include    "vector.h"
+
+struct java_class {
+
+    const char *class_name;
+    struct class_file_format cff;
+    
+    struct constant_pool *constant_pool;
+    struct vector *method_pool;
+
+};
+
+struct java_class *parse_java_class (const char *class_name);
+void free_classes (void);
+
+#endif      /* _CLASS_H */
diff --git a/constant.c b/constant.c
new file mode 100644 (file)
index 0000000..af574aa
--- /dev/null
@@ -0,0 +1,795 @@
+/******************************************************************************
+ * @file            java_constant_pool_parser.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "constant.h"
+#include    "jvm.h"
+#include    "lib.h"
+#include    "report.h"
+#include    "vector.h"
+
+#define     CONSTANT_UTF8               1
+#define     CONSTANT_INTEGER            3
+#define     CONSTANT_FLOAT              4
+#define     CONSTANT_LONG               5
+#define     CONSTANT_DOUBLE             6
+#define     CONSTANT_CLASS              7
+#define     CONSTANT_STRING_REF         8
+#define     CONSTANT_FIELD_REF          9
+#define     CONSTANT_METHOD_REF         10
+#define     CONSTANT_INTERFACE_REF      11
+#define     CONSTANT_NAME_AND_TYPE      12
+#define     CONSTANT_METHOD_HANDLER     15
+#define     CONSTANT_INVOKE_DYNAMIC     18
+
+static const int tag_additional_byte_size[13] = { 0,  2,  0,  4,  4,  8,  8,  2,  2,  4,  4,  4,  4 };
+
+/* Parse UTF-8 String. */
+static int parse_string (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_utf8 *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_UTF8;
+    ptr->index = index;
+    
+    if (fread (ptr->string_size, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_UTF8] + array_to_integer (ptr->string_size, 2, 1);
+    
+    if (!(ptr->ptr = malloc (array_to_integer (ptr->string_size, 2, 1) + 1))) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    memset (ptr->ptr, 0, array_to_integer (ptr->string_size, 2, 1));
+    
+    if (fread (ptr->ptr, 1, array_to_integer (ptr->string_size, 2, 1), fp) != array_to_integer (ptr->string_size, 2, 1)) {
+    
+        free (ptr->ptr);
+        free (ptr);
+        
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_integer (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_integer *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_INTEGER;
+    ptr->index = index;
+    
+    if (fread (ptr->value, 1, 4, fp) != 4) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTEGER];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_float (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_float *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_FLOAT;
+    ptr->index = index;
+    
+    if (fread (ptr->value, 1, 4, fp) != 4) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_FLOAT];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_long (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_long *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_LONG;
+    ptr->index = index;
+    
+    if (fread (ptr->value, 1, 8, fp) != 8) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_LONG];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_double (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_double *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_DOUBLE;
+    ptr->index = index;
+    
+    if (fread (ptr->value, 1, 8, fp) != 8) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_DOUBLE];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_class_ref (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_class_ref *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_CLASS;
+    ptr->index = index;
+    
+    if (fread (ptr->string_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_CLASS];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_string_ref (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_string_ref *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_STRING_REF;
+    ptr->index = index;
+    
+    if (fread (ptr->string_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_STRING_REF];
+    vec_push (constant_pool, ptr);
+    
+    return 0;
+
+}
+
+static int parse_field_ref (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_field_ref *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_FIELD_REF;
+    ptr->index = index;
+    
+    if (fread (ptr->class_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_FIELD_REF];
+    
+    if (fread (ptr->nat_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_method_ref (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_method_ref *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_METHOD_REF;
+    ptr->index = index;
+    
+    if (fread (ptr->class_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_METHOD_REF];
+    
+    if (fread (ptr->nat_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_interface_ref (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_interface_ref *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_INTERFACE_REF;
+    ptr->index = index;
+    
+    if (fread (ptr->class_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF];
+    
+    if (fread (ptr->nat_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_name_and_type (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_nat *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_NAME_AND_TYPE;
+    ptr->index = index;
+    
+    if (fread (ptr->name_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_NAME_AND_TYPE];
+    
+    if (fread (ptr->type_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_method_handler (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_method_handler *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_METHOD_HANDLER;
+    ptr->index = index;
+    
+    if (fread (&ptr->reference_kind, 1, 1, fp) != 1) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    /*ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF];*/
+    
+    if (fread (ptr->reference_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+static int parse_invoke_dynamic (FILE *fp, struct vector *constant_pool, int index) {
+
+    struct constant_invoke_dynamic *ptr;
+    
+    if (!(ptr = malloc (sizeof (*ptr)))) {
+        return -1;
+    }
+    
+    ptr->tag = CONSTANT_INVOKE_DYNAMIC;
+    ptr->index = index;
+    
+    if (fread (ptr->bootstrap_method_attr_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    /*ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF];*/
+    
+    if (fread (ptr->nat_index, 1, 2, fp) != 2) {
+    
+        free (ptr);
+        return -1;
+    
+    }
+    
+    vec_push (constant_pool, ptr);
+    return 0;
+
+}
+
+struct constant_pool *parse_constant_pool (FILE *fp, int count) {
+
+    struct constant_pool *constant_pool;
+    
+    unsigned char tag = 0;
+    int ret, i;
+    
+    if (!(constant_pool = malloc (sizeof (*constant_pool)))) {
+        return 0;
+    }
+    
+    memset (constant_pool, 0, sizeof (*constant_pool));
+    
+    for (i = 1; i < count; i++) {
+    
+        fread (&tag, 1, 1, fp);
+        
+        switch (tag) {
+        
+            case CONSTANT_UTF8:
+            
+                ret = parse_string (fp, &constant_pool->vec_strings, i);
+                break;
+            
+            case CONSTANT_INTEGER:
+            
+                ret = parse_integer (fp, &constant_pool->vec_integers, i);
+                break;
+            
+            case CONSTANT_FLOAT:
+            
+                ret = parse_float (fp, &constant_pool->vec_floats, i);
+                break;
+            
+            case CONSTANT_LONG:
+            
+                ret = parse_long (fp, &constant_pool->vec_longs, i);
+                
+                i++;
+                break;
+            
+            case CONSTANT_DOUBLE:
+            
+                ret = parse_double (fp, &constant_pool->vec_doubles, i);
+                
+                i++;
+                break;
+            
+            case CONSTANT_STRING_REF:
+            
+                ret = parse_string_ref (fp, &constant_pool->vec_string_refs, i);
+                break;
+            
+            case CONSTANT_CLASS:
+            
+                ret = parse_class_ref (fp, &constant_pool->vec_class_refs, i);
+                break;
+            
+            case CONSTANT_FIELD_REF:
+            
+                ret = parse_field_ref (fp, &constant_pool->vec_field_refs, i);
+                break;
+            
+            case CONSTANT_METHOD_REF:
+            
+                ret = parse_method_ref (fp, &constant_pool->vec_method_refs, i);
+                break;
+            
+            case CONSTANT_INTERFACE_REF:
+            
+                ret = parse_interface_ref (fp, &constant_pool->vec_interface_refs, i);
+                break;
+            
+            case CONSTANT_NAME_AND_TYPE:
+            
+                ret = parse_name_and_type (fp, &constant_pool->vec_nats, i);
+                break;
+            
+            case CONSTANT_METHOD_HANDLER:
+            
+                ret = parse_method_handler (fp, &constant_pool->vec_method_handlers, i);
+                break;
+            
+            case CONSTANT_INVOKE_DYNAMIC:
+            
+                ret = parse_invoke_dynamic (fp, &constant_pool->vec_invoke_dynamic, i);
+                break;
+            
+            default:
+            
+                report_at (program_name, 0, REPORT_ERROR, "unknown tag = 0x%02x", tag);
+                
+                free_constant_pool (constant_pool);
+                free (constant_pool);
+                
+                return 0;
+        
+        }
+        
+        if (ret) {
+        
+            free_constant_pool (constant_pool);
+            free (constant_pool);
+            
+            return 0;
+        
+        }
+    
+    }
+    
+    return constant_pool;
+
+}
+
+void free_constant_pool (struct constant_pool *constant_pool) {
+
+    struct constant_utf8 *ptr;
+    int i;
+    
+    for (i = 0; i < constant_pool->vec_strings.length; i++) {
+    
+        if ((ptr = constant_pool->vec_strings.data[i])) {
+        
+            free (ptr->ptr);
+            free (ptr);
+        
+        }
+    
+    }
+    
+    for (i = 0; i < constant_pool->vec_integers.length; i++) {
+        free (constant_pool->vec_integers.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_floats.length; i++) {
+        free (constant_pool->vec_floats.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_longs.length; i++) {
+        free (constant_pool->vec_longs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_doubles.length; i++) {
+        free (constant_pool->vec_doubles.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_class_refs.length; i++) {
+        free (constant_pool->vec_class_refs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_string_refs.length; i++) {
+        free (constant_pool->vec_string_refs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_field_refs.length; i++) {
+        free (constant_pool->vec_field_refs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_method_refs.length; i++) {
+        free (constant_pool->vec_method_refs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_interface_refs.length; i++) {
+        free (constant_pool->vec_interface_refs.data[i]);
+    }
+    
+    for (i = 0; i < constant_pool->vec_nats.length; i++) {
+        free (constant_pool->vec_nats.data[i]);
+    }
+
+}
+
+
+struct constant_utf8 *find_utf8 (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_strings;
+    
+    struct constant_utf8 *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_class_ref *find_class_ref (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_class_refs;
+    
+    struct constant_class_ref *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_string_ref *find_string_ref (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_string_refs;
+    
+    struct constant_string_ref *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_field_ref *find_field_ref (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_field_refs;
+    
+    struct constant_field_ref *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_method_ref *find_method_ref (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_method_refs;
+    
+    struct constant_method_ref *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_nat *find_nat (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_nats;
+    
+    struct constant_nat *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+struct constant_invoke_dynamic *find_invoke_dynamic (struct constant_pool *constant_pool, int index) {
+
+    struct vector *arr = &constant_pool->vec_invoke_dynamic;
+    
+    struct constant_invoke_dynamic *p;
+    int i;
+    
+    for (i = 0; i < arr->length; i++) {
+    
+        if ((p = arr->data[i])) {
+        
+            if (p->index == index) {
+                return p;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+double get_double_from_constant_pool (struct constant_pool *p, int index) {
+
+    struct constant_double *entry;
+    unsigned char temp[8];
+    
+    double value = 0;
+    int i, j, k;
+    
+    for (i = 0; i < p->vec_doubles.length; i++) {
+    
+        entry = p->vec_doubles.data[i];
+        
+        if (entry->index == (index)) {
+        
+            for (j = 0, k = 7; j < 8; j++, k--) {
+                temp[k] = entry->value[j];
+            }
+            
+            memcpy (&value, temp, 8);
+            return value;
+        
+        }
+    
+    }
+    
+    return 0.0f;
+
+}
+
+int get_utf8_string (struct constant_pool *p, int index, unsigned long size, char *out) {
+
+    struct constant_utf8 *utf8 = find_utf8 (p, index);
+    unsigned long copy_size = 0;
+    
+    memset (out, 0, size);
+    
+    if (utf8 != 0) {
+    
+        copy_size = (array_to_integer (utf8->string_size, 2, 1) < size) ? array_to_integer (utf8->string_size, 2, 1) : size;
+        memcpy (out, utf8->ptr, copy_size);
+    
+    }
+    
+    return copy_size;
+
+}
diff --git a/constant.h b/constant.h
new file mode 100644 (file)
index 0000000..d36249b
--- /dev/null
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * @file            constant.h
+ *****************************************************************************/
+#ifndef     _CONSTANT_H
+#define     _CONSTANT_H
+
+#include    "vector.h"
+struct constant_pool {
+
+    struct vector vec_strings;
+    struct vector vec_integers;
+    struct vector vec_floats;
+    struct vector vec_longs;
+    struct vector vec_doubles;
+    struct vector vec_class_refs;
+    struct vector vec_string_refs;
+    struct vector vec_field_refs;
+    struct vector vec_method_refs;
+    struct vector vec_interface_refs;
+    struct vector vec_nats;
+    struct vector vec_method_handlers;
+    struct vector vec_invoke_dynamic;
+
+};
+
+void free_constant_pool (struct constant_pool *constant_pool);
+
+#include    <stdio.h>
+struct constant_pool *parse_constant_pool (FILE *fp, int count);
+
+struct constant_utf8 {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char string_size[2];
+    unsigned char *ptr;
+
+};
+
+struct constant_integer {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char value[4];
+
+};
+
+struct constant_float {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char value[4];
+
+};
+
+struct constant_long {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char value[8];
+
+};
+
+struct constant_double {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char value[8];
+
+};
+
+struct constant_class_ref {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char string_index[2];
+
+};
+
+struct constant_string_ref {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char string_index[2];
+
+};
+
+struct constant_field_ref {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char class_index[2];
+    unsigned char nat_index[2];
+
+};
+
+struct constant_method_ref {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char class_index[2];
+    unsigned char nat_index[2];
+
+};
+
+struct constant_interface_ref {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char class_index[2];
+    unsigned char nat_index[2];
+
+};
+
+struct constant_nat {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char name_index[2];
+    unsigned char type_index[2];
+
+};
+
+struct constant_method_handler {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char reference_kind;
+    unsigned char reference_index[2];
+
+};
+
+struct constant_invoke_dynamic {
+
+    unsigned char tag;
+    
+    int additional_byte_size;
+    int index;
+    
+    unsigned char bootstrap_method_attr_index[2];
+    unsigned char nat_index[2];
+
+};
+
+
+double get_double_from_constant_pool (struct constant_pool *p, int index);
+int get_utf8_string (struct constant_pool *p, int index, unsigned long size, char *out);
+
+struct constant_utf8 *find_utf8 (struct constant_pool *constant_pool, int index);
+struct constant_class_ref *find_class_ref (struct constant_pool *constant_pool, int index);
+struct constant_string_ref *find_string_ref (struct constant_pool *constant_pool, int index);
+struct constant_field_ref *find_field_ref (struct constant_pool *constant_pool, int index);
+struct constant_method_ref *find_method_ref (struct constant_pool *constant_pool, int index);
+struct constant_nat *find_nat (struct constant_pool *constant_pool, int index);
+struct constant_invoke_dynamic *find_invoke_dynamic (struct constant_pool *constant_pool, int index);
+
+#endif      /* _CONSTANT_H */
diff --git a/cstr.c b/cstr.c
new file mode 100755 (executable)
index 0000000..d518f2e
--- /dev/null
+++ b/cstr.c
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * @file            cstr.c
+ *****************************************************************************/
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "cstr.h"
+
+extern void *xrealloc (void *__ptr, unsigned int __size);
+
+static void cstr_realloc (struct cstring *cstr, int new_size) {
+
+    int size = cstr->size_allocated;
+    
+    if (size < 8) {
+        size = 8;
+    }
+    
+    while (size < new_size) {
+        size *= 2;
+    }
+    
+    cstr->data = xrealloc (cstr->data, size);
+    cstr->size_allocated = size;
+
+}
+
+void cstr_ccat (struct cstring *cstr, int ch) {
+
+    int size = cstr->size + 1;
+    
+    if (size > cstr->size_allocated) {
+        cstr_realloc (cstr, size);
+    }
+    
+    ((unsigned char *) cstr->data)[size - 1] = ch;
+    cstr->size = size;
+
+}
+
+void cstr_cat (struct cstring *cstr, const char *str, int len) {
+
+    int size;
+    
+    if (len <= 0) {
+        len = strlen (str) + 1 + len;
+    }
+    
+    size = cstr->size + len;
+    
+    if (size > cstr->size_allocated) {
+        cstr_realloc (cstr, size);
+    }
+    
+    memmove (((unsigned char *) cstr->data) + cstr->size, str, len);
+    cstr->size = size;
+
+}
+
+void cstr_new (struct cstring *cstr) {
+    memset (cstr, 0, sizeof (struct cstring));
+}
+
+void cstr_free (struct cstring *cstr) {
+
+    free (cstr->data);
+    cstr_new (cstr);
+
+}
diff --git a/cstr.h b/cstr.h
new file mode 100755 (executable)
index 0000000..2736720
--- /dev/null
+++ b/cstr.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * @file            cstr.h
+ *****************************************************************************/
+#ifndef     _CSTR_H
+#define     _CSTR_H
+
+struct cstring {
+
+    int size, size_allocated;
+    void *data;
+
+};
+
+void cstr_ccat (struct cstring *cstr, int ch);
+void cstr_cat (struct cstring *cstr, const char *str, int len);
+
+void cstr_new (struct cstring *cstr);
+void cstr_free (struct cstring *cstr);
+
+#endif      /* _CSTR_H */
diff --git a/field.c b/field.c
new file mode 100644 (file)
index 0000000..fdbfa1a
--- /dev/null
+++ b/field.c
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * @file            java_field_pool_parser.c
+ *****************************************************************************/
+#include    <stdio.h>
+
+#include    "lib.h"
+
+static int parse_attr (FILE *fp, int count) {
+
+    unsigned char temp[4];
+    int i;
+    
+    for (i = 0; i < count; i++) {
+    
+        if (fread (temp, 1, 2, fp) != 2) {
+            return -1;
+        }
+        
+        if (fread (temp, 1, 4, fp) != 2) {
+            return -1;
+        }
+        
+        fseek (fp, array_to_integer (temp, 4, 1), SEEK_CUR);
+    
+    }
+    
+    return 0;
+
+}
+
+static int parse (FILE *fp) {
+
+    unsigned char temp[2];
+    
+    if (fread (temp, 1, 2, fp) != 2) {
+        return -1;
+    }
+    
+    if (fread (temp, 1, 2, fp) != 2) {
+        return -1;
+    }
+    
+    if (fread (temp, 1, 2, fp) != 2) {
+        return -1;
+    }
+    
+    if (fread (temp, 1, 2, fp) != 2) {
+        return -1;
+    }
+    
+    return parse_attr (fp, array_to_integer (temp, 2, 1));
+
+}
+
+int parse_field_pool (FILE *fp, int count) {
+
+    int ret, i;
+    
+    for (i = 0; i < count; i++) {
+    
+        if ((ret = parse (fp))) {
+            return ret;
+        }
+    
+    }
+    
+    return 0;
+
+}
diff --git a/hashtab.c b/hashtab.c
new file mode 100755 (executable)
index 0000000..328b622
--- /dev/null
+++ b/hashtab.c
@@ -0,0 +1,217 @@
+/******************************************************************************
+ * @file            hashtab.c
+ *****************************************************************************/
+#include    <stddef.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "hashtab.h"
+
+static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key);
+
+static int adjust_capacity (struct hashtab *table, unsigned int new_capacity) {
+
+    struct hashtab_entry *new_entries, *old_entries;
+    unsigned int i, new_count, old_capacity;
+    
+    if ((new_entries = malloc (sizeof (*new_entries) * new_capacity)) == NULL) {
+        return -2;
+    }
+    
+    for (i = 0; i < new_capacity; i++) {
+    
+        struct hashtab_entry *entry = &new_entries[i];
+        
+        entry->key = NULL;
+        entry->value = NULL;
+    
+    }
+    
+    old_entries = table->entries;
+    old_capacity = table->capacity;
+    
+    new_count = 0;
+    
+    for (i = 0; i < old_capacity; i++) {
+    
+        struct hashtab_entry *entry = &old_entries[i], *dest;
+        
+        if (entry->key == NULL) {
+            continue;
+        }
+        
+        dest = find_entry (new_entries, new_capacity, entry->key);
+        
+        dest->key = entry->key;
+        dest->value = entry->value;
+        
+        new_count++;
+    
+    }
+    
+    free (old_entries);
+    
+    table->capacity = new_capacity;
+    table->count = new_count;
+    table->entries = new_entries;
+    table->used = new_count;
+    
+    return 0;
+
+}
+
+static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key) {
+
+    struct hashtab_entry *tombstone = NULL;
+    unsigned int index;
+    
+    for (index = key->hash % capacity; ; index = (index + 1) % capacity) {
+    
+        struct hashtab_entry *entry = &entries[index];
+        
+        if (entry->key == NULL) {
+        
+            if (entry->value == NULL) {
+            
+                if (tombstone == NULL) {
+                    return entry;
+                }
+                
+                return tombstone;
+            
+            } else if (tombstone == NULL) {
+                tombstone = entry;
+            }
+        
+        } else if (entry->key->bytes == key->bytes) {
+        
+            if (memcmp (entry->key->chars, key->chars, key->bytes) == 0 && entry->key->hash == key->hash) {
+                return entry;
+            }
+        
+        }
+    
+    }
+
+}
+
+static unsigned int hash_string (const void *p, unsigned int length) {
+
+    unsigned char *str = (unsigned char *) p;
+    unsigned int i;
+    
+    unsigned int result = 0;
+    
+    for (i = 0; i < length; i++) {
+        result = (((unsigned short) str[i]) << 4) + (result >> 9) + result + (result >> 3) + (((unsigned short) str[i]) << 2) - (result << 12);
+    }
+    
+    return result;
+
+}
+
+struct hashtab_name *hashtab_alloc_name (const char *str) {
+
+    unsigned int bytes = strlen (str), hash = hash_string (str, bytes);
+    struct hashtab_name *name;
+    
+    if ((name = malloc (sizeof (*name))) == NULL) {
+        return NULL;
+    }
+    
+    name->bytes = bytes;
+    name->chars = str;
+    name->hash = hash;
+    
+    return name;
+
+}
+
+struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name) {
+
+    struct hashtab_name *key;
+    struct hashtab_entry *entry;
+    
+    if (table == NULL || table->count == 0 || !(key = hashtab_alloc_name (name))) {
+        return 0;
+    }
+    
+    entry = find_entry (table->entries, table->capacity, key);
+    free (key);
+    
+    return entry->key;
+
+}
+
+void *hashtab_get (struct hashtab *table, struct hashtab_name *key) {
+
+    struct hashtab_entry *entry;
+    
+    if (table == NULL || table->count == 0) {
+        return NULL;
+    }
+    
+    entry = find_entry (table->entries, table->capacity, key);
+    
+    if (entry->key == NULL) {
+        return NULL;
+    }
+    
+    return entry->value;
+
+}
+
+int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) {
+
+    const int MIN_CAPACITY = 15;
+    
+    struct hashtab_entry *entry;
+    int ret = 0;
+    
+    if (table->used >= table->capacity / 2) {
+    
+        int capacity = table->capacity * 2 - 1;
+        
+        if (capacity < MIN_CAPACITY) {
+            capacity = MIN_CAPACITY;
+        }
+        
+        if ((ret = adjust_capacity (table, capacity))) {
+            return ret;
+        }
+    
+    }
+    
+    entry = find_entry (table->entries, table->capacity, key);
+    
+    if (entry->key == NULL) {
+    
+        table->count++;
+        
+        if (entry->value == NULL) {
+            table->used++;
+        }
+    
+    }
+    
+    entry->key = key;
+    entry->value = value;
+    
+    return 0;
+
+}
+
+void hashtab_remove (struct hashtab *table, struct hashtab_name *key) {
+
+    struct hashtab_entry *entry;
+    
+    if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) {
+    
+        entry->key = NULL;
+        entry->value = NULL;
+        
+        --table->count;
+    
+    }
+
+}
diff --git a/hashtab.h b/hashtab.h
new file mode 100755 (executable)
index 0000000..ed8e828
--- /dev/null
+++ b/hashtab.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * @file            hashtab.h
+ *****************************************************************************/
+#ifndef     _HASHTAB_H
+#define     _HASHTAB_H
+
+struct hashtab_name {
+
+    const char *chars;
+    unsigned int bytes, hash;
+
+};
+
+struct hashtab_entry {
+
+    struct hashtab_name *key;
+    void *value;
+
+};
+
+struct hashtab {
+
+    struct hashtab_entry *entries;
+    int capacity, count, used;
+
+};
+
+struct hashtab_name *hashtab_alloc_name (const char *str);
+struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name);
+
+void *hashtab_get (struct hashtab *table, struct hashtab_name *key);
+
+int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value);
+void hashtab_remove (struct hashtab *table, struct hashtab_name *key);
+
+#endif      /* _HASHTAB_H */
diff --git a/interface.c b/interface.c
new file mode 100644 (file)
index 0000000..3250e11
--- /dev/null
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * @file            java_interface_pool_parser.c
+ *****************************************************************************/
+#include    <stdio.h>
+
+static int parse (FILE *fp) {
+
+    unsigned char temp[2];
+    
+    if (fread (temp, 1, 2, fp) != 2) {
+        return -1;
+    }
+    
+    return 0;
+
+}
+
+int parse_interface_pool (FILE *fp, int count) {
+
+    int ret, i;
+    
+    for (i = 0; i < count; i++) {
+    
+        if ((ret = parse (fp))) {
+            return ret;
+        }
+    
+    }
+    
+    return 0;
+
+}
diff --git a/java_lib.c b/java_lib.c
new file mode 100644 (file)
index 0000000..38f1d05
--- /dev/null
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * @file            java_lib.c
+ *****************************************************************************/
+#include    <stdlib.h>
+#include    <string.h>
+#include    <time.h>
+
+#include    "constant.h"
+#include    "stack.h"
+
+typedef int (*java_lang_lib) (struct constant_pool *p, struct stack_frame *stack);
+
+struct java_lang_method {
+
+    char *class_name;
+    char *method_name;
+    
+    java_lang_lib runtime;
+
+};
+
+static int java_lang_math_random (struct constant_pool *p, struct stack_frame *stack) {
+
+    double r = 0.0f;
+    int times = 0, i;
+    
+    srand (time (0));
+    times = rand () % 100;
+    
+    for (i = 0; i < times; i++) {
+        r = ((double) rand () / (double) RAND_MAX);
+    }
+    
+    push_double (stack, r);
+    
+    (void) p;
+    return 0;
+
+}
+
+static struct java_lang_method method_table[] = {
+    { "java/lang/Math", "random", java_lang_math_random }
+};
+
+static unsigned long java_lang_method_size = (sizeof (method_table) / sizeof (method_table[0]));
+
+static struct java_lang_method *find_java_lang_method (char *class_name, char *method_name) {
+
+    struct java_lang_method *entry;
+    unsigned long i;
+    
+    for (i = 0; i < java_lang_method_size; i++) {
+    
+        entry = &method_table[i];
+        
+        if (strcmp (entry->class_name, class_name) == 0 && strcmp (entry->method_name, method_name) == 0) {
+            return entry;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+int invoke_java_lang_library (struct constant_pool *p, struct stack_frame *stack, char *class_name, char *method_name) {
+
+    struct java_lang_method *method;
+    
+    if ((method = find_java_lang_method (class_name, method_name))) {
+        return method->runtime (p, stack);
+    }
+    
+    return -1;
+
+}
diff --git a/jvm.c b/jvm.c
new file mode 100644 (file)
index 0000000..5e33265
--- /dev/null
+++ b/jvm.c
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * @file            jvm.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "class.h"
+#include    "constant.h"
+#include    "jvm.h"
+#include    "lib.h"
+#include    "method.h"
+#include    "report.h"
+#include    "stack.h"
+#include    "vm.h"
+
+static struct stack_frame *stack_frame = 0;
+
+/*static FILE *fp = 0;
+
+static void cleanup (void) {
+    if (fp) { fclose (fp); }
+}*/
+
+struct jvm_state *state = 0;
+const char *program_name = 0;
+
+int main (int argc, char **argv) {
+
+    struct java_class *class;
+    struct method_info *main;
+    
+    long i;
+    
+    /*atexit (cleanup);*/
+    
+    if (argc && *argv) {
+    
+        char *p;
+        program_name = *argv;
+        
+        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
+            program_name = (p + 1);
+        }
+    
+    }
+    
+    state = xmalloc (sizeof (*state));
+    parse_args (argc, argv, 1);
+    
+    if (state->nb_files == 0) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "no input files provided");
+        return EXIT_FAILURE;
+    
+    }
+    
+    for (i = 0; i < state->nb_files; i++) {
+    
+        if (!(class = parse_java_class (state->files[i]))) {
+            continue;
+        }
+        
+        /*{
+        
+            struct constant_pool *p = class->constant_pool;
+            int i;
+            
+            for (i = 0; i < p->vec_method_refs.length; i++) {
+            
+                struct constant_method_ref *method = p->vec_method_refs.data[i];
+                
+                struct constant_utf8 *ptr = find_utf8 (class->constant_pool, array_to_integer (method->, 2, 1));
+                printf ("method_ref[%d]\n", method->index);
+            
+            }
+        
+        }*/
+        
+        if (!(main = find_method_in_pool (class->constant_pool, class->method_pool, ACC_PUBLIC | ACC_STATIC, "main", 4))) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "main method not found in class %s", state->files[i]);
+            continue;
+        
+        }
+        
+        if (!(stack_frame = stack_init (1024))) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for a stack");
+            continue;
+        
+        }
+        
+        execute_method (main, stack_frame, class);
+        
+        if (stack_frame) {
+        
+            if (stack_frame->store) {
+                free (stack_frame->store);
+            }
+            
+            free (stack_frame);
+        
+        }
+        
+        stack_frame = 0;
+    
+    }
+    
+    free_classes ();
+    
+    if (stack_frame) {
+    
+        if (stack_frame->store) {
+            free (stack_frame->store);
+        }
+        
+        free (stack_frame);
+    
+    }
+    
+    return (get_error_count () > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+
+}
diff --git a/jvm.h b/jvm.h
new file mode 100755 (executable)
index 0000000..bfbea35
--- /dev/null
+++ b/jvm.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * @file            jvm.h
+ *****************************************************************************/
+#ifndef     _JVM_H
+#define     _JVM_H
+
+struct jvm_state {
+
+    const char **files;
+    long nb_files;
+    
+    const char **class_paths;
+    long nb_class_paths;
+
+};
+
+extern struct jvm_state *state;
+extern const char *program_name;
+
+#include    <stdio.h>
+
+int parse_field_pool (FILE *fp, int count);
+int parse_interface_pool (FILE *fp, int count);
+
+#endif      /* _JVM_H */
diff --git a/lib.c b/lib.c
new file mode 100755 (executable)
index 0000000..d6897a7
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,295 @@
+/******************************************************************************
+ * @file            lib.c
+ *****************************************************************************/
+#include    <limits.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "jvm.h"
+#include    "lib.h"
+#include    "report.h"
+
+#define     OPTION_CLASS_PATH           0x0001
+#define     OPTION_HELP                 0x0002
+
+struct option {
+
+    const char *name;
+    int index, flags;
+
+};
+
+#define     OPTION_NO_ARG               0x0001
+#define     OPTION_HAS_ARG              0x0002
+
+static struct option opts[] = {
+
+    {   "--class-path",     OPTION_CLASS_PATH,      OPTION_HAS_ARG      },
+    {   "-cp",              OPTION_CLASS_PATH,      OPTION_HAS_ARG      },
+    
+    {   "--help",           OPTION_HELP,            OPTION_NO_ARG       },
+    {   0,                  0,                      0                   }
+
+};
+
+static int strstart (const char *val, const char **str) {
+
+    const char *p = val;
+    const char *q = *str;
+    
+    while (*p != '\0') {
+    
+        if (*p != *q) {
+            return 0;
+        }
+        
+        ++p;
+        ++q;
+    
+    }
+    
+    *str = q;
+    return 1;
+
+}
+
+static void print_help (void) {
+
+    if (program_name) {
+    
+        fprintf (stderr, "Usage: %s [options] file...\n\n", program_name);
+        fprintf (stderr, "Options:\n\n");
+        
+        fprintf (stderr, "    --help                Show this help information then exit.\n");
+    
+    }
+    
+    exit (EXIT_SUCCESS);
+
+}
+
+static void dynarray_add (void *ptab, long *nb_ptr, void *data) {
+
+    int nb, nb_alloc;
+    void **pp;
+    
+    nb = *nb_ptr;
+    pp = *(void ***) ptab;
+    
+    if ((nb & (nb - 1)) == 0) {
+    
+        if (!nb) {
+            nb_alloc = 1;
+        } else {
+            nb_alloc = nb * 2;
+        }
+        
+        pp = xrealloc (pp, nb_alloc * sizeof (void *));
+        *(void ***) ptab = pp;
+    
+    }
+    
+    pp[nb++] = data;
+    *nb_ptr = nb;
+
+}
+
+void parse_args (int argc, char **argv, int optind) {
+
+    struct option *popt;
+    const char *optarg, *r;
+    
+#if     defined (_WIN32)
+    char *p;
+    unsigned long length, i;
+#endif
+    
+    if (argc <= optind) {
+        print_help ();
+    }
+    
+    while (optind < argc) {
+    
+        r = argv[optind++];
+        
+        if (r[0] != '-' || r[1] == '\0') {
+        
+            dynarray_add (&state->files, &state->nb_files, xstrdup (r));
+            continue;
+        
+        }
+        
+        for (popt = opts; popt; popt++) {
+        
+            const char *p1 = popt->name;
+            const char *r1 = r;
+            
+            if (!p1) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (!strstart (p1, &r1)) {
+                continue;
+            }
+            
+            optarg = r1;
+            
+            if (popt->flags & OPTION_HAS_ARG) {
+            
+                if (*optarg == '\0') {
+                
+                    if (optind >= argc) {
+                    
+                        report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", r);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    optarg = argv[optind++];
+                
+                }
+            
+            } else if (*optarg != '\0') {
+                continue;
+            }
+            
+            break;
+        
+        }
+        
+        switch (popt->index) {
+        
+            case OPTION_CLASS_PATH: {
+                
+#if     defined (_WIN32)
+                length = strlen (p = (char *) optarg);
+                
+                for (i = 0; i < length; i++) {
+                
+                    if (p[i] == '/') {
+                        p[i] = '\\';
+                    }
+                
+                }
+#endif
+                dynarray_add (&state->class_paths, &state->nb_class_paths, xstrdup (optarg));
+                break;
+            
+            }
+            
+            case OPTION_HELP: {
+            
+                print_help ();
+                break;
+            
+            }
+            
+            default: {
+            
+                report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+unsigned long array_to_integer (unsigned char *arr, int size, int bigendian) {
+
+    unsigned long val = 0, mask = 1;
+    int i;
+    
+    if (bigendian) {
+    
+        int j;
+        
+        for (i = size, j = 0; i > 0; i--, j++) {
+        
+            mask *= (UCHAR_MAX + 1);
+            val |= arr[j] << (CHAR_BIT * (i - 1));
+        
+        }
+    
+    } else {
+    
+        for (i = 0; i < size; i++) {
+        
+            mask *= (UCHAR_MAX + 1);
+            val |= arr[i] << (CHAR_BIT * i);
+        
+        }
+    
+    }
+    
+    return val & (mask - 1);
+
+}
+
+void write_to_byte_array (unsigned char *arr, unsigned long value, int size, int bigendian) {
+
+    int i;
+    
+    if (bigendian) {
+    
+        int j;
+        
+        for (i = size - 1, j = 0; i >= 0; i--, j++) {
+            arr[i] = (value >> (CHAR_BIT * j)) & UCHAR_MAX;
+        }
+    
+    } else {
+    
+        for (i = 0; i < size; i++) {
+            arr[i] = (value >> (CHAR_BIT * i)) & UCHAR_MAX;
+        }
+    
+    }
+
+}
+
+char *xstrdup (const char *str) {
+
+    char *ptr = xmalloc (strlen (str) + 1);
+    strcpy (ptr, str);
+    
+    return ptr;
+
+}
+
+void *xmalloc (unsigned long size) {
+
+    void *ptr = malloc (size);
+    
+    if (ptr == NULL && size) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    memset (ptr, 0, size);
+    return ptr;
+
+}
+
+void *xrealloc (void *ptr, unsigned long size) {
+
+    void *new_ptr = realloc (ptr, size);
+    
+    if (new_ptr == NULL && size) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    return new_ptr;
+
+}
diff --git a/lib.h b/lib.h
new file mode 100755 (executable)
index 0000000..ea61df1
--- /dev/null
+++ b/lib.h
@@ -0,0 +1,17 @@
+/******************************************************************************
+ * @file            lib.h
+ *****************************************************************************/
+#ifndef     _LIB_H
+#define     _LIB_H
+
+unsigned long array_to_integer (unsigned char *arr, int size, int bigendian);
+void write_to_byte_array (unsigned char *arr, unsigned long value, int size, int bigendian);
+
+char *xstrdup (const char *str);
+
+void *xmalloc (unsigned long size);
+void *xrealloc (void *ptr, unsigned long size);
+
+void parse_args (int argc, char **argv, int optind);
+
+#endif      /* _LIB_H */
diff --git a/method.c b/method.c
new file mode 100644 (file)
index 0000000..b73a7e9
--- /dev/null
+++ b/method.c
@@ -0,0 +1,208 @@
+/******************************************************************************
+ * @file            java_method_pool_parser.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "constant.h"
+#include    "lib.h"
+#include    "method.h"
+#include    "vector.h"
+
+static int parse_attr (FILE *fp, struct method_attribute_info *attributes, int count) {
+
+    struct method_attribute_info *temp;
+    int i;
+    
+    size_t length;
+    
+    for (i = 0; i < count; i++) {
+    
+        temp = &attributes[i];
+        
+        if (fread (temp->attribute_name_index, 1, 2, fp) != 2) {
+            return -1;
+        }
+        
+        if (fread (temp->attribute_length, 1, 4, fp) != 4) {
+            return -1;
+        }
+        
+        length = array_to_integer (temp->attribute_length, 4, 1);
+        
+        if (!(temp->info = malloc (sizeof (unsigned char) * length))) {
+            return -1;
+        }
+        
+        if (fread (temp->info, 1, length, fp) != length) {
+        
+            free (temp->info);
+            return -1;
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static struct method_info *parse (FILE *fp) {
+
+    struct method_info *method_info;
+    int count;
+    
+    if (!(method_info = malloc (sizeof (*method_info)))) {
+        return 0;
+    }
+    
+    if (fread (method_info->access_flags, 1, 2, fp) != 2) {
+    
+        free (method_info);
+        return 0;
+    
+    }
+    
+    if (fread (method_info->name_index, 1, 2, fp) != 2) {
+    
+        free (method_info);
+        return 0;
+    
+    }
+    
+    if (fread (method_info->descriptor_index, 1, 2, fp) != 2) {
+    
+        free (method_info);
+        return 0;
+    
+    }
+    
+    if (fread (method_info->attributes_count, 1, 2, fp) != 2) {
+    
+        free (method_info);
+        return 0;
+    
+    }
+    
+    count = array_to_integer (method_info->attributes_count, 2, 1);
+    
+    if (!(method_info->attributes = malloc (sizeof (*method_info->attributes) * count))) {
+    
+        free (method_info);
+        return 0;
+    
+    }
+    
+    memset (method_info->attributes, 0, sizeof (*method_info->attributes) * count);
+    
+    if (parse_attr (fp, method_info->attributes, count)) {
+    
+        free (method_info->attributes);
+        free (method_info);
+        
+        return 0;
+    
+    }
+    
+    return method_info;
+
+}
+
+struct vector *parse_method_pool (FILE *fp, int count) {
+
+    struct method_info *method_info;
+    struct vector *method_pool;
+    
+    int i, j;
+    
+    if (!(method_pool = malloc (sizeof (*method_pool)))) {
+        return 0;
+    }
+    
+    memset (method_pool, 0, sizeof (*method_pool));
+    
+    for (i = 0; i < count; i++) {
+    
+        if (!(method_info = parse (fp))) {
+        
+            for (j = 0; j < method_pool->length; j++) {
+            
+                method_info = method_pool->data[j];
+                
+                free (method_info->attributes);
+                free (method_info);
+            
+            }
+            
+            free (method_pool);
+            return 0;
+        
+        }
+        
+        vec_push (method_pool, method_info);
+    
+    }
+    
+    return method_pool;
+
+}
+
+void free_method_pool (struct vector *method_pool) {
+
+    struct method_info *method_info;
+    int i;
+    
+    for (i = 0; i < method_pool->length; i++) {
+    
+        method_info = method_pool->data[i];
+        
+        free (method_info->attributes);
+        free (method_info);
+    
+    }
+
+}
+
+struct method_info *find_method_in_pool (struct constant_pool *constant_pool, struct vector *method_pool, int flags, const char *method_name, int length) {
+
+    struct constant_utf8 *name;
+    struct method_info *method;
+    
+    int access_flags, size, i;
+    
+    for (i = 0; i < method_pool->length; i++) {
+    
+        if ((method = method_pool->data[i])) {
+        
+            if (flags) {
+            
+                access_flags = array_to_integer (method->access_flags, 2, 1);
+                
+                if ((access_flags & flags) != flags) {
+                    continue;
+                }
+            
+            }
+            
+            if ((name = find_utf8 (constant_pool, array_to_integer (method->name_index, 2, 1)))) {
+            
+                size = array_to_integer (name->string_size, 2, 1);
+                
+                if (length == size) {
+                
+                    if (strncmp (method_name, (char *) name->ptr, size) == 0) {
+                        return method;
+                    }
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
diff --git a/method.h b/method.h
new file mode 100644 (file)
index 0000000..69b9a41
--- /dev/null
+++ b/method.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * @file            method.h
+ *****************************************************************************/
+#ifndef     _METHOD_H
+#define     _METHOD_H
+
+#include    "vector.h"
+
+struct method_attribute_info {
+
+    unsigned char attribute_name_index[2];
+    unsigned char attribute_length[4];
+    
+    unsigned char *info;
+
+};
+
+void free_method_pool (struct vector *method_pool);
+
+#define     ACC_PUBLIC                  (1 << 0)
+#define     ACC_PRIVATE                 (1 << 1)
+#define     ACC_PROTECTED               (1 << 2)
+
+#define     ACC_STATIC                  (1 << 3)
+
+struct method_info {
+
+    unsigned char access_flags[2];
+    unsigned char name_index[2];
+    unsigned char descriptor_index[2];
+    unsigned char attributes_count[2];
+    
+    struct method_attribute_info *attributes;
+
+};
+
+#include    <stdio.h>
+struct vector *parse_method_pool (FILE *fp, int count);
+
+#include    "constant.h"
+struct method_info *find_method_in_pool (struct constant_pool *constant_pool, struct vector *method_pool, int flags, const char *method_name, int length);
+
+#endif      /* _METHOD_H */
diff --git a/report.c b/report.c
new file mode 100644 (file)
index 0000000..8e128ef
--- /dev/null
+++ b/report.c
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * @file            report.c
+ *****************************************************************************/
+#include    <stdarg.h>
+#include    <stdio.h>
+#include    <string.h>
+
+#include    "report.h"
+
+unsigned long errors = 0;
+
+#ifndef     __PDOS__
+#if     defined (_WIN32)
+# include   <windows.h>
+static int OriginalConsoleColor = -1;
+#endif
+
+static void reset_console_color (void) {
+
+#if     defined (_WIN32)
+
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
+    
+    if (OriginalConsoleColor == -1) { return; }
+    
+    SetConsoleTextAttribute (hStdError, OriginalConsoleColor);
+    OriginalConsoleColor = -1;
+
+#else
+
+    fprintf (stderr, "\033[0m");
+
+#endif
+
+}
+
+static void set_console_color (int color) {
+
+#if     defined (_WIN32)
+
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
+    WORD wColor;
+    
+    if (OriginalConsoleColor == -1) {
+    
+        CONSOLE_SCREEN_BUFFER_INFO csbi;
+        
+        if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) {
+            return;
+        }
+        
+        OriginalConsoleColor = csbi.wAttributes;
+    
+    }
+    
+    wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF);
+    SetConsoleTextAttribute (hStdError, wColor);
+
+#else
+
+    fprintf (stderr, "\033[%dm", color);
+
+#endif
+
+}
+#endif
+
+static void output_message (const char *filename, unsigned long lineno, unsigned long idx, enum report_type type, const char *fmt, va_list ap) {
+
+    if (filename) {
+    
+        if (lineno == 0 && idx == 0) {
+            fprintf (stderr, "%s: ", filename);
+        } else {
+            fprintf (stderr, "%s:", filename);
+        }
+    
+    }
+    
+    if (lineno > 0) {
+    
+        if (idx == 0) {
+            fprintf (stderr, "%lu: ", lineno);
+        } else {
+            fprintf (stderr, "%lu:", lineno);
+        }
+    
+    }
+    
+    if (idx > 0) {
+        fprintf (stderr, "%lu: ", idx);
+    }
+    
+    if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_ERROR);
+#endif
+        
+        if (type == REPORT_ERROR) {
+            fprintf (stderr, "error:");
+        } else {
+            fprintf (stderr, "fatal error:");
+        }
+    
+    } else if (type == REPORT_INTERNAL_ERROR) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_INTERNAL_ERROR);
+#endif
+        
+        fprintf (stderr, "internal error:");
+    
+    } else if (type == REPORT_WARNING) {
+    
+#ifndef     __PDOS__
+        set_console_color (COLOR_WARNING);
+#endif
+        
+        fprintf (stderr, "warning:");
+    
+    }
+    
+#ifndef     __PDOS__
+    reset_console_color ();
+#endif
+    
+    fprintf (stderr, " ");
+    vfprintf (stderr, fmt, ap);
+    fprintf (stderr, "\n");
+    
+    if (type != REPORT_WARNING) {
+        ++errors;
+    }
+
+}
+
+unsigned long get_error_count (void) {
+    return errors;
+}
+
+void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...) {
+
+    va_list ap;
+    
+    va_start (ap, fmt);
+    output_message (filename, lineno, 0, type, fmt, ap);
+    va_end (ap);
+
+}
diff --git a/report.h b/report.h
new file mode 100644 (file)
index 0000000..8fc8758
--- /dev/null
+++ b/report.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * @file            report.h
+ *****************************************************************************/
+#ifndef     _REPORT_H
+#define     _REPORT_H
+
+enum report_type {
+
+    REPORT_ERROR = 0,
+    REPORT_FATAL_ERROR,
+    REPORT_INTERNAL_ERROR,
+    REPORT_WARNING
+
+};
+
+#if     defined (_WIN32)
+# define    COLOR_ERROR                 12
+# define    COLOR_WARNING               13
+# define    COLOR_INTERNAL_ERROR        19
+#else
+# define    COLOR_ERROR                 91
+# define    COLOR_INTERNAL_ERROR        94
+# define    COLOR_WARNING               95
+#endif
+
+unsigned long get_error_count (void);
+void report_at (const char *filename, unsigned long line_number, enum report_type type, const char *fmt, ...);
+
+#endif      /* _REPORT_H */
diff --git a/stack.c b/stack.c
new file mode 100644 (file)
index 0000000..d3312cb
--- /dev/null
+++ b/stack.c
@@ -0,0 +1,100 @@
+/******************************************************************************
+ * @file            stack.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "lib.h"
+#include    "stack.h"
+
+struct stack_frame *stack_init (int entry_size) {
+
+    struct stack_frame *stack_frame;
+    int i;
+    
+    if (!(stack_frame = malloc (sizeof (*stack_frame)))) {
+        return 0;
+    }
+    
+    memset (stack_frame, 0, sizeof (*stack_frame));
+    
+    if (!(stack_frame->store = malloc (sizeof (*stack_frame->store) * entry_size))) {
+    
+        free (stack_frame);
+        return 0;
+    
+    }
+    
+    for (i = 0; i < entry_size; i++) {
+        memset (&stack_frame->store[i], 0, sizeof (stack_frame->store[i]));
+    }
+    
+    stack_frame->size = entry_size;
+    stack_frame->max_size = entry_size;
+    
+    return stack_frame;
+
+}
+
+
+void push_double (struct stack_frame *stack, double value) {
+
+    struct stack_entry *entry = &stack->store[--stack->size];
+    memset (entry, 0, sizeof (*entry));
+    
+    memcpy (entry->entry, &value, sizeof (double));
+    entry->type = STACK_ENTRY_DOUBLE;
+
+}
+
+void push_int (struct stack_frame *stack, int value) {
+
+    struct stack_entry *entry = &stack->store[--stack->size];
+    memset (entry, 0, sizeof (*entry));
+    
+    write_to_byte_array (entry->entry, value, sizeof (int), 1);
+    entry->type = STACK_ENTRY_INT;
+
+}
+
+void push_ref (struct stack_frame *stack, int value) {
+
+    struct stack_entry *entry = &stack->store[--stack->size];
+    memset (entry, 0, sizeof (*entry));
+    
+    write_to_byte_array (entry->entry, value, sizeof (int), 1);
+    entry->type = STACK_ENTRY_REF;
+
+}
+
+double pop_double (struct stack_frame *stack) {
+
+    struct stack_entry *entry = &stack->store[stack->size++];
+    
+    double value = 0;
+    memcpy (&value, entry->entry, sizeof (double));
+    
+    return value;
+
+}
+
+int pop_int (struct stack_frame *stack) {
+
+    struct stack_entry *entry = &stack->store[stack->size++];
+    return array_to_integer (entry->entry, 4, 1);
+
+}
+
+
+struct stack_entry *pop_entry (struct stack_frame *stack) {
+    return &stack->store[stack->size++];
+}
+
+int entry_to_int (struct stack_entry *entry) {
+    return array_to_integer (entry->entry, 4, 1);
+}
+
+int is_ref_entry (struct stack_frame *stack) {
+    return (stack->store[stack->size].type == STACK_ENTRY_REF);
+}
diff --git a/stack.h b/stack.h
new file mode 100644 (file)
index 0000000..4df831d
--- /dev/null
+++ b/stack.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * @file            stack.h
+ *****************************************************************************/
+#ifndef     _STACK_H
+#define     _STACK_H
+
+struct stack_entry {
+
+    unsigned char entry[8];
+    int type;
+
+};
+
+#define     STACK_ENTRY_NONE            0
+#define     STACK_ENTRY_INT             1
+#define     STACK_ENTRY_REF             2
+#define     STACK_ENTRY_LONG            3
+#define     STACK_ENTRY_DOUBLE          4
+#define     STACK_ENTRY_FLOAT           5
+
+struct stack_frame {
+
+    int max_size, size;
+    struct stack_entry *store;
+
+};
+
+struct stack_frame *stack_init (int entry_size);
+
+void push_double (struct stack_frame *stack, double value);
+void push_int (struct stack_frame *stack, int value);
+void push_ref (struct stack_frame *stack, int value);
+
+double pop_double (struct stack_frame *stack);
+int pop_int (struct stack_frame *stack);
+
+struct stack_entry *pop_entry (struct stack_frame *stack);
+
+int entry_to_int (struct stack_entry *entry);
+int is_ref_entry (struct stack_frame *stack);
+
+#endif      /* _STACK_H */
diff --git a/vector.c b/vector.c
new file mode 100755 (executable)
index 0000000..723993a
--- /dev/null
+++ b/vector.c
@@ -0,0 +1,54 @@
+/******************************************************************************\r
+ * @file            vector.c\r
+ *****************************************************************************/\r
+#include    <stddef.h>\r
+#include    <stdlib.h>\r
+\r
+#include    "vector.h"\r
+\r
+extern void *xrealloc (void *__ptr, unsigned int __size);\r
+\r
+int vec_adjust (struct vector *vec, int length) {\r
+\r
+    if (vec->capacity <= length) {\r
+    \r
+        if (vec->capacity == 0) {\r
+            vec->capacity = 16;\r
+        } else {\r
+            vec->capacity <<= 1;\r
+        }\r
+        \r
+        vec->data = xrealloc (vec->data, sizeof (*(vec->data)) * vec->capacity);\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+void *vec_pop (struct vector *vec) {\r
+\r
+    if (!vec || vec == NULL) {\r
+        return NULL;\r
+    }\r
+    \r
+    if (vec->length == 0) {\r
+        return NULL;\r
+    }\r
+    \r
+    return vec->data[--vec->length];\r
+\r
+}\r
+\r
+int vec_push (struct vector *vec, void *elem) {\r
+\r
+    int ret;\r
+    \r
+    if ((ret = vec_adjust (vec, vec->length)) != 0) {\r
+        return ret;\r
+    }\r
+    \r
+    vec->data[vec->length++] = elem;\r
+    return 0;\r
+\r
+}\r
diff --git a/vector.h b/vector.h
new file mode 100755 (executable)
index 0000000..3da05e1
--- /dev/null
+++ b/vector.h
@@ -0,0 +1,19 @@
+/******************************************************************************\r
+ * @file            vector.h\r
+ *****************************************************************************/\r
+#ifndef     _VECTOR_H\r
+#define     _VECTOR_H\r
+\r
+struct vector {\r
+\r
+    void **data;\r
+    int capacity, length;\r
+\r
+};\r
+\r
+int vec_adjust (struct vector *vec, int length);\r
+int vec_push (struct vector *vec, void *elem);\r
+\r
+void *vec_pop (struct vector *vec);\r
+\r
+#endif      /* _VECTOR_H */\r
diff --git a/vm.c b/vm.c
new file mode 100644 (file)
index 0000000..95356ae
--- /dev/null
+++ b/vm.c
@@ -0,0 +1,864 @@
+/******************************************************************************
+ * @file            vm.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "class.h"
+#include    "cstr.h"
+#include    "lib.h"
+#include    "method.h"
+#include    "stack.h"
+#include    "vector.h"
+#include    "vm.h"
+
+int invoke_java_lang_library (struct constant_pool *p, struct stack_frame *stack, char *class_name, char *method_name);
+
+static char *java_lib[] = {
+
+    "java/io/PrintStream",
+    "java/lang/StringBuilder"
+
+};
+
+struct cstring string_builder_buffer = { 0 };;
+
+struct local_variables { int integer[10]; } local_variables = { 0 };
+struct vector vec_classes = { 0 };
+
+static double get_double_parameter (struct stack_frame *stack, struct constant_pool *p) {
+
+    if (is_ref_entry (stack)) {
+        return get_double_from_constant_pool (p, pop_int (stack));
+    }
+    
+    return pop_double (stack);
+
+}
+
+typedef int (*opcode_func) (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class);
+
+typedef struct {
+
+    const char *name;
+    
+    unsigned char opcode;
+    int offset;
+    
+    opcode_func func;
+
+} byte_code;
+
+static int op_aload_0 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 0);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_bipush (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, opcode[0][1]);
+    (void) java_class;
+    
+    *opcode = *opcode + 2;
+    return 0;
+
+}
+
+static int op_d2i (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, (int) pop_double (stack));
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_dadd (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    double value1 = get_double_parameter (stack, java_class->constant_pool);
+    double value2 = get_double_parameter (stack, java_class->constant_pool);
+    
+    push_double (stack, value1 + value2);
+    *opcode = *opcode + 1;
+    
+    return 0;
+
+}
+
+static int op_dconst_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_double (stack, 1.0f);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_dmul (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    double value1 = get_double_parameter (stack, java_class->constant_pool);
+    double value2 = get_double_parameter (stack, java_class->constant_pool);
+    
+    push_double (stack, value1 * value2);
+    *opcode = *opcode + 1;
+    
+    return 0;
+
+}
+
+static int op_dup (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    struct stack_entry *entry = pop_entry (stack);
+    int value = entry_to_int (entry);
+    
+    if (entry->type == STACK_ENTRY_INT) {
+    
+        push_int (stack, value);
+        push_int (stack, value);
+    
+    } else {
+    
+        push_ref (stack, value);
+        push_ref (stack, value);
+    
+    }
+    
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_getstatic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    unsigned short field_index = (opcode[0][1] << 8) | opcode[0][2];
+    
+    /*struct constant_pool *p = java_class->constant_pool;
+    struct vector *field_refs = &p->vec_field_refs;
+    
+    struct constant_field_ref *ref;
+    struct constant_nat *nat;
+    
+    int i;
+    
+    for (i = 0; i < field_refs->length; i++) {
+    
+        ref = field_refs->data[i];
+        
+        if ((nat = find_nat (p, array_to_integer (ref->nat_index, 2, 1)))) {
+            printf ("FUCK YEAHHH\n");
+        }
+    
+    }*/
+    
+    push_ref (stack, field_index);
+    (void) java_class;
+    
+    *opcode = *opcode + 3;
+    return 0;
+
+}
+
+static int op_iadd (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int result = pop_int (stack) + pop_int (stack);
+    
+    push_int (stack, result);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_0 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 0);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 1);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 2);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 3);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_4 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 4);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iconst_5 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, 5);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_idiv (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int value2 = pop_int (stack), value1 = pop_int (stack);
+    
+    push_int (stack, value1 / value2);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iload (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, local_variables.integer[opcode[0][1]]);
+    (void) java_class;
+    
+    *opcode = *opcode + 2;
+    return 0;
+
+}
+
+static int op_iload_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, local_variables.integer[1]);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iload_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, local_variables.integer[2]);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_iload_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, local_variables.integer[3]);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_imul (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int result = pop_int (stack) * pop_int (stack);
+    
+    push_int (stack, result);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+/*static int op_invokedynamic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    struct constant_pool *p = java_class->constant_pool;
+    unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2];
+    
+    struct vector *methods = &p->vec_invoke_dynamic;
+    struct constant_invoke_dynamic *method;
+    
+    *opcode = *opcode + 5;
+    
+    if ((method = find_invoke_dynamic (p, method_index))) {
+    
+        struct constant_nat *nat;
+        char name[255];
+        
+        if ((nat = find_nat (p, array_to_integer (method->nat_index, 2, 1)))) {
+        
+            get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, name);
+            printf ("YAYAY: %s\n", name);
+        
+        }
+    
+    }
+    
+    (void) stack;
+    
+    if (method_index < methods->length) {
+    
+        if ((method = methods->data[method_index])) {
+            return execute_method (method, stack, java_class);
+        }
+    
+    }
+    
+    if (vec_classes.length > 0) {
+    
+        java_class = vec_classes.data[vec_classes.length - 1];
+        
+        p = java_class->constant_pool;
+        method_refs = java_class->method_pool;
+        
+        if (method_index < method_refs->length) {
+        
+            if ((method = method_refs->data[method_index])) {
+                return execute_method (method, stack, java_class);
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}*/
+
+static int op_invokespecial (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2];
+    
+    struct vector *methods = java_class->method_pool;
+    struct method_info *method;
+    
+    *opcode = *opcode + 3;
+    
+    if (method_index < methods->length) {
+    
+        if ((method = methods->data[method_index])) {
+            return execute_method (method, stack, java_class);
+        }
+    
+    }
+    
+    /*if (vec_classes.length > 0) {
+    
+        java_class = vec_classes.data[vec_classes.length - 1];
+        
+        p = java_class->constant_pool;
+        method_refs = java_class->method_pool;
+        
+        if (method_index < method_refs->length) {
+        
+            if ((method = method_refs->data[method_index])) {
+                return execute_method (method, stack, java_class);
+            }
+        
+        }
+    
+    }*/
+    
+    return 0;
+
+}
+
+static int op_invokestatic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2];
+    
+    struct constant_pool *p = java_class->constant_pool;
+    struct vector *methods = java_class->method_pool;
+    
+    char class_name[255];
+    char method_name[255];
+    char method_type[255];
+    
+    struct method_info *method;
+    int ret = -1;
+    
+    *opcode = *opcode + 3;
+    
+    if (method_index < methods->length) {
+    
+        method = methods->data[method_index];
+        memset(method_name, 0, 255);
+        
+        get_utf8_string (p, array_to_integer (method->name_index, 2, 1), 255, method_name);
+        printf ("method_name: %s\n", method_name);
+    
+    } else {
+    
+        struct constant_method_ref *method_ref;
+        struct constant_class_ref *class_ref;
+        struct constant_nat *nat;
+        
+        if ((method_ref = find_method_ref (p, method_index))) {
+        
+            if ((class_ref = find_class_ref (p, array_to_integer (method_ref->class_index, 2, 1))) && (nat = find_nat (p, array_to_integer (method_ref->nat_index, 2, 1)))) {
+            
+                get_utf8_string (p, array_to_integer (class_ref->string_index, 2, 1), 255, class_name);
+                get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, method_name);
+                get_utf8_string (p, array_to_integer (nat->type_index, 2, 1), 255, method_type);
+                
+                if ((ret = invoke_java_lang_library (p, stack, class_name, method_name))) {
+                
+                    struct java_class *class = parse_java_class (class_name);
+                    
+                    if ((method = find_method_in_pool (class->constant_pool, class->method_pool, ACC_STATIC, method_name, strlen (method_name)))) {
+                        ret = execute_method (method, stack, class);
+                    }
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return ret;
+
+}
+
+static int op_invokevirtual (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    struct constant_pool *p = java_class->constant_pool;
+    unsigned short object_ref = (opcode[0][1] << 8) | opcode[0][2];
+    
+    char class_name[255];
+    char utf8[255];
+    char method_name[255];
+    
+    struct constant_method_ref *method_ref;
+    *opcode = *opcode + 3;
+    
+    if ((method_ref = find_method_ref (p, object_ref))) {
+    
+        struct constant_class_ref *class_ref = find_class_ref (p, array_to_integer (method_ref->class_index, 2, 1));
+        struct constant_nat *nat = find_nat (p, array_to_integer (method_ref->nat_index, 2, 1));
+        
+        if (class_ref && nat) {
+        
+            get_utf8_string (p, array_to_integer (class_ref->string_index, 2, 1), 255, class_name);
+            
+            if (strcmp (class_name, "java/io/PrintStream") == 0) {
+            
+                struct stack_entry *entry = pop_entry (stack);
+                struct constant_string_ref *string_ref;
+                
+                if (entry->type == STACK_ENTRY_REF) {
+                
+                    if ((string_ref = find_string_ref (p, entry_to_int (entry)))) {
+                    
+                        get_utf8_string (p, array_to_integer (string_ref->string_index, 2, 1), 255, utf8);
+                        cstr_cat (&string_builder_buffer, utf8, strlen (utf8));
+                    
+                    }
+                
+                } else if (entry->type == STACK_ENTRY_INT) {
+                
+                    sprintf (utf8, "%d", entry_to_int (entry));
+                    cstr_cat (&string_builder_buffer, utf8, strlen (utf8));
+                
+                }
+                
+                cstr_ccat (&string_builder_buffer, '\0');
+                printf ("%s\n", (char *) string_builder_buffer.data);
+                
+                cstr_free (&string_builder_buffer);
+                memset (&string_builder_buffer, 0, sizeof (string_builder_buffer));
+                
+                return 0;
+            
+            } else if (strcmp (class_name, "java/lang/StringBuilder") == 0) {
+            
+                struct stack_entry *entry = pop_entry (stack);
+                struct constant_string_ref *string_ref;
+                
+                if (entry->type == STACK_ENTRY_REF) {
+                
+                    if ((string_ref = find_string_ref (p, entry_to_int (entry)))) {
+                    
+                        get_utf8_string (p, array_to_integer (string_ref->string_index, 2, 1), 255, utf8);
+                        cstr_cat (&string_builder_buffer, utf8, strlen (utf8));
+                    
+                    }
+                
+                } else if (entry->type == STACK_ENTRY_INT) {
+                
+                    sprintf (utf8, "%d", entry_to_int (entry));
+                    cstr_cat (&string_builder_buffer, utf8, strlen (utf8));
+                
+                }
+                
+                cstr_ccat (&string_builder_buffer, '\0');
+                string_builder_buffer.size--;
+                
+                return 0;
+            
+            } else {
+            
+                struct stack_entry *entry = pop_entry (stack);
+                struct method_info *method;
+                
+                get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, method_name);
+                
+                if (entry->type == STACK_ENTRY_REF) {
+                
+                    struct java_class *class = parse_java_class (class_name);
+                    
+                    /*struct constant_field_ref *ref;
+                    char temp[255];
+                    
+                    printf ("index: %d\n", index);*/
+                    
+                    /*if ((ref = find_field_ref (p, index))) {*/
+                    
+                        /*printf ("FUCKKKK! %ld\n", array_to_integer (ref->class_index, 2, 1));
+                        exit (1);*/
+                        
+                        /*get_utf8_string (p, array_to_integer (ref->string_index, 2, 1), 255, temp);*/
+                        /*printf ("%s\n", temp);*/
+                        
+                        if ((method = find_method_in_pool (class->constant_pool, class->method_pool, 0, method_name, strlen (method_name)))) {
+                            return execute_method (method, stack, class);
+                        }
+                    
+                    /*}*/
+                
+                } else if (entry->type == STACK_ENTRY_INT) {
+                
+                    if (vec_classes.length > 0) {
+                    
+                        struct java_class *class = vec_pop (&vec_classes);
+                        
+                        if (strcmp (class->class_name, class_name) == 0) {
+                        
+                            if ((method = find_method_in_pool (class->constant_pool, class->method_pool, 0, method_name, strlen (method_name)))) {
+                                return execute_method (method, stack, class);
+                            }
+                        
+                        }
+                    
+                    }
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return -1;
+
+}
+
+static int op_irem (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int value1 = pop_int (stack), value2 = pop_int (stack);
+    
+    push_int (stack, value2 % value1);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_istore (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    local_variables.integer[opcode[0][1]] = pop_int (stack);
+    (void) java_class;
+    
+    *opcode = *opcode + 2;
+    return 0;
+
+}
+
+static int op_istore_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    local_variables.integer[1] = pop_int (stack);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_istore_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    local_variables.integer[2] = pop_int (stack);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_istore_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    local_variables.integer[3] = pop_int (stack);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_isub (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int value2 = pop_int (stack), value1 = pop_int (stack);
+    
+    push_int (stack, value1 - value2);
+    (void) java_class;
+    
+    *opcode = *opcode + 1;
+    return 0;
+
+}
+
+static int op_ldc (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_ref (stack, opcode[0][1]);
+    *opcode = *opcode + 2;
+    
+    (void) java_class;
+    return 0;
+
+}
+
+static int op_ldc2_w (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    int index = (opcode[0][1] << 8) | opcode[0][2];
+    
+    push_ref (stack, index);
+    *opcode = *opcode + 3;
+    
+    (void) java_class;
+    return 0;
+
+}
+
+static int op_new (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    unsigned short object_ref = (opcode[0][1] << 8) | opcode[0][2];
+    
+    struct constant_class_ref *ref;
+    struct java_class *class;
+    
+    char class_name[255];
+    int ret = -1;
+    
+    unsigned long count = (sizeof (java_lib) / sizeof (java_lib[0]));
+    unsigned long i;
+    
+    *opcode = *opcode + 3;
+    
+    if ((ref = find_class_ref (java_class->constant_pool, object_ref))) {
+    
+        get_utf8_string (java_class->constant_pool, array_to_integer (ref->string_index, 2, 1), 255, class_name);
+        
+        for (i = 0; i < count; i++) {
+        
+            if (strcmp (java_lib[i], class_name) == 0) {
+                return 0;
+            }
+        
+        }
+        
+        if ((class = parse_java_class (class_name))) {
+            ret = vec_push (&vec_classes, class);
+        }
+    
+    }
+    
+    (void) stack;
+    return ret;
+
+}
+
+static int op_return (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    *opcode = *opcode + 1;
+    
+    (void) stack;
+    (void) java_class;
+    
+    return -1;
+
+}
+
+static int op_sipush (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) {
+
+    push_int (stack, (opcode[0][1] << 8) | opcode[0][2]);
+    (void) java_class;
+    
+    *opcode = *opcode + 3;
+    return 0;
+
+}
+
+static byte_code opcodes[] = {
+
+    { "aload_0",        0x2A,   1,  op_aload_0          },
+    { "bipush",         0x10,   2,  op_bipush           },
+    { "dup",            0x59,   1,  op_dup              },
+    { "getstatic",      0xB2,   3,  op_getstatic        },
+    { "iadd",           0x60,   1,  op_iadd             },
+    { "iconst_0",       0x03,   1,  op_iconst_0         },
+    { "iconst_1",       0x04,   1,  op_iconst_1         },
+    { "iconst_2",       0x05,   1,  op_iconst_2         },
+    { "iconst_3",       0x06,   1,  op_iconst_3         },
+    { "iconst_4",       0x07,   1,  op_iconst_4         },
+    { "iconst_5",       0x08,   1,  op_iconst_5         },
+    { "dconst_1",       0x0F,   1,  op_dconst_1         },
+    { "idiv",           0x6C,   1,  op_idiv             },
+    { "imul",           0x68,   1,  op_imul             },
+    { "dadd",           0x63,   1,  op_dadd             },
+    { "dmul",           0x6B,   1,  op_dmul             },
+    { "d2i",            0x8e,   1,  op_d2i              },
+    { "invokespecial",  0xB7,   3,  op_invokespecial    },
+    { "invokevirtual",  0xB6,   3,  op_invokevirtual    },
+    { "invokestatic",   0xB8,   3,  op_invokestatic     },
+    /*{ "invokedynamic",  0xBA,   3,  op_invokedynamic    },*/
+    { "iload",          0x15,   2,  op_iload            },
+    { "iload_1",        0x1B,   1,  op_iload_1          },
+    { "iload_2",        0x1C,   1,  op_iload_2          },
+    { "iload_3",        0x1D,   1,  op_iload_3          },
+    { "istore",         0x36,   2,  op_istore           },
+    { "istore_1",       0x3C,   1,  op_istore_1         },
+    { "istore_2",       0x3D,   1,  op_istore_2         },
+    { "istore_3",       0x3E,   1,  op_istore_3         },
+    { "isub",           0x64,   1,  op_isub             },
+    { "ldc",            0x12,   2,  op_ldc              },
+    { "ldc2_w",         0x14,   3,  op_ldc2_w           },
+    { "new",            0xBB,   3,  op_new              },
+    { "irem",           0x70,   1,  op_irem             },
+    { "sipush",         0x11,   3,  op_sipush           },
+    { "return",         0xB1,   1,  op_return           }
+
+};
+
+static unsigned long opcodes_size = (sizeof (opcodes) / sizeof (opcodes[0]));
+
+static opcode_func find_opcode_func (unsigned char op) {
+
+    unsigned long i;
+    
+    for (i = 0; i < opcodes_size; i++) {
+    
+        if (opcodes[i].opcode == op) {
+            return opcodes[i].func;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int convert_to_code_attribute (struct code_attribute *ca, struct method_attribute_info *attr) {
+
+    unsigned long length;
+    int info_p = 0;
+    
+    memcpy (ca->max_stack, attr->info + info_p, 2);
+    info_p += 2;
+    
+    memcpy (ca->max_locals, attr->info + info_p, 2);
+    info_p += 2;
+    
+    memcpy (ca->code_length, attr->info + info_p, 4);
+    info_p += 4;
+    
+    length = array_to_integer (ca->code_length, 4, 1);
+    
+    if (!(ca->code = malloc (sizeof (unsigned char) * length))) {
+        return -1;
+    }
+    
+    memcpy (ca->code, attr->info + info_p, length);
+    return 0;
+
+}
+
+int execute_method (struct method_info *method, struct stack_frame *stack, struct java_class *java_class) {
+
+    unsigned long count = array_to_integer (method->attributes_count, 2, 1);
+    unsigned char *pc;
+    
+    char name[255];
+    unsigned long i;
+    
+    struct code_attribute ca;
+    opcode_func func;
+    
+    memset (&ca, 0, sizeof (ca));
+    
+    for (i = 0; i < count; i++) {
+    
+        if (convert_to_code_attribute (&ca, &method->attributes[i])) {
+            break;
+        }
+        
+        get_utf8_string (java_class->constant_pool, array_to_integer (ca.attribute_name_index, 2, 1), 255, name);
+        
+        if (memcmp (name, "code", 4) == 0) {
+            continue;
+        }
+        
+        pc = ca.code;
+        
+        for (;;) {
+        
+            if (!(func = find_opcode_func (pc[0]))) {
+                break;
+            }
+            
+            if (func (&pc, stack, java_class)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
diff --git a/vm.h b/vm.h
new file mode 100644 (file)
index 0000000..807c15a
--- /dev/null
+++ b/vm.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * @file            vm.h
+ *****************************************************************************/
+#ifndef     _VM_H
+#define     _VM_H
+
+struct code_attribute {
+
+    unsigned char attribute_name_index[2];
+    unsigned char attribute_length[4];
+    
+    unsigned char max_stack[2];
+    unsigned char max_locals[2];
+    
+    unsigned char code_length[4];
+    unsigned char *code;
+
+};
+
+#include    "class.h"
+#include    "method.h"
+#include    "stack.h"
+
+int execute_method (struct method_info *method, struct stack_frame *stack, struct java_class *java_class);
+
+#endif      /* _VM_H */