Merged branch subtype-trunk into default.
authorStefan Ring <stefan@complang.tuwien.ac.at>
Sat, 20 Dec 2008 15:06:26 +0000 (16:06 +0100)
committerStefan Ring <stefan@complang.tuwien.ac.at>
Sat, 20 Dec 2008 15:06:26 +0000 (16:06 +0100)
1  2 
src/vm/class.cpp
src/vm/jit/alpha/codegen.c
src/vm/jit/builtin.cpp
src/vm/jit/builtin.hpp
src/vm/jit/i386/codegen.c
src/vm/jit/i386/emit.c
src/vm/jit/i386/patcher.c
src/vm/jit/x86_64/codegen.c
src/vm/jit/x86_64/emit.c
src/vm/linker.cpp

diff --combined src/vm/class.cpp
index 9ab89073c74ad911438843ba633582f881431cf4,0aa5f21233972cf757f8f2f0f4b8c7285d38a7a7..698356d11566973010920c69af5720f75694445d
  
  #include "arch.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/llni.h"
  
  #include "threads/lock.hpp"
  #include "threads/mutex.hpp"
  
 -#include "toolbox/logging.h"
 +#include "toolbox/logging.hpp"
  
  #include "vm/array.hpp"
  #include "vm/jit/builtin.hpp"
@@@ -1471,12 -1471,16 +1471,16 @@@ bool class_isanysubclass(classinfo *sub
                if (sub->flags & ACC_INTERFACE)
                        return (super == class_java_lang_Object);
  
-               linker_classrenumber_mutex->lock();
+ #if USES_NEW_SUBTYPE
+               result = fast_subtype_check(sub->vftbl, super->vftbl);
+ #else
+               LOCK_CLASSRENUMBER_LOCK;
  
                diffval = sub->vftbl->baseval - super->vftbl->baseval;
                result  = diffval <= (uint32_t) super->vftbl->diffval;
  
-               linker_classrenumber_mutex->unlock();
+               UNLOCK_CLASSRENUMBER_LOCK;
+ #endif
        }
  
        return result;
@@@ -2113,13 -2117,6 +2117,13 @@@ int32_t class_get_modifiers(classinfo *
        classref_or_classinfo  outer;
        utf                   *innername;
        int                    i;
 +      int32_t                flags;
 +
 +      /* default to flags of passed class */
 +
 +      flags = c->flags;
 +
 +      /* if requested we check if passed class is inner class */
  
        if (!ignoreInnerClassesAttrib && (c->innerclasscount != 0)) {
                /* search for passed class as inner class */
  
                                if (outer.any)
                                        /* return flags got from the outer class file */
 -                                      return c->innerclass[i].flags & ACC_CLASS_REFLECT_MASK;
 -                              else
 -                                      return c->flags & ACC_CLASS_REFLECT_MASK;
 +                                      flags = c->innerclass[i].flags;
 +
 +                              break;
                        }
                }
        }
  
 -      /* passed class is no inner class or it was not requested */
 +      /* remove ACC_SUPER bit from flags */
  
 -      return c->flags & ACC_CLASS_REFLECT_MASK;
 +      return flags & ~ACC_SUPER & ACC_CLASS_REFLECT_MASK;
  }
  
  
index 2c14d21fea8c37cc2b8509360a1048d68afa948d,b136fd4dcaaefac36a11c63d4a751ac2f4c60b23..a49b1a0af59426899539c7e7a9ec37272353f68e
@@@ -36,7 -36,7 +36,7 @@@
  #include "vm/jit/alpha/arch.h"
  #include "vm/jit/alpha/codegen.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/localref.hpp"
  #include "native/native.hpp"
@@@ -2722,24 -2722,49 +2722,49 @@@ gen_method
                                        M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                        M_ALD(REG_ITMP3, REG_PV, disp);
  
