Merge change I866cc5d6

* changes:
  Improve run-core-tests.
diff --git a/libcore/luni/src/main/java/java/net/InetAddress.java b/libcore/luni/src/main/java/java/net/InetAddress.java
index 0fa4796..33c25f3 100644
--- a/libcore/luni/src/main/java/java/net/InetAddress.java
+++ b/libcore/luni/src/main/java/java/net/InetAddress.java
@@ -272,7 +272,7 @@
             }
         }
 
-        byte[] hBytes = Inet6Util.createByteArrayFromIPAddressString(host);
+        byte[] hBytes = NETIMPL.ipStringToByteArray(host);
         if (hBytes.length == 4) {
             return (new InetAddress[] { new Inet4Address(hBytes) });
         } else if (hBytes.length == 16) {
@@ -301,7 +301,8 @@
         return getAllByNameImpl(host, false)[0];
     }
 
-    /*
+    // BEGIN android-added
+    /**
      * Convenience method to convert a byte array to a string, converting
      * exceptions to runtime exceptions. This is used when passing in byte
      * arrays that have been verified to be correct and is necessary because
@@ -310,6 +311,8 @@
      * UnknownHostException. Exceptions should never occur when the address is
      * valid, but they cannot be simply ignored because they could be due to
      * runtime errors such as out-of-memory conditions.
+     *
+     * @param ipaddress the byte array to convert
      */
     private static String ipAddressToString(byte[] ipaddress) {
         try {
@@ -318,6 +321,7 @@
             throw new RuntimeException(e);
         }
     }
