From 95c4bff51b96926b049c28394b1bcb23172f970c Mon Sep 17 00:00:00 2001
From: Joel Dice <git@seibutsu.mailsnare.net>
Date: Wed, 20 Jun 2007 19:38:02 -0600
Subject: [PATCH] lots of bugfixes

---
 makefile               |  37 ++--
 src/constants.h        | 389 +++++++++++++++++++++--------------------
 src/main.cpp           |  29 ++-
 src/type-generator.cpp |  13 +-
 src/vm.cpp             | 377 +++++++++++++++++++++++++--------------
 5 files changed, 498 insertions(+), 347 deletions(-)

diff --git a/makefile b/makefile
index cac6103639..80d08df336 100644
--- a/makefile
+++ b/makefile
@@ -8,6 +8,7 @@ cxx = g++
 cc = gcc
 vg = nice valgrind --leak-check=full --num-callers=32 --db-attach=yes \
 	--freelist-vol=100000000
+javac = javac
 
 warnings = -Wall -Wextra -Werror -Wold-style-cast -Wunused-parameter \
 	-Winit-self -Wconversion
@@ -51,7 +52,6 @@ interpreter-sources = \
 	$(src)/main.cpp
 interpreter-objects = $(call cpp-objects,$(interpreter-sources),$(src))
 interpreter-cflags = $(slow) $(cflags)
-input = Test
 
 generator-headers = \
 	$(src)/input.h \
@@ -74,32 +74,42 @@ fast-objects = $(patsubst $(bld)/%,$(bld)/fast-%,$(interpreter-objects))
 fast-executable = $(bld)/fast-vm
 fast-cflags = $(fast) $(cflags)
 
+input = $(bld)/classes/Test.class
+input-depends = \
+	$(bld)/classes/java/lang/Object.class \
+	$(bld)/classes/java/lang/Class.class \
+	$(bld)/classes/vm/VM.class
+
+gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
+
 .PHONY: build
 build: $(executable)
 
+$(input): $(input-depends)
+
 .PHONY: run