-                                       M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
-                                       /*                              if (s1 != REG_ITMP1) { */
-                                       /*                                      M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, baseval)); */
-                                       /*                                      M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); */
-                                       /*  #if defined(ENABLE_THREADS) */
-                                       /*                                      codegen_threadcritstop(cd, (u1 *) mcodeptr - cd->mcodebase); */
-                                       /*  #endif */
-                                       /*                                      M_ISUB(REG_ITMP2, REG_ITMP1, REG_ITMP2); */
-                                       /*                              } else { */
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
-                                       M_ISUB(REG_ITMP2, REG_ITMP3, REG_ITMP2);
-                                       M_ALD(REG_ITMP3, REG_PV, disp);
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-                                       /*                              } */
-                                       M_CMPULE(REG_ITMP2, REG_ITMP3, REG_ITMP3);
-                                       emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ITMP3, s1);
+                                       if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                               M_LADD(REG_ITMP1, REG_ITMP2, REG_ITMP1);
+                                               M_ALD(REG_ITMP1, REG_ITMP1, 0);
+                                               M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+                                               emit_label_bnez(cd, BRANCH_LABEL_6, REG_ITMP1);  /* good */
+                                               if (super == NULL) {
+                                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                                       M_CMPEQ_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                                       emit_label_beqz(cd, BRANCH_LABEL_10, REG_ITMP1);  /* throw */
+                                               }
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                               M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_depth));
+                                               M_CMPLE(REG_ITMP1, REG_ITMP3, REG_ITMP3);
+                                               emit_label_beqz(cd, BRANCH_LABEL_9, REG_ITMP3);  /* throw */
+                                               /* reload */
+                                               M_ALD(REG_ITMP3, REG_PV, disp);
+                                               M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                               M_S8ADDQ(REG_ITMP1, REG_ITMP2, REG_ITMP2);
+                                               M_ALD(REG_ITMP1, REG_ITMP2, -DISPLAY_SIZE*8);
+                                               M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+                                               emit_label_bnez(cd, BRANCH_LABEL_7, REG_ITMP1);  /* good */
+                                               emit_label(cd, BRANCH_LABEL_9);
+                                               if (super == NULL)
+                                                       emit_label(cd, BRANCH_LABEL_10);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                               M_ALD_INTERN(s1, REG_ZERO, TRAP_ClassCastException);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                               emit_label(cd, BRANCH_LABEL_6);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                       }
+                                       else {
+                                               M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset);
+                                               M_CMPEQ(REG_ITMP2, REG_ITMP3, REG_ITMP2);
+                                               emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ITMP2, s1);
+                                       }
  
                                        if (super != NULL)
                                                emit_label(cd, BRANCH_LABEL_5);
                                        emit_label_beqz(cd, BRANCH_LABEL_5, s1);
                                }
  
-                               M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-                               M_ALD(REG_ITMP2, REG_PV, disp);
+                               M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+                               M_ALD(REG_ITMP3, REG_PV, disp);
+                               if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                       M_LADD(REG_ITMP1, REG_ITMP2, REG_ITMP1);
+                                       M_ALD(REG_ITMP1, REG_ITMP1, 0);
+                                       M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+                                       emit_label_beqz(cd, BRANCH_LABEL_8, REG_ITMP1);
+                                       ICONST(d, 1);
+                                       emit_label_br(cd, BRANCH_LABEL_6);  /* true */
+                                       emit_label(cd, BRANCH_LABEL_8);
+                                       if (super == NULL) {
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                               M_CMPEQ_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                               emit_label_beqz(cd, BRANCH_LABEL_10, REG_ITMP1);  /* false */
+                                       }
  
-                               M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
-                               M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval));
-                               M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval));
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
  
-                               M_ISUB(REG_ITMP1, REG_ITMP3, REG_ITMP1);
-                               M_CMPULE(REG_ITMP1, REG_ITMP2, d);
+                                       M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_depth));
+                                       M_CMPLE(REG_ITMP1, REG_ITMP3, REG_ITMP3);
+                                       emit_label_beqz(cd, BRANCH_LABEL_9, REG_ITMP3);  /* false */
+                                       /* reload */
+                                       M_ALD(REG_ITMP3, REG_PV, disp);
+                                       M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                       M_S8ADDQ(REG_ITMP1, REG_ITMP2, REG_ITMP2);
+                                       M_ALD(REG_ITMP1, REG_ITMP2, -DISPLAY_SIZE*8);
+                                       M_CMPEQ(REG_ITMP1, REG_ITMP3, d);
+                                       if (d == REG_ITMP2)
+                                               emit_label_br(cd, BRANCH_LABEL_7);
+                                       emit_label(cd, BRANCH_LABEL_9);
+                                       if (super == NULL)
+                                               emit_label(cd, BRANCH_LABEL_10);
+                                       if (d == REG_ITMP2) {
+                                               M_CLR(d);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_6);
+                               }
+                               else {
+                                       M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset);
+                                       M_CMPEQ(REG_ITMP2, REG_ITMP3, d);
+                               }
  
                                if (super != NULL)
                                        emit_label(cd, BRANCH_LABEL_5);
diff --combined src/vm/jit/builtin.cpp
index 9e927c39bc2e4ed299dcea29c3a4fa02d9211c42,f2c1a5f6b4d7523b023732cfbb94d96cd5069f44..491d48ce6c056cac6b6c212424807374485f3d46
@@@ -48,7 -48,7 +48,7 @@@
  #endif
  
  #include "mm/gc.hpp"
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/llni.h"
  
@@@ -56,7 -56,7 +56,7 @@@
  #include "threads/mutex.hpp"
  #include "threads/thread.hpp"
  
 -#include "toolbox/logging.h"
 +#include "toolbox/logging.hpp"
  #include "toolbox/util.h"
  
  #include "vm/array.hpp"
@@@ -640,6 -640,28 +640,28 @@@ bool builtin_canstore(java_handle_objec
        return result;
  }
  
+ #if USES_NEW_SUBTYPE
+ /* fast_subtype_check **********************************************************
+    Checks if s is a subtype of t, using both the restricted subtype relation
+    and the overflow array (see Cliff Click and John Rose: Fast subtype checking
+    in the Hotspot JVM.)
+    RETURN VALUE:
+       1......s is a subtype of t.
+       0......otherwise
+ *******************************************************************************/
+ bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
+ {
+    if (s->subtype_display[t->subtype_depth] == t)
+        return true;
+    if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
+        return false;
+    return s->subtype_depth >= t->subtype_depth && s->subtype_overflow[t->subtype_depth - DISPLAY_SIZE] == t;
+ }
+ #endif
  
  /* builtin_fast_canstore *******************************************************
  
@@@ -685,7 -707,7 +707,7 @@@ bool builtin_fast_canstore(java_objecta
                if (valuevftbl == componentvftbl)
                        return 1;
  
-               linker_classrenumber_mutex->lock();
+               LOCK_CLASSRENUMBER_LOCK;
  
                baseval = componentvftbl->baseval;
  
                                          (valuevftbl->interfacetable[baseval] != NULL));
                }
                else {
+ #if USES_NEW_SUBTYPE
+                       result = fast_subtype_check(valuevftbl, componentvftbl);
+ #else
                        diffval = valuevftbl->baseval - componentvftbl->baseval;
                        result  = diffval <= (uint32_t) componentvftbl->diffval;
+ #endif
                }
  
-               linker_classrenumber_mutex->unlock();
+               UNLOCK_CLASSRENUMBER_LOCK;
        }
        else if (valuedesc == NULL) {
                /* {oa has dimension > 1} */
@@@ -752,7 -778,7 +778,7 @@@ bool builtin_fast_canstore_onedim(java_
        if (valuevftbl == elementvftbl)
                return 1;
  
-       linker_classrenumber_mutex->lock();
+       LOCK_CLASSRENUMBER_LOCK;
  
        baseval = elementvftbl->baseval;
  
                                  (valuevftbl->interfacetable[baseval] != NULL));
        }
        else {
+ #if USES_NEW_SUBTYPE
+               result = fast_subtype_check(valuevftbl, elementvftbl);
+ #else
                diffval = valuevftbl->baseval - elementvftbl->baseval;
                result  = diffval <= (uint32_t) elementvftbl->diffval;
+ #endif
        }
  
-       linker_classrenumber_mutex->unlock();
+       UNLOCK_CLASSRENUMBER_LOCK;
  
        return result;
  }
@@@ -801,12 -831,16 +831,16 @@@ bool builtin_fast_canstore_onedim_class
        if (valuevftbl == elementvftbl)
                return 1;
  
-       linker_classrenumber_mutex->lock();
+       LOCK_CLASSRENUMBER_LOCK;
  
+ #if USES_NEW_SUBTYPE
+       result = fast_subtype_check(valuevftbl, elementvftbl);
+ #else
        diffval = valuevftbl->baseval - elementvftbl->baseval;
        result  = diffval <= (uint32_t) elementvftbl->diffval;
+ #endif
  
-       linker_classrenumber_mutex->unlock();
+       UNLOCK_CLASSRENUMBER_LOCK;
  
        return result;
  }
diff --combined src/vm/jit/builtin.hpp
index fdb958d7d6977bed27a500e6417cc44239a9c355,eb2d80e1c79138804eb221c8b89451024646a638..60b58e25c672497252ad3d94c99c1377b1a950c6
@@@ -36,9 -36,9 +36,9 @@@ typedef struct builtintable_entry built
  #include "arch.h"
  #include "md-abi.h"
  
 -#include "toolbox/logging.h"
 +#include "toolbox/logging.hpp"
  
 -#include "vm/descriptor.h"
 +#include "vm/descriptor.hpp"
  #include "vm/utf8.h"
  
  
@@@ -125,6 -125,10 +125,10 @@@ bool builtintable_replace_function(voi
   * ICMD_BUILTIN3.)
   */
  
+ #if USES_NEW_SUBTYPE
+ bool fast_subtype_check(struct _vftbl *, struct _vftbl *);
+ #endif
  bool builtin_instanceof(java_handle_t *obj, classinfo *c);
  /* NOT AN OP */
  bool builtin_checkcast(java_handle_t *obj, classinfo *c);
index 7ac8e26e90e53a4fe4eb1a44f439d722daed0732,a367f37aa4a05b5cd11801c2ca5a16bacd01d923..8eab0fbf0511a4cce0d56cac92d930db7c06b8ed
@@@ -36,7 -36,7 +36,7 @@@
  #include "vm/jit/i386/codegen.h"
  #include "vm/jit/i386/emit.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/localref.hpp"
  #include "native/native.hpp"
@@@ -3178,35 -3178,49 +3178,49 @@@ gen_method
                                        }
  
                                        M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                        if (super == NULL) {
                                                patcher_add_patch_ref(jd, PATCHER_checkcast_class,
                                                                                        iptr->sx.s23.s3.c.ref,
                                                                                        0);
                                        }
                                        M_MOV_IMM(supervftbl, REG_ITMP3);
  
-                                       M_ILD32(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                                       if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                               M_CMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_6);  /* good */
  
-                                       /*                              if (s1 != REG_ITMP1) { */
-                                       /*                                      emit_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, baseval), REG_ITMP1); */
-                                       /*                                      emit_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, diffval), REG_ITMP3); */
-                                       /* #if defined(ENABLE_THREADS) */
-                                       /*                                      codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
-                                       /* #endif */
-                                       /*                                      emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
+                                               if (super == NULL) {
+                                                       M_ICMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                                       emit_label_bne(cd, BRANCH_LABEL_10);  /* throw */
+                                               }
  
-                                       /*                              } else { */
-                                       M_ILD32(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
-                                       M_ISUB(REG_ITMP3, REG_ITMP2);
-                                       M_MOV_IMM(supervftbl, REG_ITMP3);
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                               M_CMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                               emit_label_bgt(cd, BRANCH_LABEL_9);  /* throw */
  
-                                       /*                              } */
+                                               M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                               M_CMP_MEMINDEX(REG_ITMP2, -4*DISPLAY_SIZE, REG_ITMP1, 2, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_7);  /* good */
+                                               emit_label(cd, BRANCH_LABEL_9);
+                                               if (super == NULL)
+                                                       emit_label(cd, BRANCH_LABEL_10);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                               M_ALD_MEM(s1, TRAP_ClassCastException);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                               emit_label(cd, BRANCH_LABEL_6);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                       }
+                                       else {
+                                               M_CMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
  
-                                       M_CMP(REG_ITMP3, REG_ITMP2);
-                                       emit_classcast_check(cd, iptr, BRANCH_ULE, REG_ITMP3, s1);
+                                               emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+                                       }
  
                                        if (super != NULL)
                                                emit_label(cd, BRANCH_LABEL_5);
                                        emit_label_beq(cd, BRANCH_LABEL_5);
                                }
  
-                               M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
+                               M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                if (super == NULL) {
                                        patcher_add_patch_ref(jd, PATCHER_instanceof_class,
                                                                                iptr->sx.s23.s3.c.ref, 0);
                                }
+                               M_MOV_IMM(supervftbl, REG_ITMP3);
+                               if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                       M_CMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                       emit_label_bne(cd, BRANCH_LABEL_8); /* jump over INC/SETE */
+                                       if (d == REG_ITMP2) {
+                                               M_SETE(d);
+                                               M_BSEXT(d, d);
+                                       } else
+                                               M_IINC(d);
+                                       emit_label_br(cd, BRANCH_LABEL_6);  /* true */
+                                       emit_label(cd, BRANCH_LABEL_8);
  
-                               M_MOV_IMM(supervftbl, REG_ITMP2);
+                                       if (super == NULL) {
+                                               M_ICMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                               emit_label_bne(cd, BRANCH_LABEL_10);  /* false */
+                                       }
  
-                               M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
-                               M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, diffval));
-                               M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                       M_CMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                       emit_label_bgt(cd, BRANCH_LABEL_9);  /* false */
  
-                               M_ISUB(REG_ITMP2, REG_ITMP1);
-                               M_CLR(d);                                 /* may be REG_ITMP2 */
-                               M_CMP(REG_ITMP3, REG_ITMP1);
-                               M_BA(5);
-                               M_MOV_IMM(1, d);
+                                       M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                       M_CMP_MEMINDEX(REG_ITMP2, -4*DISPLAY_SIZE, REG_ITMP1, 2, REG_ITMP3);
+                                       if (d >= 4) {
+                                               M_SETE(REG_ITMP1);
+                                               M_BSEXT(REG_ITMP1, d);
+                                       }
+                                       else {
+                                               M_SETE(d);
+                                               if (d == REG_ITMP2) {
+                                                       M_BSEXT(d, d);
+                                                       emit_label_br(cd, BRANCH_LABEL_7); /* jump over M_CLR */
+                                               }
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_9);
+                                       if (super == NULL)
+                                               emit_label(cd, BRANCH_LABEL_10);
+                                       if (d == REG_ITMP2) {
+                                               M_CLR(d);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_6);
+                               }
+                               else {
+                                       M_CMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+                                       if (d >= 4) {
+                                               M_SETE(REG_ITMP1);
+                                               M_BSEXT(REG_ITMP1, d);
+                                       }
+                                       else {
+                                               M_SETE(d);
+                                               if (d == REG_ITMP2)
+                                                       M_BSEXT(d, d);
+                                       }
+                               }
  
                                if (super != NULL)
                                        emit_label(cd, BRANCH_LABEL_5);
diff --combined src/vm/jit/i386/emit.c
index 784942aa7ffcbafa5c2788821a49e693fff9d6d5,d7140291a69a36eb02f0ad3c28563c7d14053561..3a264f162542561af62ca4197e098192313699a4
@@@ -33,7 -33,7 +33,7 @@@
  #include "vm/jit/i386/emit.h"
  #include "vm/jit/i386/md-abi.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "threads/lock.hpp"
  
@@@ -458,9 -458,15 +458,15 @@@ void emit_classcast_check(codegendata *
                case BRANCH_LE:
                        M_BGT(6);
                        break;
+               case BRANCH_GE:
+                       M_BLT(6);
+                       break;
                case BRANCH_EQ:
                        M_BNE(6);
                        break;
+               case BRANCH_NE:
+                       M_BEQ(6);
+                       break;
                case BRANCH_ULE:
                        M_BBE(6);
                        break;
@@@ -1084,6 -1090,11 +1090,11 @@@ void emit_alu_imm_memabs(codegendata *c
        }
  }
  