+    // END android-added
 
     /**
      * Gets the textual representation of this IP address.
@@ -735,8 +739,12 @@
      * Returns true if the string is a host name, false if it is an IP Address.
      */
     private static boolean isHostName(String value) {
-        return !(Inet6Util.isValidIPV4Address(value) || Inet6Util
-                .isValidIP6Address(value));
+        try {
+            NETIMPL.ipStringToByteArray(value);
+            return false;
+        } catch (UnknownHostException e) {
+            return true;
+        }
     }
 
     /**
@@ -1278,173 +1286,6 @@
         return value;
     }
 
-    /**
-     * Creates an InetAddress based on the {@code ipAddressString}. No error
-     * handling is performed here.
-     */
-    static InetAddress createHostNameFromIPAddress(String ipAddressString)
-            throws UnknownHostException {
-
-        InetAddress address = null;
-
-        if (Inet6Util.isValidIPV4Address(ipAddressString)) {
-            byte[] byteAddress = new byte[4];
-            String[] parts = ipAddressString.split("\\."); //$NON-NLS-1$
-            int length = parts.length;
-            if (length == 1) {
-                long value = Long.parseLong(parts[0]);
-                for (int i = 0; i < 4; i++) {
-                    byteAddress[i] = (byte) (value >> ((3 - i) * 8));
-                }
-            } else {
-                for (int i = 0; i < length; i++) {
-                    byteAddress[i] = (byte) Integer.parseInt(parts[i]);
-                }
-            }
-
-            // adjust for 2/3 parts address
-            if (length == 2) {
-                byteAddress[3] = byteAddress[1];
-                byteAddress[1] = 0;
-            }
-            if (length == 3) {
-                byteAddress[3] = byteAddress[2];
-                byteAddress[2] = 0;
-            }
-
-            address = new Inet4Address(byteAddress);
-        } else { // otherwise it must be ipv6
-
-            if (ipAddressString.charAt(0) == '[') {
-                ipAddressString = ipAddressString.substring(1, ipAddressString
-                        .length() - 1);
-            }
-
-            StringTokenizer tokenizer = new StringTokenizer(ipAddressString,
-                    ":.%", true); //$NON-NLS-1$
-            ArrayList<String> hexStrings = new ArrayList<String>();
-            ArrayList<String> decStrings = new ArrayList<String>();
-            String scopeString = null;
-            String token = ""; //$NON-NLS-1$
-            String prevToken = ""; //$NON-NLS-1$
-            String prevPrevToken = ""; //$NON-NLS-1$
-            int doubleColonIndex = -1; // If a double colon exists, we need to
-            // insert 0s.
-
-            // Go through the tokens, including the separators ':' and '.'
-            // When we hit a : or . the previous token will be added to either
-            // the hex list or decimal list. In the case where we hit a ::
-            // we will save the index of the hexStrings so we can add zeros
-            // in to fill out the string
-            while (tokenizer.hasMoreTokens()) {
-                prevPrevToken = prevToken;
-                prevToken = token;
-                token = tokenizer.nextToken();
-
-                if (token.equals(":")) { //$NON-NLS-1$
-                    if (prevToken.equals(":")) { //$NON-NLS-1$
-                        doubleColonIndex = hexStrings.size();
-                    } else if (!prevToken.equals("")) { //$NON-NLS-1$
-                        hexStrings.add(prevToken);
-                    }
-                } else if (token.equals(".")) { //$NON-NLS-1$
-                    decStrings.add(prevToken);
-                } else if (token.equals("%")) { //$NON-NLS-1$
-                    // add the last word before the % properly
-                    if (!prevToken.equals(":") && !prevToken.equals(".")) { //$NON-NLS-1$ //$NON-NLS-2$
-                        if (prevPrevToken.equals(":")) { //$NON-NLS-1$
-                            hexStrings.add(prevToken);
-                        } else if (prevPrevToken.equals(".")) { //$NON-NLS-1$
-                            decStrings.add(prevToken);
-                        }
-                    }
-
-                    // the rest should be the scope string
-                    scopeString = tokenizer.nextToken();
-                    while (tokenizer.hasMoreTokens()) {
-                        scopeString = scopeString + tokenizer.nextToken();
-                    }
-                }
-            }
-
-            if (prevToken.equals(":")) { //$NON-NLS-1$
-                if (token.equals(":")) { //$NON-NLS-1$
-                    doubleColonIndex = hexStrings.size();
-                } else {
-                    hexStrings.add(token);
-                }
-            } else if (prevToken.equals(".")) { //$NON-NLS-1$
-                decStrings.add(token);
-            }
-
-            // figure out how many hexStrings we should have
-            // also check if it is a IPv4 address
-            int hexStringsLength = 8;
-
-            // If we have an IPv4 address tagged on at the end, subtract
-            // 4 bytes, or 2 hex words from the total
-            if (decStrings.size() > 0) {
-                hexStringsLength -= 2;
-            }
-
-            // if we hit a double Colon add the appropriate hex strings
-            if (doubleColonIndex != -1) {
-                int numberToInsert = hexStringsLength - hexStrings.size();
-                for (int i = 0; i < numberToInsert; i++) {
-                    hexStrings.add(doubleColonIndex, "0"); //$NON-NLS-1$
-                }
-            }
-
-            byte ipByteArray[] = new byte[16];
-
-            // Finally convert these strings to bytes...
-            for (int i = 0; i < hexStrings.size(); i++) {
-                Inet6Util.convertToBytes(hexStrings.get(i), ipByteArray, i * 2);
-            }
-
-            // Now if there are any decimal values, we know where they go...
-            for (int i = 0; i < decStrings.size(); i++) {
-                ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings
-                        .get(i)) & 255);
-            }
-
-            // now check to see if this guy is actually and IPv4 address
-            // an ipV4 address is ::FFFF:d.d.d.d
-            boolean ipV4 = true;
-            for (int i = 0; i < 10; i++) {
-                if (ipByteArray[i] != 0) {
-                    ipV4 = false;
-                    break;
-                }
-            }
-
-            if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
-                ipV4 = false;
-            }
-
-            if (ipV4) {
-                byte ipv4ByteArray[] = new byte[4];
-                for (int i = 0; i < 4; i++) {
-                    ipv4ByteArray[i] = ipByteArray[i + 12];
-                }
-                address = InetAddress.getByAddress(ipv4ByteArray);
-            } else {
-                int scopeId = 0;
-                if (scopeString != null) {
-                    try {
-                        scopeId = Integer.parseInt(scopeString);
-                    } catch (Exception e) {
-                        // this should not occur as we should not get into this
-                        // function unless the address is in a valid format
-                    }
-                }
-                address = InetAddress.getByAddress(ipByteArray, scopeId);
-            }
-        }
-
-        return address;
-    }
-
     static boolean preferIPv6Addresses() {
         String result = AccessController.doPrivileged(new PriviAction<String>(
                 "java.net.preferIPv6Addresses")); //$NON-NLS-1$
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
index 1345341..fb47f0d 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
@@ -218,9 +218,14 @@
 
     public void setInetAddress(InetAddress sender, byte[] address);
 
+    // BEGIN android-added
     public String byteArrayToIpString(byte[] address)
             throws UnknownHostException;
 
+    public byte[] ipStringToByteArray(String address)
+            throws UnknownHostException;
+    // END android-added
+
     // BEGIN android-removed
     // public boolean isReachableByICMP(InetAddress dest,InetAddress source,int ttl,int timeout);
     // END android-removed
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 0fa25ea..bd6a609 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -242,6 +242,9 @@
     public native String byteArrayToIpString(byte[] address)
             throws UnknownHostException;
 
+    public native byte[] ipStringToByteArray(String address)
+            throws UnknownHostException;
+
     static native int getSocketFlagsImpl();
 
     public InetAddress getSocketLocalAddress(FileDescriptor fd,
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java b/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
index 4dae1c3..55914de 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/Inet6Util.java
@@ -24,244 +24,6 @@
  */
 public class Inet6Util {
 
-	/**
-	 * Creates an byte[] based on an ipAddressString. No error handling is
-	 * performed here.
-	 */
-	public static byte[] createByteArrayFromIPAddressString(
-			String ipAddressString) {
-
-		if (isValidIPV4Address(ipAddressString)) {
-            StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ".");
-			String token = "";
-			int tempInt = 0;
-			byte[] byteAddress = new byte[4];
-			for (int i = 0; i < 4; i++) {
-				token = tokenizer.nextToken();
-				tempInt = Integer.parseInt(token);
-				byteAddress[i] = (byte) tempInt;
-			}
-
-			return byteAddress;
-		}
-
-		if (ipAddressString.charAt(0) == '[') {
-            ipAddressString = ipAddressString.substring(1, ipAddressString.length() - 1);
-        }
-
-        StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ":.", true);
-        ArrayList<String> hexStrings = new ArrayList<String>();
-        ArrayList<String> decStrings = new ArrayList<String>();
-        String token = "";
-        String prevToken = "";
-        // If a double colon exists, we need to insert 0s.
-        int doubleColonIndex = -1;
-
-        /*
-         * Go through the tokens, including the separators ':' and '.' When we
-         * hit a : or . the previous token will be added to either the hex list
-         * or decimal list. In the case where we hit a :: we will save the index
-         * of the hexStrings so we can add zeros in to fill out the string
-         */
-		while (tokenizer.hasMoreTokens()) {
-			prevToken = token;
-			token = tokenizer.nextToken();
-
-			if (token.equals(":")) {
-				if (prevToken.equals(":")) {
-					doubleColonIndex = hexStrings.size();
-				} else if (!prevToken.equals("")) {
-					hexStrings.add(prevToken);
-				}
-			} else if (token.equals(".")) {
-				decStrings.add(prevToken);
-			}
-		}
-
-		if (prevToken.equals(":")) {
-			if (token.equals(":")) {
-				doubleColonIndex = hexStrings.size();
-			} else {
-				hexStrings.add(token);
-			}
-		} else if (prevToken.equals(".")) {
-			decStrings.add(token);
-		}
-
-		// figure out how many hexStrings we should have
-		// also check if it is a IPv4 address
-		int hexStringsLength = 8;
-
-		// If we have an IPv4 address tagged on at the end, subtract
-		// 4 bytes, or 2 hex words from the total
-		if (decStrings.size() > 0) {
-			hexStringsLength -= 2;
-		}
-
-		// if we hit a double Colon add the appropriate hex strings
-		if (doubleColonIndex != -1) {
-			int numberToInsert = hexStringsLength - hexStrings.size();
-			for (int i = 0; i < numberToInsert; i++) {
-				hexStrings.add(doubleColonIndex, "0");
-			}
-		}
-
-		byte ipByteArray[] = new byte[16];
-
-		// Finally convert these strings to bytes...
-		for (int i = 0; i < hexStrings.size(); i++) {
-			convertToBytes(hexStrings.get(i), ipByteArray, i * 2);
-		}
-
-		// Now if there are any decimal values, we know where they go...
-		for (int i = 0; i < decStrings.size(); i++) {
-            ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings.get(i)) & 255);
-        }
-
-		// now check to see if this guy is actually and IPv4 address
-		// an ipV4 address is ::FFFF:d.d.d.d
-		boolean ipV4 = true;
-		for (int i = 0; i < 10; i++) {
-			if (ipByteArray[i] != 0) {
-				ipV4 = false;
-				break;
-			}
-		}
-
-		if (ipByteArray[10] != -1 || ipByteArray[11] != -1) {
-			ipV4 = false;
-		}
-
-		if (ipV4) {
-			byte ipv4ByteArray[] = new byte[4];
-			for (int i = 0; i < 4; i++) {
-				ipv4ByteArray[i] = ipByteArray[i + 12];
-			}
-			return ipv4ByteArray;
-		}
-
-		return ipByteArray;
-
-	}
-
-	/** Converts a 4 character hex word into a 2 byte word equivalent */
-	public static void convertToBytes(String hexWord, byte ipByteArray[],
-			int byteIndex) {
-
-		int hexWordLength = hexWord.length();
-		int hexWordIndex = 0;
-		ipByteArray[byteIndex] = 0;
-		ipByteArray[byteIndex + 1] = 0;
-		int charValue;
-
-		// high order 4 bits of first byte
-		if (hexWordLength > 3) {
-			charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-			ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | (charValue << 4));
-		}
-
-		// low order 4 bits of the first byte
-		if (hexWordLength > 2) {
-			charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-			ipByteArray[byteIndex] = (byte) (ipByteArray[byteIndex] | charValue);
-		}
-
-		// high order 4 bits of second byte
-		if (hexWordLength > 1) {
-			charValue = getIntValue(hexWord.charAt(hexWordIndex++));
-			ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | (charValue << 4));
-		}
-
-		// low order 4 bits of the first byte
-		charValue = getIntValue(hexWord.charAt(hexWordIndex));
-		ipByteArray[byteIndex + 1] = (byte) (ipByteArray[byteIndex + 1] | charValue & 15);
-	}
-
-	static int getIntValue(char c) {
-
-		switch (c) {
-		case '0':
-			return 0;
-		case '1':
-			return 1;
-		case '2':
-			return 2;
-		case '3':
-			return 3;
-		case '4':
-			return 4;
-		case '5':
-			return 5;
-		case '6':
-			return 6;
-		case '7':
-			return 7;
-		case '8':
-			return 8;
-		case '9':
-			return 9;
-		}
-
-		c = Character.toLowerCase(c);
-		switch (c) {
-		case 'a':
-			return 10;
-		case 'b':
-			return 11;
-		case 'c':
-			return 12;
-		case 'd':
-			return 13;
-		case 'e':
-			return 14;
-		case 'f':
-			return 15;
-		}
-		return 0;
-	}
-
-	private static boolean isIPv4MappedAddress(byte ipAddress[]) {
-
-		// Check if the address matches ::FFFF:d.d.d.d
-		// The first 10 bytes are 0. The next to are -1 (FF).
-		// The last 4 bytes are varied.
-		for (int i = 0; i < 10; i++) {
-			if (ipAddress[i] != 0) {
-				return false;
-			}
-		}
-
-		if (ipAddress[10] != -1 || ipAddress[11] != -1) {
-			return false;
-		}
-
-		return true;
-
-	}
-
-	/**
-	 * Takes the byte array and creates an integer out of four bytes starting at
-	 * start as the high-order byte. This method makes no checks on the validity
-	 * of the parameters.
-	 */
-	public static int bytesToInt(byte bytes[], int start) {
-		// First mask the byte with 255, as when a negative
-		// signed byte converts to an integer, it has bits
-		// on in the first 3 bytes, we are only concerned
-		// about the right-most 8 bits.
-		// Then shift the rightmost byte to align with its
-		// position in the integer.
-		int value = ((bytes[start + 3] & 255))
-				| ((bytes[start + 2] & 255) << 8)
-				| ((bytes[start + 1] & 255) << 16)
-				| ((bytes[start] & 255) << 24);
-		return value;
-	}
-
-	public static String addressToString(int value) {
-		return ((value >> 24) & 0xff) + "." + ((value >> 16) & 0xff) + "."
-				+ ((value >> 8) & 0xff) + "." + (value & 0xff);
-	}
 
     public static boolean isIP6AddressInFullForm(String ipAddress) {
         if (isValidIP6Address(ipAddress)) {
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 6d258e0..dd96498 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
+// BEGIN android-changed
+//
+// This file has been substantially reworked in order to provide more IPv6
+// support and to move functionality from Java to native code where it made
+// sense (e.g. when converting between IP addresses, socket structures, and
+// strings, for which there exist fast and robust native implementations).
+
 #define LOG_TAG "OSNetworkSystem"
 
 #include "JNIHelp.h"
@@ -26,6 +33,7 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
+#include <arpa/inet.h>
 #include <sys/time.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
@@ -215,28 +223,6 @@
 }
 
 /**
- * Converts a 4-byte array to a native address structure. Throws a
- * NullPointerException or an IOException in case of error. This is
- * signaled by a return value of -1. The normal return value is 0.
- */
-static int javaAddressToStructIn(
-        JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
-    if (java_address == NULL) {
-        return -1;
-    }
-
-    if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
-        return -1;
-    }
-
-    memset(address, 0, sizeof(address));
-
-    jbyte* dst = reinterpret_cast<jbyte*>(&(address->s_addr));
-    env->GetByteArrayRegion(java_address, 0, sizeof(address->s_addr), dst);
-    return 0;
-}
-
-/**
  * Converts a native address structure to a Java byte array. Throws a
  * NullPointerException or an IOException in case of error. This is
  * signaled by a return value of -1. The normal return value is 0.
@@ -246,7 +232,7 @@
  * @exception SocketException the address family is unknown, or out of memory
  *
  */
-static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
+static jbyteArray socketAddressToByteArray(JNIEnv *env,
         struct sockaddr_storage *address) {
 
     void *rawAddress;
@@ -293,6 +279,34 @@
 }
 
 /**
+ * Checks whether a socket address structure contains an IPv4-mapped address.
+ *
+ * @param address the socket address structure to check
+ * @return true if address contains an IPv4-mapped address, false otherwise.
+ */
+static bool isMappedAddress(sockaddr *address) {
+    if (! address || address->sa_family != AF_INET6) {
+        return false;
+    }
+    in6_addr addr = ((sockaddr_in6 *) address)->sin6_addr;
+    return (addr.s6_addr32[0] == 0 &&
+            addr.s6_addr32[1] == 0 &&
+            addr.s6_addr32[2] == htonl(0xffff));
+}
+
+/**
+ * Checks whether a 16-byte array represents an IPv4-mapped IPv6 address.
+ *
+ * @param addressBytes the address to check. Must be 16 bytes long.
+ * @return true if address contains an IPv4-mapped address, false otherwise.
+ */
+static bool isJavaMappedAddress(jbyte *addressBytes) {
+    static const unsigned char mappedBytes[] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
+    return !memcmp(mappedBytes, addressBytes, sizeof(mappedBytes));
+}
+
+/**
  * Converts a native address structure to an InetAddress object.
  * Throws a NullPointerException or an IOException in case of
  * error.
@@ -304,7 +318,7 @@
 static jobject socketAddressToInetAddress(JNIEnv *env,
         struct sockaddr_storage *sockaddress) {
 
-    jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
+    jbyteArray byteArray = socketAddressToByteArray(env, sockaddress);
     if (byteArray == NULL)  // Exception has already been thrown.
         return NULL;
 
@@ -313,6 +327,39 @@
 }
 
 /**
+ * Converts an IPv4-mapped IPv6 address to an IPv4 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4-mapped address.
+ * @param outputAddress the converted address. Will contain an IPv4 address.
+ */
+static void convertMappedToIpv4(sockaddr_in6 *sin6, sockaddr_in *sin) {
+  memset(sin, 0, sizeof(*sin));
+  sin->sin_family = AF_INET;
+  sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
+  sin->sin_port = sin6->sin6_port;
+}
+
+/**
+ * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4 address.
+ * @param outputAddress the converted address. Will contain an IPv6 address.
+ * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ */
+static void convertIpv4ToMapped(struct sockaddr_in *sin,
+        struct sockaddr_in6 *sin6, bool mapUnspecified) {
+  memset(sin6, 0, sizeof(*sin6));
+  sin6->sin6_family = AF_INET6;
+  sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
+  if (sin->sin_addr.s_addr != 0  || mapUnspecified) {
+      sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+  }
+  sin6->sin6_port = sin->sin_port;
+}
+
+/**
  * Converts an InetAddress object and port number to a native address structure.
  * Throws a NullPointerException or a SocketException in case of
  * error. This is signaled by a return value of -1. The normal
@@ -332,8 +379,9 @@
         throwNullPointerException(env);
         return EFAULT;
     }
-    // Convert the IP address bytes to the proper IP address type.
     size_t addressLength = env->GetArrayLength(addressBytes);
+
+    // Convert the IP address bytes to the proper IP address type.
     if (addressLength == 4) {
         // IPv4 address.
         sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
@@ -473,6 +521,84 @@
 }
 
 /**
+ * Convert a Java string representing an IP address to a Java byte array.
+ * The formats accepted are:
+ * - IPv4:
+ *   - 1.2.3.4
+ *   - 1.2.4
+ *   - 1.4
+ *   - 4
+ * - IPv6
+ *   - Compressed form (2001:db8::1)
+ *   - Uncompressed form (2001:db8:0:0:0:0:0:1)
+ *   - IPv4-compatible (::192.0.2.0)
+ *   - With an embedded IPv4 address (2001:db8::192.0.2.0).
+ * IPv6 addresses may appear in square brackets.
+ *
+ * @param addressByteArray the byte array to convert.
+ *
+ * @return a string with the textual representation of the address.
+ *
+ * @throws UnknownHostException the IP address was invalid.
+ */
+static jbyteArray osNetworkSystem_ipStringToByteArray(JNIEnv *env, jclass clazz,
+        jstring javaString) {
+    if (javaString == NULL) {
+        throwNullPointerException(env);
+    }
+
+    char ipString[INET6_ADDRSTRLEN];
+    int stringLength = env->GetStringUTFLength(javaString);
+    env->GetStringUTFRegion(javaString, 0, stringLength, ipString);
+
+    // Accept IPv6 addresses (only) in square brackets for compatibility.
+    if (ipString[0] == '[' && ipString[stringLength - 1] == ']' &&
+            index(ipString, ':') != NULL) {
+        memmove(ipString, ipString + 1, stringLength - 2);
+        ipString[stringLength - 2] = '\0';
+    }
+
+    jbyteArray result = NULL;
+    sockaddr_in sin;
+    addrinfo hints, *res;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_NUMERICHOST;
+    int ret = getaddrinfo(ipString, NULL, &hints, &res);
+    if (ret == 0 && res) {
+        // Convert mapped addresses to IPv4 addresses if necessary.
+        if (res->ai_family == AF_INET6 && isMappedAddress(res->ai_addr)) {
+            convertMappedToIpv4((sockaddr_in6 *) res->ai_addr, &sin);
+            result = socketAddressToByteArray(env, (sockaddr_storage *) &sin);
+        } else {
+            result = socketAddressToByteArray(env,
+                    (sockaddr_storage *) res->ai_addr);
+        }
+    } else {
+        // For backwards compatibility, deal with address formats that
+        // getaddrinfo does not support. For example, 1.2.3, 1.3, and even 3 are
+        // valid IPv4 addresses according to the Java API. If getaddrinfo fails,
+        // try to use inet_aton.
+        if (inet_aton(ipString, &sin.sin_addr)) {
+            sin.sin_port = 0;
+            sin.sin_family = AF_INET;
+            result = socketAddressToByteArray(env, (sockaddr_storage *) &sin);
+        }
+    }
+
+    if (res) {
+        freeaddrinfo(res);
+    }
+
+    if (! result) {
+        env->ExceptionClear();
+        jniThrowException(env, "java/net/UnknownHostException",
+                gai_strerror(ret));
+    }
+
+    return result;
+}
+
+/**
  * Answer a new java.lang.Boolean object.
  *
  * @param env   pointer to the JNI library
@@ -924,41 +1050,50 @@
 }
 
 /**
- * Converts an IPv4-mapped IPv6 address to an IPv4 address. Performs no error
- * checking.
+ * A helper method, to set the connect context to a Long object.
  *
- * @param address the address to convert. Must contain an IPv4-mapped address.
- * @param outputAddress the converted address. Will contain an IPv4 address.
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
  */
-static void convertMappedToIpv4(sockaddr_storage *address,
-        sockaddr_storage *outputAddress) {
-  memset(outputAddress, 0, sizeof(sockaddr_in));
-  const sockaddr_in6 *sin6 = ((sockaddr_in6 *) address);
-  sockaddr_in *sin = ((sockaddr_in *) outputAddress);
-  sin->sin_family = AF_INET;
-  sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
-  sin->sin_port = sin6->sin6_port;
-}
+void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
+};
 
 /**
- * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
- * checking.
+ * A helper method, to get the connect context.
  *
- * @param address the address to convert. Must contain an IPv4 address.
- * @param outputAddress the converted address. Will contain an IPv6 address.
- * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
  */
-static void convertIpv4ToMapped(struct sockaddr_storage *address,
-        struct sockaddr_storage *outputAddress, bool mapUnspecified) {
-  memset(outputAddress, 0, sizeof(struct sockaddr_in6));
-  const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
-  struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
-  sin6->sin6_family = AF_INET6;
-  sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
-  if (sin->sin_addr.s_addr != 0  || mapUnspecified) {
-      sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
-  }
-  sin6->sin6_port = sin->sin_port;
+jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
+};
+
+// typical ip checksum
+unsigned short ip_checksum(unsigned short* buffer, int size) {
+    register unsigned short * buf = buffer;
+    register int bufleft = size;
+    register unsigned long sum = 0;
+
+    while (bufleft > 1) {
+        sum = sum + (*buf++);
+        bufleft = bufleft - sizeof(unsigned short );
+    }
+    if (bufleft) {
+        sum = sum + (*(unsigned char*)buf);
+    }
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+
+    return (unsigned short )(~sum);
 }
 
 /**
@@ -969,11 +1104,12 @@
  * @param socketAddress the address to connect to
  */
 static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
-    struct sockaddr_storage mappedAddress;
-    struct sockaddr_storage *realAddress;
+    sockaddr_storage mappedAddress;
+    sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        convertIpv4ToMapped(socketAddress, &mappedAddress, true);
+        convertIpv4ToMapped((sockaddr_in *) socketAddress,
+                (sockaddr_in6 *) &mappedAddress, true);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -998,7 +1134,8 @@
     struct sockaddr_storage *realAddress;
     if (socketAddress->ss_family == AF_INET &&
         getSocketAddressFamily(socket) == AF_INET6) {
-        convertIpv4ToMapped(socketAddress, &mappedAddress, false);
+        convertIpv4ToMapped((sockaddr_in *) socketAddress,
+                (sockaddr_in6 *) &mappedAddress, false);
         realAddress = &mappedAddress;
     } else {
         realAddress = socketAddress;
@@ -1256,7 +1393,6 @@
         return -1;
 }
 
-
 /**
  * Join/Leave the nominated multicast group on the specified socket.
  * Implemented by setting the multicast 'add membership'/'drop membership'
@@ -1514,7 +1650,6 @@
     return sock;
 }
 
-
 static void osNetworkSystem_createStreamSocketImpl(JNIEnv* env, jclass clazz,
         jobject fileDescriptor, jboolean preferIPv4Stack) {
     // LOGD("ENTER createSocketImpl");
@@ -2272,7 +2407,7 @@
     }
 
     if (packet != NULL) {
-        jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
+        jbyteArray addr = socketAddressToByteArray(env, &sockAddr);
         if (addr == NULL)  // Exception has already been thrown.
             return 0;
         int port = getSocketAddressPort(&sockAddr);
@@ -3589,6 +3724,7 @@
     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
     { "inheritedChannelImpl",              "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannelImpl               },
     { "byteArrayToIpString",               "([B)Ljava/lang/String;",                                                   (void*) osNetworkSystem_byteArrayToIpString                },
+    { "ipStringToByteArray",               "(Ljava/lang/String;)[B",                                                   (void*) osNetworkSystem_ipStringToByteArray                },
 };
 
 int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
@@ -3597,3 +3733,4 @@
             gMethods,
             NELEM(gMethods));
 }
+// END android-changed
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
index 920f137..163db31 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet4AddressTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.harmony.luni.tests.java.net;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass; 
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
@@ -484,12 +483,6 @@
         method = "equals",
         args = {java.lang.Object.class}
     )
-    @KnownFailure("127.0.0 is not recognized as a valid IP address. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_equals() throws Exception {
         InetAddress addr = Inet4Address.getByName("239.191.255.255");
         assertTrue(addr.equals(addr));
@@ -508,7 +501,6 @@
         method = "getHostAddress",
         args = {}
     )
-    @KnownFailure("1, 1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_getHostAddress() throws Exception {
         InetAddress addr = Inet4Address.getByName("localhost");
         assertEquals("127.0.0.1", addr.getHostAddress());
@@ -535,7 +527,6 @@
         method = "hashCode",
         args = {}
     )
-    @KnownFailure("1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_hashCode() throws Exception {
         InetAddress addr1 = Inet4Address.getByName("1.1");
         InetAddress addr2 = Inet4Address.getByName("1.1.1");
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
index 62952d9..98ae45e 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/Inet6AddressTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.harmony.luni.tests.java.net;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass; 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetNew;
@@ -1153,12 +1152,6 @@
         method = "equals",
         args = {java.lang.Object.class}
     )
-    @KnownFailure("127.0.0 is not recognized as a valid IP address. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_equals() throws Exception {
         InetAddress addr = Inet6Address.getByName("239.191.255.255");
         assertTrue(addr.equals(addr));
@@ -1177,7 +1170,6 @@
         method = "getHostAddress",
         args = {}
     )
-    @KnownFailure("1, 1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_getHostAddress() throws Exception {
         InetAddress aAddr = Inet6Address.getByName("localhost");
         assertEquals("127.0.0.1", aAddr.getHostAddress());
@@ -1201,7 +1193,9 @@
                 0x25, (byte) 0xFF, (byte) 0xFE, (byte) 0xF8, (byte) 0x7C,
                 (byte) 0xB2 };
         aAddr = Inet6Address.getByAddress(bAddr);
-        assertEquals("fe80:0:0:0:211:25ff:fef8:7cb2", aAddr.getHostAddress());
+        String aString = aAddr.getHostAddress();
+        assertTrue(aString.equals("fe80:0:0:0:211:25ff:fef8:7cb2") ||
+                   aString.equals("fe80::211:25ff:fef8:7cb2"));
 
         byte[] cAddr = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
                 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
@@ -1215,7 +1209,9 @@
                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
         aAddr = Inet6Address.getByAddress(dAddr);
-        assertEquals("0:0:0:0:0:0:0:0", aAddr.getHostAddress());
+        aString = aAddr.getHostAddress();
+        assertTrue(aString.equals("0:0:0:0:0:0:0:0") ||
+                   aString.equals("::"));
 
         byte[] eAddr = { (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
                 (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
@@ -1238,7 +1234,6 @@
         method = "hashCode",
         args = {}
     )
-    @KnownFailure("1.1 and 1.1.1 are not recognized as valid IP addresses.")
     public void test_hashCode() throws Exception {
         InetAddress addr1 = Inet6Address.getByName("1.1");
         InetAddress addr2 = Inet6Address.getByName("1.1.1");
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
index 6087a46..5635ecb 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
@@ -18,7 +18,6 @@
 package org.apache.harmony.luni.tests.java.net;
 
 import dalvik.annotation.BrokenTest;
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
@@ -255,12 +254,6 @@
         method = "getByName",
         args = {java.lang.String.class}
     )
-    @KnownFailure("1.2.3 and 1.2 are not recognized as valid IPv4 addresses. " +
-            "Unfortunately, despite the fact that these IP address formats " +
-            "have been the cause of numerous phishing and security " +
-            "vulnerabilities in the past, and most other languages refuse " +
-            "them, the RI documentation explicitly specifies that they are " +
-            "supported. Fix the code to support these.")
     public void test_getByNameLjava_lang_String() throws Exception {
         // Test for method java.net.InetAddress
         // java.net.InetAddress.getByName(java.lang.String)
diff --git a/tests/081-hot-exceptions/expected.txt b/tests/081-hot-exceptions/expected.txt
new file mode 100644
index 0000000..2432ff4
--- /dev/null
+++ b/tests/081-hot-exceptions/expected.txt
@@ -0,0 +1,2 @@
+sum = 0
+exception = 1024
diff --git a/tests/081-hot-exceptions/info.txt b/tests/081-hot-exceptions/info.txt
new file mode 100644
index 0000000..cc514f3
--- /dev/null
+++ b/tests/081-hot-exceptions/info.txt
@@ -0,0 +1,3 @@
+Make a hot exception-throwing path to stress test how the trace builder handles
+exceptions encountered during trace selection. The existence of exceptions will
+cause a control flow change to deviate from the current method.
diff --git a/tests/081-hot-exceptions/src/Main.java b/tests/081-hot-exceptions/src/Main.java
new file mode 100644
index 0000000..90e7af2
--- /dev/null
+++ b/tests/081-hot-exceptions/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+    static class ArrayObj {
+        int[] array;
+
+        int getArrayElement(int i) throws NullPointerException {
+            return array[i];
+        }
+    }
+
+    public static void main(String[] args) {
+        ArrayObj arrayObj2 = new ArrayObj();
+        int sum = 0;
+        int exception = 0;
+
+        for (int i = 0; i < 1024; i++) {
+            try {
+                // A hot method invocation that always encounters exceptions
+                sum += arrayObj2.getArrayElement(i);
+            } catch (NullPointerException npe) {
+                exception++;
+            }
+        }
+        System.out.println("sum = " + sum);
+        System.out.println("exception = " + exception);
+    }
+}
diff --git a/vm/Jni.c b/vm/Jni.c
index 10afcaa..d7d1122 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -3102,7 +3102,7 @@
     JNI_ENTER();
 
     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
-    jint retval;
+    jint retval = JNI_OK;
     int i;
 
     if (gDvm.verboseJni) {
@@ -3115,12 +3115,9 @@
                 methods[i].signature, methods[i].fnPtr))
         {
             retval = JNI_ERR;
-            goto bail;
         }
     }
-    retval = JNI_OK;
 
-bail:
     JNI_EXIT();
     return retval;
 }
@@ -4218,4 +4215,3 @@
     free(argv);
     return result;
 }
-
diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c
index 30a7b1b..2e735fa 100644
--- a/vm/compiler/codegen/arm/Codegen.c
+++ b/vm/compiler/codegen/arm/Codegen.c
@@ -2316,11 +2316,11 @@
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
             assert(classPtr != NULL);
             assert(classPtr->status & CLASS_INITIALIZED);
-            if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
-                /* It's going to throw, just let the interp. deal with it. */
-                genInterpSingleStep(cUnit, mir);
-                return false;
-            }
+            /*
+             * If it is going to throw, it should not make to the trace to begin
+             * with.
+             */
+            assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
             loadConstant(cUnit, r4PC, (int)dvmAllocObject);
             loadConstant(cUnit, r0, (int) classPtr);
             genExportPC(cUnit, mir, r2, r3 );
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 928ca09..28994b7 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -161,10 +161,11 @@
 
     int currTraceRun;
     int totalTraceLen;        // Number of Dalvik insts in trace