-run: $(executable)
-	$(<) $(input)
+run: $(executable) $(input)
+	$(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
 
 .PHONY: debug
-debug: $(executable)
-	gdb --args $(<) $(input)
+debug: $(executable) $(input)
+	gdb --args $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
 
 .PHONY: fast
 fast: $(fast-executable)
 	ls -lh $(<)
 
 .PHONY: vg
-vg: $(executable)
-	$(vg) $(<) $(input)
+vg: $(executable) $(input)
+	$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
 
 .PHONY: test
-test: $(test-executable)
-	$(vg) $(<) $(input)
+test: $(test-executable) $(input)
+	$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
 
 .PHONY: stress
-stress: $(stress-executable)
-	$(vg) $(<) $(input)
+stress: $(stress-executable) $(input)
+	$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
 
 .PHONY: run-all
 run-all: $(executable)
@@ -136,6 +146,11 @@ $(bld)/fast-vm.o: \
 $(bld)/type-generator.o: \
 	$(generator-headers)
 
+$(bld)/classes/%.class: $(inp)/%.java
+	@echo "compiling $(@)"
+	@mkdir -p $(dir $(@))
+	$(javac) -bootclasspath $(inp) -classpath $(inp) -d $(bld)/classes $(<)
+
 $(stdcpp-objects): $(bld)/%.o: $(src)/%.cpp
 	@echo "compiling $(@)"
 	@mkdir -p $(dir $(@))
diff --git a/src/constants.h b/src/constants.h
index 4307fc0598..def9058369 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -4,191 +4,210 @@
 namespace vm {
 
 enum OpCode {
-  aaload,
-  aastore,
-  aconst_null,
-  aload,
-  aload_0,
-  aload_1,
-  aload_2,
-  aload_3,
-  anewarray,
-  areturn,
-  arraylength,
-  astore,
-  astore_0,
-  astore_1,
-  astore_2,
-  astore_3,
-  athrow,
-  baload,
-  bastore,
-  bipush,
-  breakpoint,
-  caload,
-  castore,
-  checkcast,
-  d2f,
-  d2i,
-  d2l,
-  dadd,
-  daload,
-  dastore,
-  dcmpg,
-  dcmpl,
-  dconst,
-  ddiv,
-  dload,
-  dmul,
-  dneg,
-  drem,
-  dreturn,
-  dstore,
-  dsub,
-  dup,
-  dup_x1,
-  dup_x2,
-  dup2,
-  dup2_x1,
-  dup2_x2,
-  f2d,
-  f2i,
-  f2l,
-  fadd,
-  faload,
-  fastore,
-  fcmpg,
-  fcmpl,
-  fconst,
-  fdiv,
-  fload,
-  fmul,
-  fneg,
-  frem,
-  freturn,
-  fstore,
-  fsub,
-  getfield,
-  getstatic,
-  goto_,
-  goto_w,
-  i2b,
-  i2c,
-  i2d,
-  i2f,
-  i2l,
-  i2s,
-  iadd,
-  iaload,
-  iand,
-  iastore,
-  iconst_0,
-  iconst_1,
-  iconst_2,
-  iconst_3,
-  iconst_4,
-  iconst_5,
-  idiv,
-  if_,
-  if_acmpeq,
-  if_acmpne,
-  if_icmpeq,
-  if_icmpne,
-  if_icmpgt,
-  if_icmpge,
-  if_icmplt,
-  if_icmple,
-  ifeq,
-  ifge,
-  ifgt,
-  ifle,
-  iflt,
-  ifne,
-  ifnonnull,
-  ifnull,
-  iinc,
-  iload,
-  iload_0,
-  iload_1,
-  iload_2,
-  iload_3,
-  impdep1,
-  impdep2,
-  imul,
-  ineg,
-  instanceof,
-  invokeinterface,
-  invokespecial,
-  invokestatic,
-  invokevirtual,
-  ior,
-  irem,
-  ireturn,
-  ishl,
-  ishr,
-  istore,
-  istore_0,
-  istore_1,
-  istore_2,
-  istore_3,
-  isub,
-  iushr,
-  ixor,
-  jsr,
-  jsr_w,
-  l2d,
-  l2f,
-  l2i,
-  ladd,
-  laload,
-  land,
-  lastore,
-  lcmp,
-  lconst_0,
-  lconst_1,
-  ldc,
-  ldc_w,
-  ldc2_w,
-  ldiv,
-  lload,
-  lload_0,
-  lload_1,
-  lload_2,
-  lload_3,
-  lmul,
-  lneg,
-  lookupswitch,
-  lor,
-  lrem,
-  lreturn,
-  lshl,
-  lshr,
-  lstore,
-  lstore_0,
-  lstore_1,
-  lstore_2,
-  lstore_3,
-  lsub,
-  lushr,
-  lxor,
-  monitorenter,
-  monitorexit,
-  multianewarray,
-  new_,
-  newarray,
-  nop,
-  pop,
-  pop2,
-  putfield,
-  putstatic,
-  ret,
-  return_,
-  saload,
-  sastore,
-  sipush,
-  swap,
-  tableswitch,
-  wide
+  aaload = 0x32,
+  aastore = 0x53,
+  aconst_null = 0x01,
+  aload = 0x19,
+  aload_0 = 0x2a,
+  aload_1 = 0x2b,
+  aload_2 = 0x2c,
+  aload_3 = 0x2d,
+  anewarray = 0xbd,
+  areturn = 0xb0,
+  arraylength = 0xbe,
+  astore = 0x3a,
+  astore_0 = 0x4b,
+  astore_1 = 0x4c,
+  astore_2 = 0x4d,
+  astore_3 = 0x4e,
+  athrow = 0xbf,
+  baload = 0x33,
+  bastore = 0x54,
+  bipush = 0x10,
+  breakpoint = 0xca,
+  caload = 0x34,
+  castore = 0x55,
+  checkcast = 0xc0,
+  d2f = 0x90,
+  d2i = 0x8e,
+  d2l = 0x8f,
+  dadd = 0x63,
+  daload = 0x31,
+  dastore = 0x52,
+  dcmpg = 0x98,
+  dcmpl = 0x97,
+  dconst_0 = 0x0e,
+  dconst_1 = 0x0f,
+  ddiv = 0x6f,
+  dload = 0x18,
+  dload_0 = 0x26,
+  dload_1 = 0x27,
+  dload_2 = 0x28,
+  dload_3 = 0x29,
+  dmul = 0x6b,
+  dneg = 0x77,
+  drem = 0x73,
+  dreturn = 0xaf,
+  dstore = 0x39,
+  dstore_0 = 0x47,
+  dstore_1 = 0x48,
+  dstore_2 = 0x49,
+  dstore_3 = 0x4a,
+  dsub = 0x67,
+  dup = 0x59,
+  dup_x1 = 0x5a,
+  dup_x2 = 0x5b,
+  dup2 = 0x5c,
+  dup2_x1 = 0x5d,
+  dup2_x2 = 0x5e,
+  f2d = 0x8d,
+  f2i = 0x8b,
+  f2l = 0x8c,
+  fadd = 0x62,
+  faload = 0x30,
+  fastore = 0x51,
+  fcmpg = 0x96,
+  fcmpl = 0x95,
+  fconst_0 = 0x0b,
+  fconst_1 = 0x0c,
+  fconst_2 = 0x0d,
+  fdiv = 0x6e,
+  fload = 0x17,
+  fload_0 = 0x22,
+  fload_1 = 0x23,
+  fload_2 = 0x24,
+  fload_3 = 0x25,
+  fmul = 0x6a,
+  fneg = 0x76,
+  frem = 0x72,
+  freturn = 0xae,
+  fstore = 0x38,
+  fstore_0 = 0x43,
+  fstore_1 = 0x44,
+  fstore_2 = 0x45,
+  fstore_3 = 0x46,
+  fsub = 0x66,
+  getfield = 0xb4,
+  getstatic = 0xb2,
+  goto_ = 0xa7,
+  goto_w = 0xc8,
+  i2b = 0x91,
+  i2c = 0x92,
+  i2d = 0x87,
+  i2f = 0x86,
+  i2l = 0x85,
+  i2s = 0x93,
+  iadd = 0x60,
+  iaload = 0x2e,
+  iand = 0x73,
+  iastore = 0x4f,
+  iconst_m1 = 0x02,
+  iconst_0 = 0x03,
+  iconst_1 = 0x04,
+  iconst_2 = 0x05,
+  iconst_3 = 0x06,
+  iconst_4 = 0x07,
+  iconst_5 = 0x08,
+  idiv = 0x6c,
+  if_acmpeq = 0xa5,
+  if_acmpne = 0xa6,
+  if_icmpeq = 0x9f,
+  if_icmpne = 0xa0,
+  if_icmpgt = 0xa1,
+  if_icmpge = 0xa2,
+  if_icmplt = 0xa3,
+  if_icmple = 0xa4,
+  ifeq = 0x99,
+  ifge = 0x9c,
+  ifgt = 0x9d,
+  ifle = 0x9e,
+  iflt = 0x9b,
+  ifne = 0x9a,
+  ifnonnull = 0xc7,
+  ifnull = 0xc6,
+  iinc = 0x84,
+  iload = 0x15,
+  iload_0 = 0x1a,
+  iload_1 = 0x1b,
+  iload_2 = 0x1c,
+  iload_3 = 0x1d,
+  impdep1 = 0xfe,
+  impdep2 = 0xff,
+  imul = 0x68,
+  ineg = 0x74,
+  instanceof = 0xc1,
+  invokeinterface = 0xb9,
+  invokespecial = 0xb7,
+  invokestatic = 0xb8,
+  invokevirtual = 0xb6,
+  ior = 0x80,
+  irem = 0x70,
+  ireturn = 0xac,
+  ishl = 0x78,
+  ishr = 0x7a,
+  istore = 0x36,
+  istore_0 = 0x3b,
+  istore_1 = 0x3c,
+  istore_2 = 0x3d,
+  istore_3 = 0x3e,
+  isub = 0x64,
+  iushr = 0x7c,
+  ixor = 0x82,
+  jsr = 0xa8,
+  jsr_w = 0xc9,
+  l2d = 0x8a,
+  l2f = 0x89,
+  l2i = 0x88,
+  ladd = 0x61,
+  laload = 0x2f,
+  land = 0x7f,
+  lastore = 0x50,
+  lcmp = 0x94,
+  lconst_0 = 0x09,
+  lconst_1 = 0x0a,
+  ldc = 0x12,
+  ldc_w = 0x13,
+  ldc2_w = 0x14,
+  ldiv = 0x6d,
+  lload = 0x16,
+  lload_0 = 0x1e,
+  lload_1 = 0x1f,
+  lload_2 = 0x20,
+  lload_3 = 0x21,
+  lmul = 0x69,
+  lneg = 0x75,
+  lookupswitch = 0xab,
+  lor = 0x81,
+  lrem = 0x71,
+  lreturn = 0xad,
+  lshl = 0x79,
+  lshr = 0x7b,
+  lstore = 0x37,
+  lstore_0 = 0x3f,
+  lstore_1 = 0x40,
+  lstore_2 = 0x41,
+  lstore_3 = 0x42,
+  lsub = 0x65,
+  lushr = 0x7d,
+  lxor = 0x83,
+  monitorenter = 0xc2,
+  monitorexit = 0xc3,
+  multianewarray = 0xc5,
+  new_ = 0xbb,
+  newarray = 0xbc,
+  nop = 0x00,
+  pop = 0x57,
+  pop2 = 0x58,
+  putfield = 0xb5,
+  putstatic = 0xb3,
+  ret = 0xa9,
+  return_ = 0xb1,
+  saload = 0x35,
+  sastore = 0x56,
+  sipush = 0x11,
+  swap = 0x5f,
+  tableswitch = 0xaa,
+  wide = 0xc4
 };
 
 enum TypeCode {
diff --git a/src/main.cpp b/src/main.cpp
index 8679a28c65..49d07dec4c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -42,13 +42,19 @@ class System: public vm::System {
     if (up == 0) abort();
 
     *up = *size;
+    count += *up;
+
     return up + 1;
   }
 
   virtual void free(const void* p) {
     if (p) {
       const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
+      if (count < *up) {
+        abort();
+      }
       count -= *up;
+
       ::free(const_cast<uintptr_t*>(up));
     }
   }
@@ -71,15 +77,18 @@ class System: public vm::System {
 };
 
 const char*
-append(vm::System* s, const char* a, const char* b, const char* c)
+append(vm::System* s, const char* a, const char* b, const char* c,
+       const char* d)
 {
   unsigned al = strlen(a);
   unsigned bl = strlen(b);
   unsigned cl = strlen(c);
-  char* p = static_cast<char*>(s->allocate(al + bl + cl + 1));
+  unsigned dl = strlen(d);
+  char* p = static_cast<char*>(s->allocate(al + bl + cl + dl + 1));
   memcpy(p, a, al);
   memcpy(p + al, b, bl);
-  memcpy(p + al + bl, c, cl + 1);
+  memcpy(p + al + bl, c, cl);
+  memcpy(p + al + bl + cl, d, dl + 1);
   return p;
 }
 
@@ -92,7 +101,8 @@ class ClassFinder: public vm::ClassFinder {
 
   class Data: public vm::ClassFinder::Data {
    public:
-    Data(uint8_t* start, size_t length):
+    Data(vm::System* system, uint8_t* start, size_t length):
+      system(system),
       start_(start),
       length_(length)
     { }
@@ -109,18 +119,22 @@ class ClassFinder: public vm::ClassFinder {
       if (start_) {
         munmap(start_, length_);
       }
+      system->free(this);
     }
 
+    vm::System* system;
     uint8_t* start_;
     size_t length_;
   };
 
   virtual Data* find(const char* className) {
-    Data* d = new (system->allocate(sizeof(Data))) Data(0, 0);
+    Data* d = new (system->allocate(sizeof(Data))) Data(system, 0, 0);
 
     for (const char** p = path; *p; ++p) {
-      const char* file = append(system, *p, "/", className);
+      const char* file = append(system, *p, "/", className, ".class");
       int fd = open(file, O_RDONLY);
+      system->free(file);
+
       if (fd != -1) {
         struct stat s;
         int r = fstat(fd, &s);
@@ -133,7 +147,6 @@ class ClassFinder: public vm::ClassFinder {
           }
         }
       }
-      system->free(file);
     }
     
     system->free(d);
@@ -183,7 +196,7 @@ parsePath(vm::System* s, const char* path)
   unsigned i = 0;
   for (Tokenizer t(path, ':'); t.hasMore(); ++i) {
     Tokenizer::Token token(t.next());
-    char* p = static_cast<char*>(s->allocate(token.length));
+    char* p = static_cast<char*>(s->allocate(token.length + 1));
     memcpy(p, token.s, token.length);
     p[token.length] = 0;
     v[i] = p;
diff --git a/src/type-generator.cpp b/src/type-generator.cpp
index a030ad529a..4b7f6ec8d1 100644
--- a/src/type-generator.cpp
+++ b/src/type-generator.cpp
@@ -1492,19 +1492,14 @@ writeInitializations(Output* out, Object* declarations)
 
   out->write("t->vm->types = allocate(t, pad((");
   out->write(count);
-  out->write(" * ");
-  out->write(sizeof(void*));
-  out->write(") + 4 + ");
-  out->write(sizeof(void*));
-  out->write("));\n");
+  out->write(" * sizeof(void*)) + 4 + sizeof(void*)));\n");
   out->write("objectClass(t->vm->types) = 0;\n");
   out->write("arrayLength(t, t->vm->types) = ");
   out->write(count);
   out->write(";\n");
-
-  out->write("t->vm->types = makeArray(t, ");
-  out->write(typeCount(declarations));
-  out->write(");\n\n");
+  out->write("memset(&arrayBody(t, t->vm->types, 0), 0, ");
+  out->write(count);
+  out->write(" * sizeof(void*));\n\n");
 
   for (Object* p = declarations; p; p = cdr(p)) {
     Object* o = car(p);
diff --git a/src/vm.cpp b/src/vm.cpp
index 21f6695d4f..f3a37f024a 100644
--- a/src/vm.cpp
+++ b/src/vm.cpp
@@ -16,6 +16,8 @@ using namespace vm;
 
 namespace {
 
+static const bool Debug = true;
+
 class Thread;
 
 void assert(Thread*, bool);
@@ -291,6 +293,8 @@ collect(Machine* m, Heap::CollectionType type)
     Machine* m;
   } it(m);
 
+  fprintf(stderr, "collection time!\n");
+
   m->heap->collect(type, &it);
 }
 
@@ -759,18 +763,19 @@ find(Thread* t, object class_, object table, object reference,
   object n = referenceName(t, reference);
   object s = referenceSpec(t, reference);
   for (unsigned i = 0; i < arrayLength(t, table); ++i) {
-    object field = arrayBody(t, table, i);
-    if (strcmp(&byteArrayBody(t, name(t, field), 0),
+    object o = arrayBody(t, table, i);
+
+    if (strcmp(&byteArrayBody(t, name(t, o), 0),
                &byteArrayBody(t, n, 0)) == 0 and
-        strcmp(&byteArrayBody(t, spec(t, field), 0),
+        strcmp(&byteArrayBody(t, spec(t, o), 0),
                &byteArrayBody(t, s, 0)) == 0)
     {
-      return field;
+      return o;
     }               
   }
 
   object message = makeString
-    (t, "%s (%s) not found in %s",
+    (t, "%s:%s not found in %s",
      &byteArrayBody(t, n, 0),
      &byteArrayBody(t, s, 0),
      &byteArrayBody(t, className(t, class_), 0));
@@ -966,6 +971,126 @@ listAppend(Thread* t, object list, object value)
   set(t, listRear(t, list), p);
 }
 
+object
+parsePool(Thread* t, Stream& s)
+{
+  unsigned poolCount = s.read2() - 1;
+  object pool = makeArray(t, poolCount);
+  PROTECT(t, pool);
+
+  for (unsigned i = 0; i < poolCount; ++i) {
+    unsigned c = s.read1();
+
+    switch (c) {
+    case CONSTANT_Integer: {
+      object value = makeInt(t, s.read4());
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Float: {
+      object value = makeFloat(t, s.readFloat());
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Long: {
+      object value = makeLong(t, s.read8());
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Double: {
+      object value = makeLong(t, s.readDouble());
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Utf8: {
+      unsigned length = s.read2();
+      object value = makeByteArray(t, length + 1);
+      s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, value, 0)), length);
+      byteArrayBody(t, value, length) = 0;
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Class: {
+      object value = makeIntArray(t, 2);
+      intArrayBody(t, value, 0) = c;
+      intArrayBody(t, value, 1) = s.read2();
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_String: {
+      object value = makeIntArray(t, 2);
+      intArrayBody(t, value, 0) = c;
+      intArrayBody(t, value, 1) = s.read2();
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_NameAndType: {
+      object value = makeIntArray(t, 3);
+      intArrayBody(t, value, 0) = c;
+      intArrayBody(t, value, 1) = s.read2();
+      intArrayBody(t, value, 2) = s.read2();
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    case CONSTANT_Fieldref:
+    case CONSTANT_Methodref:
+    case CONSTANT_InterfaceMethodref: {
+      object value = makeIntArray(t, 3);
+      intArrayBody(t, value, 0) = c;
+      intArrayBody(t, value, 1) = s.read2();
+      intArrayBody(t, value, 2) = s.read2();
+      set(t, arrayBody(t, pool, i), value);
+    } break;
+
+    default: abort(t);
+    }
+  }
+
+  for (unsigned i = 0; i < poolCount; ++i) {
+    object o = arrayBody(t, pool, i);
+    if (objectClass(o) == arrayBody(t, t->vm->types, Machine::IntArrayType)) {
+      switch (intArrayBody(t, o, 0)) {
+      case CONSTANT_Class: {
+        set(t, arrayBody(t, pool, i),
+            arrayBody(t, pool, intArrayBody(t, o, 1) - 1));
+      } break;
+
+      case CONSTANT_String: {
+        object bytes = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
+        object value = makeString(t, bytes, 0, byteArrayLength(t, bytes), 0);
+        set(t, arrayBody(t, pool, i), value);
+      } break;
+
+      case CONSTANT_NameAndType: {
+        object name = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
+        object type = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
+        object value = makePair(t, name, type);
+        set(t, arrayBody(t, pool, i), value);
+      } break;
+      }
+    }
+  }
+
+  for (unsigned i = 0; i < poolCount; ++i) {
+    object o = arrayBody(t, pool, i);
+    if (objectClass(o) == arrayBody(t, t->vm->types, Machine::IntArrayType)) {
+      switch (intArrayBody(t, o, 0)) {
+      case CONSTANT_Fieldref:
+      case CONSTANT_Methodref:
+      case CONSTANT_InterfaceMethodref: {
+        object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
+        object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
+        object value = makeReference
+          (t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
+        set(t, arrayBody(t, pool, i), value);
+      } break;
+      }
+    }
+  }
+
+  return pool;
+}
+
 void
 parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
 {
@@ -975,17 +1100,21 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
   object map = makeHashMap(t, 0, 0);
   PROTECT(t, map);
 
-  object superInterfaces = classInterfaceTable(t, classSuper(t, class_));
-  PROTECT(t, superInterfaces);
+  if (classSuper(t, class_)) {
+    object superInterfaces = classInterfaceTable(t, classSuper(t, class_));
+    if (superInterfaces) {
+      PROTECT(t, superInterfaces);
 
-  for (unsigned i = 0; i < arrayLength(t, superInterfaces); i += 2) {
-    object name = interfaceName(t, arrayBody(t, superInterfaces, i));
-    hashMapInsert(t, map, name, name, byteArrayHash);
+      for (unsigned i = 0; i < arrayLength(t, superInterfaces); i += 2) {
+        object name = interfaceName(t, arrayBody(t, superInterfaces, i));
+        hashMapInsert(t, map, name, name, byteArrayHash);
+      }
+    }
   }
   
   unsigned count = s.read2();
   for (unsigned i = 0; i < count; ++i) {
-    object name = arrayBody(t, pool, s.read2());
+    object name = arrayBody(t, pool, s.read2() - 1);
     hashMapInsert(t, map, name, name, byteArrayHash);
   }
 
@@ -1060,8 +1189,13 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
 
   unsigned count = s.read2();
   if (count) {
-    unsigned memberOffset
-      = classFixedSize(t, classSuper(t, class_)) * BytesPerWord;
+    fprintf(stderr, "%d fields\n", count);
+
+    unsigned memberOffset = BytesPerWord;
+    if (classSuper(t, class_)) {
+      memberOffset= classFixedSize(t, classSuper(t, class_)) * BytesPerWord;
+    }
+
     unsigned staticOffset = 0;
   
     object fieldTable = makeArray(t, count);
@@ -1081,8 +1215,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
       object value = makeField(t,
                                flags,
                                0, // offset
-                               arrayBody(t, pool, name),
-                               arrayBody(t, pool, spec),
+                               arrayBody(t, pool, name - 1),
+                               arrayBody(t, pool, spec - 1),
                                class_);
 
       if (flags & ACC_STATIC) {
@@ -1185,14 +1319,18 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
 
   unsigned virtualCount = 0;
 
-  object superVirtualTable = classVirtualTable(t, classSuper(t, class_));
+  object superVirtualTable = 0;
   PROTECT(t, superVirtualTable);
 
+  if (classSuper(t, class_)) {
+    superVirtualTable = classVirtualTable(t, classSuper(t, class_));
+  }
+
   if (superVirtualTable) {
     virtualCount = arrayLength(t, superVirtualTable);
     for (unsigned i = 0; i < virtualCount; ++i) {
       object method = arrayBody(t, superVirtualTable, i);
-      hashMapInsert(t, map, method, method, byteArrayHash);
+      hashMapInsert(t, map, method, method, methodHash);
     }
   }
 
@@ -1212,7 +1350,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
       object code = 0;
       unsigned attributeCount = s.read2();
       for (unsigned j = 0; j < attributeCount; ++j) {
-        object name = arrayBody(t, pool, s.read2());
+        object name = arrayBody(t, pool, s.read2() - 1);
         unsigned length = s.read4();
 
         if (strcmp(reinterpret_cast<const int8_t*>("Code"),
@@ -1224,14 +1362,15 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
         }
       }
 
-      object value = makeMethod(t,
-                                flags,
-                                0, // offset
-                                parameterCount(t, arrayBody(t, pool, spec)),
-                                arrayBody(t, pool, name),
-                                arrayBody(t, pool, spec),
-                                class_,
-                                code);
+      object value = makeMethod
+        (t,
+         flags,
+         0, // offset
+         parameterCount(t, arrayBody(t, pool, spec - 1)),
+         arrayBody(t, pool, name - 1),
+         arrayBody(t, pool, spec - 1),
+         class_,
+         code);
       PROTECT(t, value);
 
       if (flags & ACC_STATIC) {
@@ -1265,18 +1404,18 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
 
     object vtable = makeArray(t, virtualCount);
 
+    unsigned i = 0;
     if (superVirtualTable) {
-      unsigned i = 0;
       for (; i < arrayLength(t, superVirtualTable); ++i) {
         object method = arrayBody(t, superVirtualTable, i);
         method = hashMapFind(t, map, method, methodHash, methodEqual);
 
         set(t, arrayBody(t, vtable, i), method);
       }
+    }
 
-      for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
-        set(t, arrayBody(t, vtable, i++), pairFirst(t, p));        
-      }
+    for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
+      set(t, arrayBody(t, vtable, i++), pairFirst(t, p));        
     }
 
     set(t, classVirtualTable(t, class_), vtable);
@@ -1284,17 +1423,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
     // generate interface vtables
     
     object itable = classInterfaceTable(t, class_);
-    PROTECT(t, itable);
+    if (itable) {
+      PROTECT(t, itable);
 
-    for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
-      object methodTable = interfaceMethodTable(t, arrayBody(t, itable, i));
-      object vtable = arrayBody(t, itable, i + 1);
-
-      for (unsigned j = 0; j < arrayLength(t, methodTable); ++j) {
-        object method = arrayBody(t, methodTable, j);
-        method = hashMapFind(t, map, method, methodHash, methodEqual);
-
-        set(t, arrayBody(t, vtable, j), method);        
+      for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
+        object methodTable = interfaceMethodTable(t, arrayBody(t, itable, i));
+        object vtable = arrayBody(t, itable, i + 1);
+        
+        for (unsigned j = 0; j < arrayLength(t, methodTable); ++j) {
+          object method = arrayBody(t, methodTable, j);
+          method = hashMapFind(t, map, method, methodHash, methodEqual);
+          
+          set(t, arrayBody(t, vtable, j), method);        
+        }
       }
     }
   }
@@ -1322,70 +1463,7 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
   s.read2(); // minor version
   s.read2(); // major version
 
-  unsigned poolCount = s.read2();
-  object pool = makeArray(t, poolCount);
-  PROTECT(t, pool);
-
-  for (unsigned i = 0; i < poolCount; ++i) {
-    switch (s.read1()) {
-    case CONSTANT_Class: {
-      set(t, arrayBody(t, pool, i), arrayBody(t, pool, s.read2()));
-    } break;
-
-    case CONSTANT_Fieldref:
-    case CONSTANT_Methodref:
-    case CONSTANT_InterfaceMethodref: {
-      object c = arrayBody(t, pool, s.read2());
-      object nameAndType = arrayBody(t, pool, s.read2());
-      object value = makeReference
-        (t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_String: {
-      object bytes = arrayBody(t, pool, s.read2());
-      object value = makeString(t, bytes, 0, byteArrayLength(t, bytes), 0);
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_Integer: {
-      object value = makeInt(t, s.read4());
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_Float: {
-      object value = makeFloat(t, s.readFloat());
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_Long: {
-      object value = makeLong(t, s.read8());
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_Double: {
-      object value = makeLong(t, s.readDouble());
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_NameAndType: {
-      object name = arrayBody(t, pool, s.read2());
-      object type = arrayBody(t, pool, s.read2());
-      object value = makePair(t, name, type);
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    case CONSTANT_Utf8: {
-      unsigned length = s.read2();
-      object value = makeByteArray(t, length + 1);
-      s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, value, 0)), length);
-      byteArrayBody(t, value, length) = 0;
-      set(t, arrayBody(t, pool, i), value);
-    } break;
-
-    default: abort(t);
-    }
-  }
+  object pool = parsePool(t, s);
 
   unsigned flags = s.read2();
   unsigned name = s.read2();
@@ -1395,7 +1473,7 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
                             0, // fixed size
                             0, // array size
                             0, // object mask
-                            arrayBody(t, pool, name),
+                            arrayBody(t, pool, name - 1),
                             0, // super
                             0, // interfaces
                             0, // vtable
@@ -1405,10 +1483,13 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
                             0); // initializer
   PROTECT(t, class_);
   
-  object super = resolveClass(t, arrayBody(t, pool, s.read2()));
-  if (UNLIKELY(t->exception)) return 0;
+  unsigned super = s.read2();
+  if (super) {
+    object sc = resolveClass(t, arrayBody(t, pool, super - 1));
+    if (UNLIKELY(t->exception)) return 0;
 
-  set(t, classSuper(t, class_), super);
+    set(t, classSuper(t, class_), sc);
+  }
   
   parseInterfaceTable(t, s, class_, pool);
   if (UNLIKELY(t->exception)) return 0;
@@ -1435,10 +1516,16 @@ resolveClass(Thread* t, object spec)
       (reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
 
     if (data) {
+      fprintf(stderr, "parsing %s\n", &byteArrayBody
+              (t, spec, 0));
+
       // parse class file
       class_ = parseClass(t, data->start(), data->length());
       data->dispose();
 
+      fprintf(stderr, "done parsing %s\n", &byteArrayBody
+              (t, className(t, class_), 0));
+
       PROTECT(t, class_);
 
       hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash);
@@ -1614,7 +1701,7 @@ run(Thread* t)
       uint8_t index2 = codeBody(t, code, ip++);
       uint16_t index = (index1 << 8) | index2;
       
-      object class_ = resolveClass(t, codePool(t, code), index);
+      object class_ = resolveClass(t, codePool(t, code), index - 1);
       if (UNLIKELY(exception)) goto throw_;
       
       object array = makeObjectArray(t, class_, c);
@@ -1804,7 +1891,7 @@ run(Thread* t)
     if (stack[sp - 1]) {
       uint16_t index = (index1 << 8) | index2;
       
-      object class_ = resolveClass(t, codePool(t, code), index);
+      object class_ = resolveClass(t, codePool(t, code), index - 1);
       if (UNLIKELY(exception)) goto throw_;
 
       if (not instanceOf(t, class_, stack[sp - 1])) {
@@ -1915,7 +2002,7 @@ run(Thread* t)
       uint8_t index2 = codeBody(t, code, ip++);
       uint16_t index = (index1 << 8) | index2;
     
-      object field = resolveField(t, codePool(t, code), index);
+      object field = resolveField(t, codePool(t, code), index - 1);
       if (UNLIKELY(exception)) goto throw_;
       
       push(t, getField(t, instance, field));
@@ -1930,7 +2017,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
 
-    object field = resolveField(t, codePool(t, code), index);
+    object field = resolveField(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
 
     object clinit = classInitializer(t, fieldClass(t, field));
@@ -2288,7 +2375,7 @@ run(Thread* t)
     if (stack[sp - 1]) {
       uint16_t index = (index1 << 8) | index2;
       
-      object class_ = resolveClass(t, codePool(t, code), index);
+      object class_ = resolveClass(t, codePool(t, code), index - 1);
       if (UNLIKELY(exception)) goto throw_;
 
       if (instanceOf(t, class_, stack[sp - 1])) {
@@ -2308,7 +2395,7 @@ run(Thread* t)
       
     ip += 2;
 
-    object method = resolveMethod(t, codePool(t, code), index);
+    object method = resolveMethod(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
     
     parameterCount = methodParameterCount(t, method);
@@ -2328,7 +2415,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
 
-    object method = resolveMethod(t, codePool(t, code), index);
+    object method = resolveMethod(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
     
     parameterCount = methodParameterCount(t, method);
@@ -2353,7 +2440,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
 
-    object method = resolveMethod(t, codePool(t, code), index);
+    object method = resolveMethod(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
     
     object clinit = classInitializer(t, methodClass(t, method));
@@ -2374,7 +2461,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
 
-    object method = resolveMethod(t, codePool(t, code), index);
+    object method = resolveMethod(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
     
     parameterCount = methodParameterCount(t, method);
@@ -2539,7 +2626,7 @@ run(Thread* t)
   } goto loop;
 
   case ldc: {
-    push(t, arrayBody(t, codePool(t, code), codeBody(t, code, ip++)));
+    push(t, arrayBody(t, codePool(t, code), codeBody(t, code, ip++) - 1));
   } goto loop;
 
   case ldc_w:
@@ -2547,7 +2634,7 @@ run(Thread* t)
     uint8_t index1 = codeBody(t, code, ip++);
     uint8_t index2 = codeBody(t, code, ip++);
 
-    push(t, arrayBody(t, codePool(t, code), (index1 << 8) | index2));
+    push(t, arrayBody(t, codePool(t, code), ((index1 << 8) | index2) - 1));
   } goto loop;
 
   case vm::ldiv: {
@@ -2625,7 +2712,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
     
-    object class_ = resolveClass(t, codePool(t, code), index);
+    object class_ = resolveClass(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
 
     object clinit = classInitializer(t, class_);
@@ -2727,7 +2814,7 @@ run(Thread* t)
       uint8_t index2 = codeBody(t, code, ip++);
       uint16_t index = (index1 << 8) | index2;
     
-      object field = resolveField(t, codePool(t, code), index);
+      object field = resolveField(t, codePool(t, code), index - 1);
       if (UNLIKELY(exception)) goto throw_;
       
       object value = pop(t);
@@ -2743,7 +2830,7 @@ run(Thread* t)
     uint8_t index2 = codeBody(t, code, ip++);
     uint16_t index = (index1 << 8) | index2;
 
-    object field = resolveField(t, codePool(t, code), index);
+    object field = resolveField(t, codePool(t, code), index - 1);
     if (UNLIKELY(exception)) goto throw_;
 
     object clinit = classInitializer(t, fieldClass(t, field));
@@ -2906,11 +2993,13 @@ run(Thread* t)
     if (eht) {
       for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
         ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
-        uint16_t catchType = exceptionHandlerCatchType(eh);
+        object catchType =
+          arrayBody(t, codePool(t, code), exceptionHandlerCatchType(eh) - 1);
+
         if (catchType == 0 or
-            instanceOf(t,
-                       arrayBody(t, codePool(t, code), catchType),
-                       exception))
+            (objectClass(catchType)
+             == arrayBody(t, t->vm->types, Machine::ClassType) and
+             instanceOf(t, catchType, exception)))
         {
           sp = frameStackBase(t, frame);
           ip = exceptionHandlerIp(eh);
@@ -2922,14 +3011,34 @@ run(Thread* t)
     }
   }
 
-  object method = threadExceptionHandler(t, t->thread);
-  code = methodCode(t, method);
-  frame = makeFrame(t, method, 0, 0, 0, codeMaxLocals(t, code));
-  sp = 0;
-  ip = 0;
-  push(t, exception);
-  exception = 0;
-  goto loop;
+  if (t->thread) {
+    object method = threadExceptionHandler(t, t->thread);
+    code = methodCode(t, method);
+    frame = makeFrame(t, method, 0, 0, 0, codeMaxLocals(t, code));
+    sp = 0;
+    ip = 0;
+    push(t, exception);
+    exception = 0;
+    goto loop;
+  } else if (Debug) {
+    object p = 0;
+    object n = 0;
+    for (object trace = throwableTrace(t, exception); trace; trace = n) {
+      n = traceNext(t, trace);
+      set(t, traceNext(t, trace), p);
+      p = trace;
+    }
+
+    fprintf(stderr, "uncaught exception: %s\n", &byteArrayBody
+            (t, stringBytes(t, throwableMessage(t, exception)), 0));
+
+    for (; p; p = traceNext(t, p)) {
+      fprintf(stderr, "  at %s\n", &byteArrayBody
+              (t, methodName(t, traceMethod(t, p)), 0));
+    }
+  }
+
+  abort(t);
 }
 
 void