+ void emit_alu_memindex_reg(codegendata *cd, s4 opc, s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg)
+ {
+       *(cd->mcodeptr++) = (((u1) (opc)) << 3) + 3;
+       emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+ }
  
  void emit_test_reg_reg(codegendata *cd, s4 reg, s4 dreg)
  {
@@@ -1104,6 -1115,12 +1115,12 @@@ void emit_test_imm_reg(codegendata *cd
  /*
   * inc, dec operations
   */
+ void emit_inc_reg(codegendata *cd, s4 reg)
+ {
+       *(cd->mcodeptr++) = 0xff;
+       emit_reg(0,(reg));
+ }
  void emit_dec_mem(codegendata *cd, s4 mem)
  {
        *(cd->mcodeptr++) = 0xff;
@@@ -1296,6 -1313,7 +1313,7 @@@ void emit_jcc(codegendata *cd, s4 opc, 
   */
  void emit_setcc_reg(codegendata *cd, s4 opc, s4 reg)
  {
+       assert(reg < 4);                     /* Can only operate on al, bl, cl, dl. */
        *(cd->mcodeptr++) = 0x0f;
        *(cd->mcodeptr++) = 0x90 + (u1) (opc);
        emit_reg(0,(reg));
index ff67f972a743a33977ee042a20b19a6bcf58cfb2,3eecac97ed221fe0b0a2956aef2876cd1ab686b1..fb04b86c4e1e2ac8a88bad0f5f35d963862e2383
@@@ -32,7 -32,7 +32,7 @@@
  #include "vm/jit/i386/codegen.h"
  #include "vm/jit/i386/md.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/native.hpp"
  
@@@ -633,7 -633,6 +633,6 @@@ bool patcher_checkcast_class(patchref_
        /* patch super class' vftbl */
  
        *((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
-       *((ptrint *) (ra + 5 + 6 + 6 + 2 + 1)) = (ptrint) c->vftbl;
  
        return true;
  }
index ef10ece73831c46db9e6909b6598a9d99a771a3a,96f4967bc9f052f7a74ea741adf8dee33a2389bd..80c81af88b5c59ba9345d556d9b92f0adf58839d
@@@ -37,7 -37,7 +37,7 @@@
  #include "vm/jit/x86_64/codegen.h"
  #include "vm/jit/x86_64/emit.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/localref.hpp"
  #include "native/native.hpp"
@@@ -2567,30 -2567,41 +2567,41 @@@ gen_method
                                        M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                        M_ALD(REG_ITMP3, RIP, disp);
  
-                                       M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
-                                       /*                                      if (s1 != REG_ITMP1) { */
-                                       /*                                              emit_movl_membase_reg(cd, REG_ITMP3, */
-                                       /*                                                                                              OFFSET(vftbl_t, baseval), */
-                                       /*                                                                                              REG_ITMP1); */
-                                       /*                                              emit_movl_membase_reg(cd, REG_ITMP3, */
-                                       /*                                                                                              OFFSET(vftbl_t, diffval), */
-                                       /*                                                                                              REG_ITMP3); */
-                                       /*  #if defined(ENABLE_THREADS) */
-                                       /*                                              codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
-                                       /*  #endif */
-                                       /*                                              emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
-                                       /*                                      } else { */
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
-                                       M_ISUB(REG_ITMP3, REG_ITMP2);
-                                       M_ALD(REG_ITMP3, RIP, disp);
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-                                       /*                                      } */
-                                       M_ICMP(REG_ITMP3, REG_ITMP2);
-                                       emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1);
+                                       if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                               M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_6);  /* good */
+                                               if (super == NULL) {
+                                                       M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                                       emit_label_bne(cd, BRANCH_LABEL_10);  /* throw */
+                                               }
+                                               M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                               M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                               emit_label_bgt(cd, BRANCH_LABEL_9);  /* throw */
+                                               M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                               M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+                                               emit_label_beq(cd, BRANCH_LABEL_7);  /* good */
+                                               emit_label(cd, BRANCH_LABEL_9);
+                                               if (super == NULL)
+                                                       emit_label(cd, BRANCH_LABEL_10);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                               M_ALD_MEM(s1, TRAP_ClassCastException);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                               emit_label(cd, BRANCH_LABEL_6);
+                                               /* reload s1, might have been destroyed */
+                                               emit_load_s1(jd, iptr, REG_ITMP1);
+                                       }
+                                       else {
+                                               M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+                                               emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+                                       }
  
                                        if (super != NULL)
                                                emit_label(cd, BRANCH_LABEL_5);
                                        disp = dseg_add_address(cd, super->vftbl);
                                }
  
-                               M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-                               M_ALD(REG_ITMP2, RIP, disp);
+                               M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+                               M_ALD(REG_ITMP3, RIP, disp);
+                               if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+                                       M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+                                       emit_label_bne(cd, BRANCH_LABEL_8); /* jump over INC/SETE */
+                                       if (d == REG_ITMP2) {
+                                               M_SETE(d);
+                                               M_BSEXT(d, d);
+                                       } else
+                                               M_LINC(d);
+                                       emit_label_br(cd, BRANCH_LABEL_6);  /* true */
+                                       emit_label(cd, BRANCH_LABEL_8);
+                                       if (super == NULL) {
+                                               M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                               emit_label_bne(cd, BRANCH_LABEL_10);  /* false */
+                                       }
  
-                               M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
-                               M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, diffval));
-                               M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                                       M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+                                       M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+                                       emit_label_bgt(cd, BRANCH_LABEL_9);  /* false */
  
-                               M_ISUB(REG_ITMP2, REG_ITMP1);
-                               M_CLR(d); /* may be REG_ITMP2 */
-                               M_ICMP(REG_ITMP3, REG_ITMP1);
-                               M_SETULE(d);
+                                       M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                       M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+                                       M_SETE(d);
+                                       if (d == REG_ITMP2) {
+                                               M_BSEXT(d, d);
+                                               emit_label_br(cd, BRANCH_LABEL_7); /* jump over M_CLR */
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_9);
+                                       if (super == NULL)
+                                               emit_label(cd, BRANCH_LABEL_10);
+                                       if (d == REG_ITMP2) {
+                                               M_CLR(d);
+                                               emit_label(cd, BRANCH_LABEL_7);
+                                       }
+                                       emit_label(cd, BRANCH_LABEL_6);
+                               }
+                               else {
+                                       M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+                                       M_SETE(d);
+                                       if (d == REG_ITMP2)
+                                               M_BSEXT(d, d);
+                               }
  
                                if (super != NULL)
                                        emit_label(cd, BRANCH_LABEL_5);
diff --combined src/vm/jit/x86_64/emit.c
index 60b37d9163dac1c14db1cae54b621d4f8f3b26bb,9c777fb54a558b0545c5177ea11a2fdea6107ae3..5f6f0d87a76fcfa7323255f0f2b4ba83246806a5
@@@ -33,7 -33,7 +33,7 @@@
  #include "vm/jit/x86_64/codegen.h"
  #include "vm/jit/x86_64/emit.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "threads/lock.hpp"
  
@@@ -359,9 -359,15 +359,15 @@@ void emit_classcast_check(codegendata *
                case BRANCH_LE:
                        M_BGT(8);
                        break;
+               case BRANCH_GE:
+                       M_BLT(8);
+                       break;
                case BRANCH_EQ:
                        M_BNE(8);
                        break;
+               case BRANCH_NE:
+                       M_BEQ(8);
+                       break;
                case BRANCH_UGT:
                        M_BULE(8);
                        break;
@@@ -1395,6 -1401,19 +1401,19 @@@ void emit_alul_imm_membase(codegendata 
        }
  }
  
+ void emit_alu_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg)
+ {
+       emit_rex(1,(reg),(indexreg),(basereg));
+       *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+       emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+ }
+ void emit_alul_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg)
+ {
+       emit_rex(0,(reg),(indexreg),(basereg));
+       *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+       emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+ }
  
  void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
        emit_rex(1,(reg),0,(dreg));
@@@ -1446,6 -1465,18 +1465,18 @@@ void emit_leal_membase_reg(codegendata 
  }
  
  
+ void emit_incl_reg(codegendata *cd, s8 reg)
+ {
+       *(cd->mcodeptr++) = 0xff;
+       emit_reg(0,(reg));
+ }
+ void emit_incq_reg(codegendata *cd, s8 reg)
+ {
+       emit_rex(1,0,0,(reg));
+       *(cd->mcodeptr++) = 0xff;
+       emit_reg(0,(reg));
+ }
  
  void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp)
  {
        emit_membase(cd, (basereg),(disp),0);
  }
  
+ void emit_incq_membase(codegendata *cd, s8 basereg, s8 disp)
+ {
+       emit_rex(1,0,0,(basereg));
+       *(cd->mcodeptr++) = 0xff;
+       emit_membase(cd, (basereg),(disp),0);
+ }
  
  
  void emit_cltd(codegendata *cd) {
@@@ -1686,6 -1724,18 +1724,18 @@@ void emit_jmp_imm(codegendata *cd, s8 i
        emit_imm32((imm));
  }
  
+ /* like emit_jmp_imm but allows 8 bit optimization */
+ void emit_jmp_imm2(codegendata *cd, s8 imm) {
+       if (IS_IMM8(imm)) {
+               *(cd->mcodeptr++) = 0xeb;
+               emit_imm8((imm));
+       }
+       else {
+               *(cd->mcodeptr++) = 0xe9;
+               emit_imm32((imm));
+       }
+ }
  
  void emit_jmp_reg(codegendata *cd, s8 reg) {
        emit_rex(0,0,0,(reg));
diff --combined src/vm/linker.cpp
index 84672cfb16cbf46a3587656e5ff220fe453dd858,50639b736310468fe801800ded6d5af43b443748..b1bd60a427ca66815990cf6269939f03395e75be
  
  #include "vm/types.h"
  
 -#include "mm/memory.h"
 +#include "mm/memory.hpp"
  
  #include "native/native.hpp"
  
  #include "threads/lock.hpp"
  #include "threads/mutex.hpp"
  
 -#include "toolbox/logging.h"
 +#include "toolbox/logging.hpp"
  
  #include "vm/access.hpp"
  #include "vm/array.hpp"
@@@ -94,7 -94,9 +94,9 @@@ classinfo *resolve_classref_or_classinf
  static s4 interfaceindex;       /* sequential numbering of interfaces         */
  static s4 classvalue;
  
- Mutex *linker_classrenumber_mutex;
+ #if !USES_NEW_SUBTYPE
+ Mutex *linker_classrenumber_lock;
+ #endif
  
  #if defined(__cplusplus)
  extern "C" {
@@@ -125,10 -127,10 +127,10 @@@ void linker_preinit(void
  
        interfaceindex = 0;
  
- #if defined(ENABLE_THREADS)
+ #if defined(ENABLE_THREADS) && !USES_NEW_SUBTYPE
        /* create the global mutex */
  
-       linker_classrenumber_mutex = new Mutex();
+       linker_classrenumber_lock = new Mutex();
  #endif
  
        /* Link the most basic classes. */
@@@ -519,6 -521,77 +521,77 @@@ static bool linker_overwrite_method(met
  }
  
  
+ #if USES_NEW_SUBTYPE
+ /* build_display ***************************************************************
+    Builds the entire display for a class. This entails filling the fixed part
+    as well as allocating and initializing the overflow part.
+    See Cliff Click and John Rose: Fast subtype checking in the Hotspot JVM.
+ *******************************************************************************/
+ static classinfo *build_display(classinfo *c)
+ {
+       int depth, i;
+       int depth_fixed;
+       classinfo *super;
+       do {
+               /* Handle arrays. */
+               if (c->vftbl->arraydesc) {
+                       arraydescriptor *a = c->vftbl->arraydesc;
+                       if (a->elementvftbl && a->elementvftbl->clazz->super) {
+                               classinfo *cls = a->elementvftbl->clazz->super;
+                               int n;
+                               for (n=0; n<a->dimension; n++)
+                                       cls = class_array_of(cls, true);
+                               super = cls;
+                               break;
+                       }
+                       if (a->componentvftbl && a->elementvftbl) {
+                               super = a->componentvftbl->clazz;
+                               break;
+                       }
+               }
+               /* Normal classes. */
+               super = c->super;
+       } while (false);
+       if (super) {
+               if (!link_class(super))
+                       return NULL;
+               depth = super->vftbl->subtype_depth + 1;
+       } else
+               /* java.lang.Object doesn't have a super class. */
+               depth = 0;
+       /* Now copy super's display, append c->vftbl and initialize the remaining fields. */
+       if (depth >= DISPLAY_SIZE) {
+               c->vftbl->subtype_overflow = MNEW(vftbl_t *, depth - DISPLAY_SIZE + 1);
+ #if defined(ENABLE_STATISTICS)
+               if (opt_stat)
+                       count_vftbl_len += sizeof(vftbl_t*) * (depth - DISPLAY_SIZE + 1);
+ #endif
+               memcpy(c->vftbl->subtype_overflow, super->vftbl->subtype_overflow, sizeof(vftbl_t*) * (depth - DISPLAY_SIZE));
+               c->vftbl->subtype_overflow[depth - DISPLAY_SIZE] = c->vftbl;
+               depth_fixed = DISPLAY_SIZE;
+       }
+       else {
+               depth_fixed = depth;
+               c->vftbl->subtype_display[depth] = c->vftbl;
+       }
+       if (super)
+               memcpy(c->vftbl->subtype_display, super->vftbl->subtype_display, sizeof(vftbl_t*) * depth_fixed);
+       for (i=depth_fixed+1; i<=DISPLAY_SIZE; i++)
+               c->vftbl->subtype_display[i] = NULL;
+       c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[0]) + sizeof(vftbl_t*) * depth_fixed;
+       c->vftbl->subtype_depth = depth;
+       return c;
+ }
+ #endif
  /* link_class_intern ***********************************************************
  
     Tries to link a class. The function calculates the length in bytes
@@@ -921,8 -994,14 +994,14 @@@ static classinfo *link_class_intern(cla
  
        linker_compute_subclasses(c);
  
+       /* FIXME: this is completely useless now */
        RT_TIMING_GET_TIME(time_subclasses);
  
+ #if USES_NEW_SUBTYPE
+       if (!build_display(c))
+               return NULL;
+ #endif
        /* revert the linking state and class is linked */
  
        c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
@@@ -1029,8 -1108,8 +1108,8 @@@ static arraydescriptor *link_array(clas
                        desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
  
                        if (compvftbl->arraydesc->dimension >= 255) {
 -                              log_text("Creating array of dimension >255");
 -                              assert(0);
 +                              exceptions_throw_illegalargumentexception();
 +                              return NULL;
                        }
  
                        desc->dimension = compvftbl->arraydesc->dimension + 1;
  
  static void linker_compute_subclasses(classinfo *c)
  {
-       linker_classrenumber_mutex->lock();
+       LOCK_CLASSRENUMBER_LOCK;
  
        if (!(c->flags & ACC_INTERFACE)) {
                c->nextsub = NULL;
                c->sub     = NULL;
+ #if USES_NEW_SUBTYPE
+               c->vftbl->baseval = 1; /* so it does not look like an interface */
+ #endif
        }
  
        if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
  
        classvalue = 0;
  
+ #if !USES_NEW_SUBTYPE
        /* compute class values */
  
        linker_compute_class_values(class_java_lang_Object);
+ #endif
+       UNLOCK_CLASSRENUMBER_LOCK;
  
-       linker_classrenumber_mutex->unlock();
  }