-    const u2* currTraceHead;        // Start of the trace we're building
-    const u2* currRunHead;          // Start of run we're building
+    const u2* currTraceHead;  // Start of the trace we're building
+    const u2* currRunHead;    // Start of run we're building
     int currRunLen;           // Length of run in 16-bit words
     int lastThreshFilter;
+    const u2* lastPC;         // Stage the PC first for the threaded interpreter
 #if defined(WITH_SELF_VERIFICATION)
     struct HeapArgSpace heapArgSpace;
 #endif
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index f1ac1c2..aca5fff 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -515,25 +515,38 @@
 #endif
             );
 
+    /* First instruction - just remember the PC and exit */
+    if (interpState->lastPC == NULL) {
+        interpState->lastPC = pc;
+        return switchInterp;
+    }
+
+    /* Prepare to handle last PC and stage the current PC */
+    const u2 *lastPC = interpState->lastPC;
+    interpState->lastPC = pc;
+
     switch (interpState->jitState) {
         char* nopStr;
         int target;
         int offset;
         DecodedInstruction decInsn;
         case kJitTSelect:
-            dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
+            /* Grow the trace around the last PC if jitState is kJitTSelect */
+            dexDecodeInstruction(gDvm.instrFormat, lastPC, &decInsn);
 #if defined(SHOW_TRACE)
             LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
 #endif
             flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
-            len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
-            offset = pc - interpState->method->insns;
-            if (pc != interpState->currRunHead + interpState->currRunLen) {
+            len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, lastPC);
+            offset = lastPC - interpState->method->insns;
+            assert((unsigned) offset <
+                   dvmGetMethodInsnsSize(interpState->method));
+            if (lastPC != interpState->currRunHead + interpState->currRunLen) {
                 int currTraceRun;
                 /* We need to start a new trace run */
                 currTraceRun = ++interpState->currTraceRun;
                 interpState->currRunLen = 0;
-                interpState->currRunHead = (u2*)pc;
+                interpState->currRunHead = (u2*)lastPC;
                 interpState->trace[currTraceRun].frag.startOffset = offset;
                 interpState->trace[currTraceRun].frag.numInsts = 0;
                 interpState->trace[currTraceRun].frag.runEnd = false;
@@ -542,6 +555,12 @@
             interpState->trace[interpState->currTraceRun].frag.numInsts++;
             interpState->totalTraceLen++;
             interpState->currRunLen += len;
+
+            /* Will probably never hit this with the current trace buildier */
+            if (interpState->currTraceRun == (MAX_JIT_RUN_LEN - 1)) {
+                interpState->jitState = kJitTSelectEnd;
+            }
+
             if (  ((flags & kInstrUnconditional) == 0) &&
                   /* don't end trace on INVOKE_DIRECT_EMPTY  */
                   (decInsn.opCode != OP_INVOKE_DIRECT_EMPTY) &&
@@ -880,6 +899,7 @@
                  interpState->trace[0].frag.numInsts = 0;
                  interpState->trace[0].frag.runEnd = false;
                  interpState->trace[0].frag.hint = kJitHintNone;
+                 interpState->lastPC = 0;
                  break;
             case kJitTSelect:
             case kJitTSelectAbort:
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index f20c0f1..c34d6c4 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -576,6 +576,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 4b0a17d..81e7165 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3609,6 +3609,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index a336a95..45a18da 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -3909,6 +3909,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 7e03400..3576608 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -3623,6 +3623,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index f8792bd..6492daf 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1764,6 +1764,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/native/java_lang_Runtime.c b/vm/native/java_lang_Runtime.c
index 1278f03..b5c0aee 100644
--- a/vm/native/java_lang_Runtime.c
+++ b/vm/native/java_lang_Runtime.c
@@ -53,6 +53,9 @@
         LOGW("JNI exit hook returned\n");
     }
     LOGD("Calling exit(%d)\n", status);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+    dvmCompilerDumpStats();
+#endif
     exit(status);
 }
 
@@ -161,4 +164,3 @@
         Dalvik_java_lang_Runtime_totalMemory },
     { NULL, NULL, NULL },
 };
-