--- /dev/null
+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>
--- /dev/null
+#******************************************************************************
+# @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
--- /dev/null
+#******************************************************************************
+# @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 $@ $^
--- /dev/null
+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.
--- /dev/null
+/******************************************************************************
+ * @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);
+
+ }
+
+ }
+
+ }
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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);
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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;
+
+ }
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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);
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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);
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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);
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************\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
--- /dev/null
+/******************************************************************************\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
--- /dev/null
+/******************************************************************************
+ * @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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */