Merge "More exception cleanup." into dalvik-dev
diff --git a/vm/Exception.c b/vm/Exception.c
index 9e32d47..0a796fd 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -156,7 +156,14 @@
     ok &= initRef(&gDvm.exRuntimeException, "Ljava/lang/RuntimeException;");
     ok &= initRef(&gDvm.exStackOverflowError,
             "Ljava/lang/StackOverflowError;");
+    ok &= initRef(&gDvm.exStringIndexOutOfBoundsException,
+            "Ljava/lang/StringIndexOutOfBoundsException;");
     ok &= initRef(&gDvm.exThrowable, "Ljava/lang/Throwable;");
+    ok &= initRef(&gDvm.exUnsupportedOperationException,
+            "Ljava/lang/UnsupportedOperationException;");
+    ok &= initRef(&gDvm.exVirtualMachineError,
+            "Ljava/lang/VirtualMachineError;");
+
     ok &= initRef(&gDvm.classJavaLangStackTraceElement,
             "Ljava/lang/StackTraceElement;");
     ok &= initRef(&gDvm.classJavaLangStackTraceElementArray,
@@ -1572,8 +1579,17 @@
     dvmThrowException("Ldalvik/system/StaleDexCacheError;", msg);
 }
 
-void dvmThrowStringIndexOutOfBoundsException(const char* msg) {
-    dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", msg);
+void dvmThrowStringIndexOutOfBoundsExceptionWithIndex(jsize stringLength,
+        jsize requestIndex) {
+    dvmThrowExceptionFmtByClass(gDvm.exStringIndexOutOfBoundsException,
+            "length=%d; index==%d", stringLength, requestIndex);
+}
+
+void dvmThrowStringIndexOutOfBoundsExceptionWithRegion(jsize stringLength,
+        jsize requestStart, jsize requestLength) {
+    dvmThrowExceptionFmtByClass(gDvm.exStringIndexOutOfBoundsException,
+            "length=%d; regionStart=%d regionLength=%d",
+            stringLength, requestStart, requestLength);
 }
 
 void dvmThrowUnsatisfiedLinkError(const char* msg) {
@@ -1581,9 +1597,9 @@
 }
 
 void dvmThrowUnsupportedOperationException(const char* msg) {
-    dvmThrowException("Ljava/lang/UnsupportedOperationException;", msg);
+    dvmThrowExceptionByClass(gDvm.exUnsupportedOperationException, msg);
 }
 
 void dvmThrowVirtualMachineError(const char* msg) {
-    dvmThrowException("Ljava/lang/VirtualMachineError;", msg);
+    dvmThrowExceptionByClass(gDvm.exVirtualMachineError, msg);
 }
diff --git a/vm/Exception.h b/vm/Exception.h
index 9fbad99..37553ba 100644
--- a/vm/Exception.h
+++ b/vm/Exception.h
@@ -404,9 +404,19 @@
 
 /**
  * Throw a StringIndexOutOfBoundsException in the current thread, with
- * the given detail message.
+ * a detail message specifying an actual length as well as a requested
+ * index.
  */
-void dvmThrowStringIndexOutOfBoundsException(const char* msg);
+void dvmThrowStringIndexOutOfBoundsExceptionWithIndex(jsize stringLength,
+        jsize requestIndex);
+
+/**
+ * Throw a StringIndexOutOfBoundsException in the current thread, with
+ * a detail message specifying an actual length as well as a requested
+ * region.
+ */
+void dvmThrowStringIndexOutOfBoundsExceptionWithRegion(jsize stringLength,
+        jsize requestStart, jsize requestLength);
 
 /**
  * Throw an UnsatisfiedLinkError in the current thread, with
diff --git a/vm/Globals.h b/vm/Globals.h
index 25f6c15..9c55ee7 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -280,7 +280,10 @@
     ClassObject* exNullPointerException;
     ClassObject* exRuntimeException;
     ClassObject* exStackOverflowError;
+    ClassObject* exStringIndexOutOfBoundsException;
     ClassObject* exThrowable;
+    ClassObject* exUnsupportedOperationException;
+    ClassObject* exVirtualMachineError;
 
     /* synthetic classes for arrays of primitives */
     ClassObject* classArrayBoolean;
diff --git a/vm/InlineNative.c b/vm/InlineNative.c
index 1cc86ea..6b78878 100644
--- a/vm/InlineNative.c
+++ b/vm/InlineNative.c
@@ -139,8 +139,7 @@
     //LOGI("String.charAt this=0x%08x index=%d\n", arg0, arg1);
     count = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
     if ((s4) arg1 < 0 || (s4) arg1 >= count) {
-        dvmThrowExceptionFmt("Ljava/lang/StringIndexOutOfBoundsException;",
-            "index=%d length=%d", arg1, count);
+        dvmThrowStringIndexOutOfBoundsExceptionWithIndex(count, arg1);
         return false;
     } else {
         offset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
diff --git a/vm/Jni.c b/vm/Jni.c
index 6b083af..6df5ab0 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -3411,8 +3411,9 @@
 {
     JNI_ENTER();
     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
-    if (start + len > dvmStringLen(strObj))
-        dvmThrowStringIndexOutOfBoundsException(NULL);
+    int strLen = dvmStringLen(strObj);
+    if (((start|len) < 0) || (start + len > dvmStringLen(strObj)))
+        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
     else
         memcpy(buf, dvmStringChars(strObj) + start, len * sizeof(u2));
     JNI_EXIT();
@@ -3427,8 +3428,9 @@
 {
     JNI_ENTER();
     StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr);
-    if (start + len > dvmStringLen(strObj))
-        dvmThrowStringIndexOutOfBoundsException(NULL);
+    int strLen = dvmStringLen(strObj);
+    if (((start|len) < 0) || (start + len > dvmStringLen(strObj)))
+        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
     else
         dvmCreateCstrFromStringRegion(strObj, start, len, buf);
     JNI_EXIT();