Merge "Use the generated opcode info tables." into dalvik-dev
diff --git a/vm/Exception.c b/vm/Exception.c
index 7b0a835..13c655f 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -1359,3 +1359,13 @@
     dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;",
         "index=%d length=%d", index, length);
 }
+
+void dvmThrowClassCastException(ClassObject* actual, ClassObject* desired)
+{
+    char* actualClassName = dvmDescriptorToDot(actual->descriptor);
+    char* desiredClassName = dvmDescriptorToDot(desired->descriptor);
+    dvmThrowExceptionFmt("Ljava/lang/ClassCastException;", "%s cannot be cast to %s",
+        actualClassName, desiredClassName);
+    free(desiredClassName);
+    free(actualClassName);
+}
diff --git a/vm/Exception.h b/vm/Exception.h
index 559e47f..41ee189 100644
--- a/vm/Exception.h
+++ b/vm/Exception.h
@@ -41,6 +41,12 @@
  */
 void dvmThrowAIOOBE(int index, int length);
 
+/**
+ * Throw a ClassCastException in the current thread, using the given classes'
+ * names in the detail message.
+ */
+void dvmThrowClassCastException(ClassObject* actual, ClassObject* desired);
+
 /*
  * Like dvmThrowChainedException, but takes printf-style args for the message.
  */
diff --git a/vm/mterp/armv5te/OP_CHECK_CAST.S b/vm/mterp/armv5te/OP_CHECK_CAST.S
index c711276..3a07ea3 100644
--- a/vm/mterp/armv5te/OP_CHECK_CAST.S
+++ b/vm/mterp/armv5te/OP_CHECK_CAST.S
@@ -32,21 +32,20 @@
     /*
      * Trivial test failed, need to perform full check.  This is common.
      *  r0 holds obj->clazz
-     *  r1 holds class resolved from BBBB
+     *  r1 holds desired class resolved from BBBB
      *  r9 holds object
      */
 .L${opcode}_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
     bl      dvmInstanceofNonTrivial     @ r0<- boolean result
     cmp     r0, #0                      @ failed?
     bne     .L${opcode}_okay            @ no, success
 
-    @ A cast has failed.  We need to throw a ClassCastException with the
-    @ class of the object that failed to be cast.
+    @ A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC()                         @ about to throw
-    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
-    ldr     r0, .LstrClassCastExceptionPtr
-    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
-    bl      dvmThrowExceptionWithClassMessage
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
     b       common_exceptionThrown
 
     /*
@@ -67,6 +66,3 @@
     mov     r1, r0                      @ r1<- class resolved from BBB
     ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
     b       .L${opcode}_resolved        @ pick up where we left off
-
-.LstrClassCastExceptionPtr:
-    .word   .LstrClassCastException
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index ad4994d..8f15c59 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -1257,8 +1257,6 @@
     .asciz  "Ljava/lang/ArithmeticException;"
 .LstrArrayStoreException:
     .asciz  "Ljava/lang/ArrayStoreException;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrDivideByZero:
     .asciz  "divide by zero"
 .LstrFilledNewArrayNotImpl:
diff --git a/vm/mterp/c/OP_CHECK_CAST.c b/vm/mterp/c/OP_CHECK_CAST.c
index 9a7ecfb..2c4a304 100644
--- a/vm/mterp/c/OP_CHECK_CAST.c
+++ b/vm/mterp/c/OP_CHECK_CAST.c
@@ -22,8 +22,7 @@
                     GOTO_exceptionThrown();
             }
             if (!dvmInstanceof(obj->clazz, clazz)) {
-                dvmThrowExceptionWithClassMessage(
-                    "Ljava/lang/ClassCastException;", obj->clazz->descriptor);
+                dvmThrowClassCastException(obj->clazz, clazz);
                 GOTO_exceptionThrown();
             }
         }
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index fe923dc..bcb357a 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -7827,21 +7827,20 @@
     /*
      * Trivial test failed, need to perform full check.  This is common.
      *  r0 holds obj->clazz
-     *  r1 holds class resolved from BBBB
+     *  r1 holds desired class resolved from BBBB
      *  r9 holds object
      */
 .LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
     bl      dvmInstanceofNonTrivial     @ r0<- boolean result
     cmp     r0, #0                      @ failed?
     bne     .LOP_CHECK_CAST_okay            @ no, success
 
-    @ A cast has failed.  We need to throw a ClassCastException with the
-    @ class of the object that failed to be cast.
+    @ A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC()                         @ about to throw
-    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
-    ldr     r0, .LstrClassCastExceptionPtr
-    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
-    bl      dvmThrowExceptionWithClassMessage
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
     b       common_exceptionThrown
 
     /*
@@ -7863,9 +7862,6 @@
     ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
     b       .LOP_CHECK_CAST_resolved        @ pick up where we left off
 
-.LstrClassCastExceptionPtr:
-    .word   .LstrClassCastException
-
 /* continuation for OP_INSTANCE_OF */
 
     /*
@@ -10614,8 +10610,6 @@
     .asciz  "Ljava/lang/ArithmeticException;"
 .LstrArrayStoreException:
     .asciz  "Ljava/lang/ArrayStoreException;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrDivideByZero:
     .asciz  "divide by zero"
 .LstrFilledNewArrayNotImpl:
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index b30260c..05898d3 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -8149,21 +8149,20 @@
     /*
      * Trivial test failed, need to perform full check.  This is common.
      *  r0 holds obj->clazz
-     *  r1 holds class resolved from BBBB
+     *  r1 holds desired class resolved from BBBB
      *  r9 holds object
      */
 .LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
     bl      dvmInstanceofNonTrivial     @ r0<- boolean result
     cmp     r0, #0                      @ failed?
     bne     .LOP_CHECK_CAST_okay            @ no, success
 
-    @ A cast has failed.  We need to throw a ClassCastException with the
-    @ class of the object that failed to be cast.
+    @ A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC()                         @ about to throw
-    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
-    ldr     r0, .LstrClassCastExceptionPtr
-    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
-    bl      dvmThrowExceptionWithClassMessage
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
     b       common_exceptionThrown
 
     /*
@@ -8185,9 +8184,6 @@
     ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
     b       .LOP_CHECK_CAST_resolved        @ pick up where we left off
 
-.LstrClassCastExceptionPtr:
-    .word   .LstrClassCastException
-
 /* continuation for OP_INSTANCE_OF */
 
     /*
@@ -11072,8 +11068,6 @@
     .asciz  "Ljava/lang/ArithmeticException;"
 .LstrArrayStoreException:
     .asciz  "Ljava/lang/ArrayStoreException;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrDivideByZero:
     .asciz  "divide by zero"
 .LstrFilledNewArrayNotImpl:
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index 65514b3..4c2da43 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -7781,21 +7781,20 @@
     /*
      * Trivial test failed, need to perform full check.  This is common.
      *  r0 holds obj->clazz
-     *  r1 holds class resolved from BBBB
+     *  r1 holds desired class resolved from BBBB
      *  r9 holds object
      */
 .LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
     bl      dvmInstanceofNonTrivial     @ r0<- boolean result
     cmp     r0, #0                      @ failed?
     bne     .LOP_CHECK_CAST_okay            @ no, success
 
-    @ A cast has failed.  We need to throw a ClassCastException with the
-    @ class of the object that failed to be cast.
+    @ A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC()                         @ about to throw
-    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
-    ldr     r0, .LstrClassCastExceptionPtr
-    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
-    bl      dvmThrowExceptionWithClassMessage
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
     b       common_exceptionThrown
 
     /*
@@ -7817,9 +7816,6 @@
     ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
     b       .LOP_CHECK_CAST_resolved        @ pick up where we left off
 
-.LstrClassCastExceptionPtr:
-    .word   .LstrClassCastException
-
 /* continuation for OP_INSTANCE_OF */
 
     /*
@@ -10552,8 +10548,6 @@
     .asciz  "Ljava/lang/ArithmeticException;"
 .LstrArrayStoreException:
     .asciz  "Ljava/lang/ArrayStoreException;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrDivideByZero:
     .asciz  "divide by zero"
 .LstrFilledNewArrayNotImpl:
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index dff7ef5..c17fe9d 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -7781,21 +7781,20 @@
     /*
      * Trivial test failed, need to perform full check.  This is common.
      *  r0 holds obj->clazz
-     *  r1 holds class resolved from BBBB
+     *  r1 holds desired class resolved from BBBB
      *  r9 holds object
      */
 .LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
     bl      dvmInstanceofNonTrivial     @ r0<- boolean result
     cmp     r0, #0                      @ failed?
     bne     .LOP_CHECK_CAST_okay            @ no, success
 
-    @ A cast has failed.  We need to throw a ClassCastException with the
-    @ class of the object that failed to be cast.
+    @ A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC()                         @ about to throw
-    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
-    ldr     r0, .LstrClassCastExceptionPtr
-    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
-    bl      dvmThrowExceptionWithClassMessage
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
     b       common_exceptionThrown
 
     /*
@@ -7817,9 +7816,6 @@
     ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
     b       .LOP_CHECK_CAST_resolved        @ pick up where we left off
 
-.LstrClassCastExceptionPtr:
-    .word   .LstrClassCastException
-
 /* continuation for OP_INSTANCE_OF */
 
     /*
@@ -10552,8 +10548,6 @@
     .asciz  "Ljava/lang/ArithmeticException;"
 .LstrArrayStoreException:
     .asciz  "Ljava/lang/ArrayStoreException;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrDivideByZero:
     .asciz  "divide by zero"
 .LstrFilledNewArrayNotImpl:
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index c2ce035..6ddf10f 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -6556,21 +6556,20 @@
      *  rINST holds object
      */
 .LOP_CHECK_CAST_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
     movl    %eax,OUT_ARG1(%esp)
     movl    %ecx,OUT_ARG0(%esp)
-    call    dvmInstanceofNonTrivial     # eax<- boolean result
-    testl   %eax,%eax                   # failed?
-    jne     .LOP_CHECK_CAST_okay            # no, success
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    testl   %eax,%eax                  # failed?
+    jne     .LOP_CHECK_CAST_okay           # no, success
 
-    # A cast has failed.  We need to throw a ClassCastException with the
-    # class of the object that failed to be cast.
+    # A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC
-    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
-    movl    $.LstrClassCastException,%eax
-    movl    offClassObject_descriptor(%ecx),%ecx
-    movl    %eax,OUT_ARG0(%esp)     # arg0<- message
-    movl    %ecx,OUT_ARG1(%esp)     # arg1<- obj->clazz->descriptor
-    call    dvmThrowExceptionWithClassMessage
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
     jmp     common_exceptionThrown
 
     /*
@@ -9598,8 +9597,6 @@
     .asciz  "Ljava/lang/NegativeArraySizeException;"
 .LstrInstantiationError:
     .asciz  "Ljava/lang/InstantiationError;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrNoSuchMethodError:
     .asciz  "Ljava/lang/NoSuchMethodError;"
 .LstrInternalErrorA:
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 198d623..0379d7a 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -1616,8 +1616,7 @@
                     GOTO_exceptionThrown();
             }
             if (!dvmInstanceof(obj->clazz, clazz)) {
-                dvmThrowExceptionWithClassMessage(
-                    "Ljava/lang/ClassCastException;", obj->clazz->descriptor);
+                dvmThrowClassCastException(obj->clazz, clazz);
                 GOTO_exceptionThrown();
             }
         }
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index e32a9ce..03b69df 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -1972,8 +1972,7 @@
                     GOTO_exceptionThrown();
             }
             if (!dvmInstanceof(obj->clazz, clazz)) {
-                dvmThrowExceptionWithClassMessage(
-                    "Ljava/lang/ClassCastException;", obj->clazz->descriptor);
+                dvmThrowClassCastException(obj->clazz, clazz);
                 GOTO_exceptionThrown();
             }
         }
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 6070ec3..b0adbc8 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -1722,8 +1722,7 @@
                     GOTO_exceptionThrown();
             }
             if (!dvmInstanceof(obj->clazz, clazz)) {
-                dvmThrowExceptionWithClassMessage(
-                    "Ljava/lang/ClassCastException;", obj->clazz->descriptor);
+                dvmThrowClassCastException(obj->clazz, clazz);
                 GOTO_exceptionThrown();
             }
         }
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
index 0d50d2e..462728d 100644
--- a/vm/mterp/x86-atom/TODO.txt
+++ b/vm/mterp/x86-atom/TODO.txt
@@ -11,7 +11,8 @@
 
 (md) Correct OP_MONITOR_EXIT (need to adjust PC before throw)
 (md) OP_THROW needs to export the PC
-(md) Use dvmThrowAIOOBE(index, lentgh) for array bounds error.
+(md) Use dvmThrowAIOOBE(index, length) for array bounds errors.
+(md) Use dvmThrowClassCastException(actual, desired) for class cast errors.
 
 (lo) Implement OP_BREAKPOINT
 (lo) Implement OP_EXECUTE_INLINE_RANGE
diff --git a/vm/mterp/x86/OP_CHECK_CAST.S b/vm/mterp/x86/OP_CHECK_CAST.S
index 176dc57..6fb8415 100644
--- a/vm/mterp/x86/OP_CHECK_CAST.S
+++ b/vm/mterp/x86/OP_CHECK_CAST.S
@@ -36,21 +36,20 @@
      *  rINST holds object
      */
 .L${opcode}_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
     movl    %eax,OUT_ARG1(%esp)
     movl    %ecx,OUT_ARG0(%esp)
-    call    dvmInstanceofNonTrivial     # eax<- boolean result
-    testl   %eax,%eax                   # failed?
-    jne     .L${opcode}_okay            # no, success
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    testl   %eax,%eax                  # failed?
+    jne     .L${opcode}_okay           # no, success
 
-    # A cast has failed.  We need to throw a ClassCastException with the
-    # class of the object that failed to be cast.
+    # A cast has failed.  We need to throw a ClassCastException.
     EXPORT_PC
-    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
-    movl    $$.LstrClassCastException,%eax
-    movl    offClassObject_descriptor(%ecx),%ecx
-    movl    %eax,OUT_ARG0(%esp)     # arg0<- message
-    movl    %ecx,OUT_ARG1(%esp)     # arg1<- obj->clazz->descriptor
-    call    dvmThrowExceptionWithClassMessage
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
     jmp     common_exceptionThrown
 
     /*
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
index fb6df27..1d63a52 100644
--- a/vm/mterp/x86/footer.S
+++ b/vm/mterp/x86/footer.S
@@ -502,8 +502,6 @@
     .asciz  "Ljava/lang/NegativeArraySizeException;"
 .LstrInstantiationError:
     .asciz  "Ljava/lang/InstantiationError;"
-.LstrClassCastException:
-    .asciz  "Ljava/lang/ClassCastException;"
 .LstrNoSuchMethodError:
     .asciz  "Ljava/lang/NoSuchMethodError;"
 .LstrInternalErrorA: