Merge "Add tests to demonstrate libcore.io.Base64 behavior"
diff --git a/Docs.mk b/Docs.mk
index 0c52bf5..a163d1f 100644
--- a/Docs.mk
+++ b/Docs.mk
@@ -20,20 +20,11 @@
    libart/src/main/java/dalvik \
    libart/src/main/java/java \
    luni/src/main/java/android \
+   luni/src/main/java/java \
    luni/src/main/java/javax \
    luni/src/main/java/org/xml/sax \
    luni/src/main/java/org/w3c \
    xml/src/main/java/org/xmlpull/v1)
 
-# IcuIteratorWrapper.java references com.ibm.icu.text.BreakIterator,
-# which is renamed by our jarjar rule, and so unrecognizable by javadoc,
-# with annoying error: error: package com.ibm.icu.text does not exist.
-# We don't want to generate doc for this file anyway.
-libcore_to_document += \
-  $(filter-out luni/src/main/java/java/text/IcuIteratorWrapper.java,\
-    $(call find-files-in-subdirs, libcore, \
-      "*.java", \
-      luni/src/main/java/java))
-
 libcore_docs_include_once := 1
 endif # libcore_docs_include_once
diff --git a/benchmarks/src/benchmarks/regression/AnnotatedElementBenchmark.java b/benchmarks/src/benchmarks/regression/AnnotatedElementBenchmark.java
index 6c33968..107767b 100644
--- a/benchmarks/src/benchmarks/regression/AnnotatedElementBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/AnnotatedElementBenchmark.java
@@ -141,7 +141,68 @@
 
     public void timeGetDeclaredAnnotationsOnSubclass(int reps) {
         for (int i = 0; i < reps; i++) {
-            ExtendsHasThreeAnnotations.class.getAnnotations();
+            ExtendsHasThreeAnnotations.class.getDeclaredAnnotations();
+        }
+    }
+
+
+    // get annotations with enclosing / inner classes
+
+    public void timeGetDeclaredClasses(int reps) {
+        for (int i = 0; i < reps; i++) {
+            AnnotatedElementBenchmark.class.getDeclaredClasses();
+        }
+    }
+
+    public void timeGetDeclaringClass(int reps) {
+        for (int i = 0; i < reps; i++) {
+            HasSmallAnnotation.class.getDeclaringClass();
+        }
+    }
+
+    public void timeGetEnclosingClass(int reps) {
+        Object anonymousClass = new Object() {};
+        for (int i = 0; i < reps; i++) {
+            anonymousClass.getClass().getEnclosingClass();
+        }
+    }
+
+    public void timeGetEnclosingConstructor(int reps) {
+        Object anonymousClass = new Object() {};
+        for (int i = 0; i < reps; i++) {
+            anonymousClass.getClass().getEnclosingConstructor();
+        }
+    }
+
+    public void timeGetEnclosingMethod(int reps) {
+        Object anonymousClass = new Object() {};
+        for (int i = 0; i < reps; i++) {
+            anonymousClass.getClass().getEnclosingMethod();
+        }
+    }
+
+    public void timeGetModifiers(int reps) {
+        for (int i = 0; i < reps; i++) {
+            HasSmallAnnotation.class.getModifiers();
+        }
+    }
+
+    public void timeGetSimpleName(int reps) {
+        for (int i = 0; i < reps; i++) {
+            HasSmallAnnotation.class.getSimpleName();
+        }
+    }
+
+    public void timeIsAnonymousClass(int reps) {
+        Object anonymousClass = new Object() {};
+        for (int i = 0; i < reps; i++) {
+            anonymousClass.getClass().isAnonymousClass();
+        }
+    }
+
+    public void timeIsLocalClass(int reps) {
+        for (int i = 0; i < reps; i++) {
+            HasSmallAnnotation.class.isLocalClass();
         }
     }
 
@@ -174,7 +235,7 @@
     @Marker
     public class HasThreeAnnotations {}
 
-    public class ExtendsHasThreeAnnotations {}
+    public class ExtendsHasThreeAnnotations extends HasThreeAnnotations {}
 
 
     // the annotations
diff --git a/benchmarks/src/benchmarks/regression/BidiBenchmark.java b/benchmarks/src/benchmarks/regression/BidiBenchmark.java
new file mode 100644
index 0000000..bb5087e
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/BidiBenchmark.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.SimpleBenchmark;
+
+import java.math.BigDecimal;
+import java.text.AttributedCharacterIterator;
+import java.text.Bidi;
+import java.text.DecimalFormat;
+
+public class BidiBenchmark extends SimpleBenchmark {
+
+    private static final AttributedCharacterIterator charIter =
+            DecimalFormat.getInstance().formatToCharacterIterator(new BigDecimal(Math.PI));
+
+    public void time_createBidiFromIter(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi bidi = new Bidi(charIter);
+        }
+    }
+
+    public void time_createBidiFromCharArray(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi bd = new Bidi(new char[]{'s', 's', 's'}, 0, new byte[]{(byte) 1,
+                    (byte) 2, (byte) 3}, 0, 3, Bidi.DIRECTION_RIGHT_TO_LEFT);
+        }
+    }
+
+    public void time_createBidiFromString(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi bidi = new Bidi("Hello", Bidi.DIRECTION_LEFT_TO_RIGHT);
+        }
+    }
+
+    public void time_reorderVisually(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi.reorderVisually(new byte[]{2, 1, 3, 0, 4}, 0,
+                    new String[]{"H", "e", "l", "l", "o"}, 0, 5);
+        }
+    }
+
+    public void time_hebrewBidi(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi bd = new Bidi(new char[]{'\u05D0', '\u05D0', '\u05D0'}, 0,
+                    new byte[]{(byte) -1, (byte) -2, (byte) -3}, 0, 3,
+                    Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+            bd = new Bidi(new char[]{'\u05D0', '\u05D0', '\u05D0'}, 0,
+                    new byte[]{(byte) -1, (byte) -2, (byte) -3}, 0, 3,
+                    Bidi.DIRECTION_LEFT_TO_RIGHT);
+        }
+    }
+
+    public void time_complicatedOverrideBidi(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi bd = new Bidi("a\u05D0a\"a\u05D0\"\u05D0a".toCharArray(), 0,
+                    new byte[]{0, 0, 0, -3, -3, 2, 2, 0, 3}, 0, 9,
+                    Bidi.DIRECTION_RIGHT_TO_LEFT);
+        }
+    }
+
+    public void time_requiresBidi(int reps) {
+        for (int i = 0; i < reps; i++) {
+            Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1);  // false.
+            Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1);  // true.
+        }
+    }
+
+}
diff --git a/benchmarks/src/benchmarks/regression/IdnBenchmark.java b/benchmarks/src/benchmarks/regression/IdnBenchmark.java
new file mode 100644
index 0000000..9de5261
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/IdnBenchmark.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * 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.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.SimpleBenchmark;
+
+import java.net.IDN;
+
+public class IdnBenchmark extends SimpleBenchmark {
+
+    public void timeToUnicode(int reps) {
+        for (int i = 0; i < reps; i++) {
+            IDN.toASCII("fass.de");
+            IDN.toASCII("faß.de");
+            IDN.toASCII("fäß.de");
+            IDN.toASCII("a\u200Cb");
+            IDN.toASCII("öbb.at");
+            IDN.toASCII("abc・日本.co.jp");
+            IDN.toASCII("日本.co.jp");
+            IDN.toASCII("x\u0327\u0301.de");
+            IDN.toASCII("σόλοσ.gr");
+        }
+    }
+
+    public void timeToAscii(int reps) {
+        for (int i = 0; i < reps; i++) {
+            IDN.toUnicode("xn--fss-qla.de");
+            IDN.toUnicode("xn--n00d.com");
+            IDN.toUnicode("xn--bb-eka.at");
+            IDN.toUnicode("xn--og-09a.de");
+            IDN.toUnicode("xn--53h.de");
+            IDN.toUnicode("xn--iny-zx5a.de");
+            IDN.toUnicode("xn--abc-rs4b422ycvb.co.jp");
+            IDN.toUnicode("xn--wgv71a.co.jp");
+            IDN.toUnicode("xn--x-xbb7i.de");
+            IDN.toUnicode("xn--wxaikc6b.gr");
+            IDN.toUnicode("xn--wxaikc6b.xn--gr-gtd9a1b0g.de");
+        }
+    }
+
+}
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index 0d37cd6..0dc4bc4 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -37,6 +37,7 @@
 import java.io.InputStream;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
@@ -53,7 +54,9 @@
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import libcore.reflect.AnnotationAccess;
 import libcore.reflect.GenericSignatureParser;
@@ -202,6 +205,9 @@
     /** Virtual methods defined in this class; invoked through vtable. */
     private transient long virtualMethods;
 
+    /** Class flags to help the GC with object scanning. */
+    private transient int classFlags;
+
     /**
      * Total size of the Class instance; used when allocating storage on GC heap.
      * See also {@link Class#objectSize}.
@@ -351,7 +357,25 @@
     }
 
     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
-        return AnnotationAccess.getAnnotation(this, annotationType);
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+
+        A annotation = getDeclaredAnnotation(annotationType);
+        if (annotation != null) {
+            return annotation;
+        }
+
+        if (annotationType.isDeclaredAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                annotation = sup.getDeclaredAnnotation(annotationType);
+                if (annotation != null) {
+                    return annotation;
+                }
+            }
+        }
+
+        return null;
     }
 
     /**
@@ -361,7 +385,33 @@
      * @see #getDeclaredAnnotations()
      */
     @Override public Annotation[] getAnnotations() {
-        return AnnotationAccess.getAnnotations(this);
+        /*
+         * We need to get the annotations declared on this class, plus the
+         * annotations from superclasses that have the "@Inherited" annotation
+         * set.  We create a temporary map to use while we accumulate the
+         * annotations and convert it to an array at the end.
+         *
+         * It's possible to have duplicates when annotations are inherited.
+         * We use a Map to filter those out.
+         *
+         * HashMap might be overkill here.
+         */
+        HashMap<Class<?>, Annotation> map = new HashMap<Class<?>, Annotation>();
+        for (Annotation declaredAnnotation : getDeclaredAnnotations()) {
+            map.put(declaredAnnotation.annotationType(), declaredAnnotation);
+        }
+        for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+            for (Annotation declaredAnnotation : sup.getDeclaredAnnotations()) {
+                Class<? extends Annotation> clazz = declaredAnnotation.annotationType();
+                if (!map.containsKey(clazz) && clazz.isDeclaredAnnotationPresent(Inherited.class)) {
+                    map.put(clazz, declaredAnnotation);
+                }
+            }
+        }
+
+        /* Convert annotation values from HashMap to array. */
+        Collection<Annotation> coll = map.values();
+        return coll.toArray(new Annotation[coll.size()]);
     }
 
     /**
@@ -734,10 +784,17 @@
      *
      * @see #getAnnotations()
      */
-    @Override public Annotation[] getDeclaredAnnotations() {
-        List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
-        return result.toArray(new Annotation[result.size()]);
-    }
+    @Override public native Annotation[] getDeclaredAnnotations();
+
+    /**
+     * Returns the annotation if it exists.
+     */
+    private native <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass);
+
+    /**
+     * Returns true if the annotation exists.
+     */
+    private native boolean isDeclaredAnnotationPresent(Class<? extends Annotation> annotationClass);
 
     /**
      * Returns an array containing {@code Class} objects for all classes,
@@ -793,7 +850,7 @@
      * method or constructor.
      */
     public Class<?> getDeclaringClass() {
-        if (AnnotationAccess.isAnonymousClass(this)) {
+        if (isAnonymousClass()) {
             return null;
         }
         return AnnotationAccess.getEnclosingClass(this);
@@ -1220,7 +1277,23 @@
     }
 
     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
-        return AnnotationAccess.isAnnotationPresent(this, annotationType);
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+
+        if (isDeclaredAnnotationPresent(annotationType)) {
+            return true;
+        }
+
+        if (annotationType.isDeclaredAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                if (sup.isDeclaredAnnotationPresent(annotationType)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
     }
 
     /**
diff --git a/libart/src/main/java/java/lang/ClassLoader.java b/libart/src/main/java/java/lang/ClassLoader.java
index dfbeeb5..860e4a1 100644
--- a/libart/src/main/java/java/lang/ClassLoader.java
+++ b/libart/src/main/java/java/lang/ClassLoader.java
@@ -92,6 +92,11 @@
     private Map<String, Package> packages = new HashMap<String, Package>();
 
     /**
+     * Pointer to the class table, only used from within the runtime.
+     */
+    private transient long classTable;
+
+    /**
      * To avoid unloading individual classes, {@link java.lang.reflect.Proxy}
      * only generates one class for each set of interfaces. This maps sets of
      * interfaces to the proxy class that implements all of them. It is declared
diff --git a/libart/src/main/java/java/lang/reflect/Constructor.java b/libart/src/main/java/java/lang/reflect/Constructor.java
index 9711ef4..0dadd8d 100644
--- a/libart/src/main/java/java/lang/reflect/Constructor.java
+++ b/libart/src/main/java/java/lang/reflect/Constructor.java
@@ -36,7 +36,6 @@
 import java.lang.annotation.Annotation;
 import java.util.Comparator;
 import java.util.List;
-import libcore.reflect.AnnotationAccess;
 import libcore.reflect.Types;
 
 /**
@@ -97,10 +96,7 @@
      * this constructor has no declared exceptions, an empty array will be
      * returned.
      */
-    public Class<?>[] getExceptionTypes() {
-        // TODO: use dex cache to speed looking up class
-        return AnnotationAccess.getExceptions(this);
-    }
+    public native Class<?>[] getExceptionTypes();
 
     /**
      * Returns an array of the {@code Class} objects associated with the
@@ -181,24 +177,23 @@
         return super.getGenericExceptionTypes();
     }
 
-    @Override public Annotation[] getDeclaredAnnotations() {
-        List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
-        return result.toArray(new Annotation[result.size()]);
-    }
+    @Override public native Annotation[] getDeclaredAnnotations();
 
     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
+        return isAnnotationPresentNative(annotationType);
     }
+    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
 
     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.getDeclaredAnnotation(this, annotationType);
+        return getAnnotationNative(annotationType);
     }
+    private native <A extends Annotation> A getAnnotationNative(Class<A> annotationType);
 
     /**
      * Returns an array of arrays that represent the annotations of the formal
@@ -209,9 +204,13 @@
      * @return an array of arrays of {@code Annotation} instances
      */
     public Annotation[][] getParameterAnnotations() {
-        return AnnotationAccess.getParameterAnnotations(
-            declaringClassOfOverriddenMethod, dexMethodIndex);
+        Annotation[][] parameterAnnotations = getParameterAnnotationsNative();
+        if (parameterAnnotations == null) {
+          parameterAnnotations = new Annotation[getParameterTypes().length][0];
+        }
+        return parameterAnnotations;
     }
+    private native Annotation[][] getParameterAnnotationsNative();
 
     /**
      * Returns the constructor's signature in non-printable form. This is called
diff --git a/libart/src/main/java/java/lang/reflect/Field.java b/libart/src/main/java/java/lang/reflect/Field.java
index 37f2ad0..06cc0b2 100644
--- a/libart/src/main/java/java/lang/reflect/Field.java
+++ b/libart/src/main/java/java/lang/reflect/Field.java
@@ -36,7 +36,6 @@
 import java.lang.annotation.Annotation;
 import java.util.Comparator;
 import java.util.List;
-import libcore.reflect.AnnotationAccess;
 import libcore.reflect.GenericSignatureParser;
 import libcore.reflect.Types;
 
@@ -218,7 +217,7 @@
      *             instantiated for some reason
      */
     public Type getGenericType() {
-        String signatureAttribute = AnnotationAccess.getSignature(this);
+        String signatureAttribute = getSignatureAttribute();
         Class<?> declaringClass = getDeclaringClass();
         ClassLoader cl = declaringClass.getClassLoader();
         GenericSignatureParser parser = new GenericSignatureParser(cl);
@@ -230,6 +229,19 @@
         return genericType;
     }
 
+    private String getSignatureAttribute() {
+        String[] annotation = getSignatureAnnotation();
+        if (annotation == null) {
+            return null;
+        }
+        StringBuilder result = new StringBuilder();
+        for (String s : annotation) {
+          result.append(s);
+        }
+        return result.toString();
+    }
+    private native String[] getSignatureAnnotation();
+
     /**
      * Returns the constructor's signature in non-printable form. This is called
      * (only) from IO native code and needed for deriving the serialVersionUID
@@ -240,24 +252,23 @@
         return Types.getSignature(getType());
     }
 
-    @Override public Annotation[] getDeclaredAnnotations() {
-        List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
-        return result.toArray(new Annotation[result.size()]);
-    }
+    @Override public native Annotation[] getDeclaredAnnotations();
 
     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.getDeclaredAnnotation(this, annotationType);
+        return getAnnotationNative(annotationType);
     }
+    private native <A extends Annotation> A getAnnotationNative(Class<A> annotationType);
 
     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
+        return isAnnotationPresentNative(annotationType);
     }
+    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
 
     /**
      * Returns the value of the field in the specified object. This reproduces
diff --git a/libart/src/main/java/java/lang/reflect/Method.java b/libart/src/main/java/java/lang/reflect/Method.java
index a07ec6f..79287ba 100644
--- a/libart/src/main/java/java/lang/reflect/Method.java
+++ b/libart/src/main/java/java/lang/reflect/Method.java
@@ -36,7 +36,6 @@
 import java.lang.annotation.Annotation;
 import java.util.Comparator;
 import java.util.List;
-import libcore.reflect.AnnotationAccess;
 import libcore.reflect.Types;
 
 /**
@@ -148,16 +147,7 @@
      *
      * @return the declared exception classes
      */
-    public Class<?>[] getExceptionTypes() {
-        if (getDeclaringClass().isProxy()) {
-            return getExceptionTypesNative();
-        } else {
-            // TODO: use dex cache to speed looking up class
-            return AnnotationAccess.getExceptions(this);
-        }
-    }
-
-    private native Class<?>[] getExceptionTypesNative();
+    public native Class<?>[] getExceptionTypes();
 
     /**
      * Returns an array of {@code Class} objects associated with the parameter
@@ -250,8 +240,9 @@
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
+        return isAnnotationPresentNative(annotationType);
     }
+    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
 
     /**
      * Returns the exception types as an array of {@code Type} instances. If
@@ -288,17 +279,15 @@
         return Types.getType(getMethodOrConstructorGenericInfo().genericReturnType);
     }
 
-    @Override public Annotation[] getDeclaredAnnotations() {
-        List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
-        return result.toArray(new Annotation[result.size()]);
-    }
+    @Override public native Annotation[] getDeclaredAnnotations();
 
     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
         if (annotationType == null) {
             throw new NullPointerException("annotationType == null");
         }
-        return AnnotationAccess.getDeclaredAnnotation(this, annotationType);
+        return getAnnotationNative(annotationType);
     }
+    private native <A extends Annotation> A getAnnotationNative(Class<A> annotationType);
 
     /**
      * Returns an array of arrays that represent the annotations of the formal
@@ -309,9 +298,13 @@
      * @return an array of arrays of {@code Annotation} instances
      */
     public Annotation[][] getParameterAnnotations() {
-        return AnnotationAccess.getParameterAnnotations(
-            declaringClassOfOverriddenMethod, dexMethodIndex);
+        Annotation[][] parameterAnnotations = getParameterAnnotationsNative();
+        if (parameterAnnotations == null) {
+          parameterAnnotations = new Annotation[getParameterTypes().length][0];
+        }
+        return parameterAnnotations;
     }
+    private native Annotation[][] getParameterAnnotationsNative();
 
     /**
      * Returns the default value for the annotation member represented by this
@@ -323,9 +316,7 @@
      *             if this annotation member is of type {@code Class} and no
      *             definition can be found
      */
-    public Object getDefaultValue() {
-        return AnnotationAccess.getDefaultValue(this);
-    }
+    public native Object getDefaultValue();
 
     /**
      * Returns the result of dynamically invoking this method. Equivalent to
diff --git a/luni/src/main/java/java/lang/reflect/Array.java b/luni/src/main/java/java/lang/reflect/Array.java
index a7dacfe..72e6717 100644
--- a/luni/src/main/java/java/lang/reflect/Array.java
+++ b/luni/src/main/java/java/lang/reflect/Array.java
@@ -371,7 +371,7 @@
         } else if (componentType == void.class) {
             throw new IllegalArgumentException("Can't allocate an array of void");
         }
-        throw new AssertionError();
+        throw new AssertionError(componentType.toString());
     }
 
     /*
diff --git a/luni/src/main/java/java/net/IDN.java b/luni/src/main/java/java/net/IDN.java
index 4e60209..dd256c2 100644
--- a/luni/src/main/java/java/net/IDN.java
+++ b/luni/src/main/java/java/net/IDN.java
@@ -16,7 +16,7 @@
 
 package java.net;
 
-import libcore.icu.NativeIDN;
+import com.ibm.icu.text.IDNA;
 
 /**
  * Converts internationalized domain names between Unicode and the ASCII Compatible Encoding
@@ -61,7 +61,11 @@
      * @throws IllegalArgumentException if {@code input} does not conform to <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>
      */
     public static String toASCII(String input, int flags) {
-        return NativeIDN.toASCII(input, flags);
+        try {
+            return IDNA.convertIDNToASCII(input, flags).toString();
+        } catch (com.ibm.icu.text.StringPrepParseException e) {
+            throw new IllegalArgumentException("Invalid input to toASCII: " + input, e);
+        }
     }
 
     /**
@@ -91,7 +95,28 @@
      *         or {@code ALLOW_UNASSIGNED | USE_STD3_ASCII_RULES}
      */
     public static String toUnicode(String input, int flags) {
-        return NativeIDN.toUnicode(input, flags);
+        try {
+            // ICU only translates separators to ASCII for toASCII.
+            // Java expects the translation for toUnicode too.
+            return convertFullStop(IDNA.convertIDNToUnicode(input, flags)).toString();
+        } catch (com.ibm.icu.text.StringPrepParseException e) {
+            // The RI documentation explicitly states that if the conversion was unsuccessful
+            // the original string is returned.
+            return input;
+        }
+    }
+
+    private static boolean isLabelSeperator(char c) {
+        return (c == '\u3002' || c == '\uff0e' || c == '\uff61');
+    }
+
+    private static StringBuffer convertFullStop(StringBuffer input) {
+        for (int i = 0; i < input.length(); i++) {
+            if (isLabelSeperator(input.charAt(i))) {
+                input.setCharAt(i, '.');
+            }
+        }
+        return input;
     }
 
     /**
@@ -101,6 +126,6 @@
      * @return the Unicode name
      */
     public static String toUnicode(String input) {
-        return NativeIDN.toUnicode(input, 0);
+        return toUnicode(input, 0);
     }
 }
diff --git a/luni/src/main/java/java/text/Bidi.java b/luni/src/main/java/java/text/Bidi.java
index d73ea4a..65861a7 100644
--- a/luni/src/main/java/java/text/Bidi.java
+++ b/luni/src/main/java/java/text/Bidi.java
@@ -17,11 +17,6 @@
 
 package java.text;
 
-import java.awt.font.NumericShaper;
-import java.awt.font.TextAttribute;
-import java.util.ArrayList;
-import java.util.Arrays;
-
 /**
  * Implements the <a href="http://unicode.org/reports/tr9/">Unicode Bidirectional Algorithm</a>.
  *
@@ -58,33 +53,28 @@
      */
     public static final int DIRECTION_RIGHT_TO_LEFT = 1;
 
-    /**
-     * TODO: if we care about performance, we might just want to use an int[] instead of a Run[].
-     */
-    static class Run {
-        private final int start;
-        private final int limit;
-        private final int level;
-
-        public Run(int start, int limit, int level) {
-            this.start = start;
-            this.limit = limit;
-            this.level = level;
-        }
-
-        public int getLevel() {
-            return level;
-        }
-
-        public int getLimit() {
-            return limit;
-        }
-
-        public int getStart() {
-            return start;
+    private static int translateConstToIcu(int javaInt) {
+        switch (javaInt) {
+            case DIRECTION_DEFAULT_LEFT_TO_RIGHT:
+                return com.ibm.icu.text.Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+            case DIRECTION_DEFAULT_RIGHT_TO_LEFT:
+                return com.ibm.icu.text.Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT;
+            case DIRECTION_LEFT_TO_RIGHT:
+                return com.ibm.icu.text.Bidi.DIRECTION_LEFT_TO_RIGHT;
+            case DIRECTION_RIGHT_TO_LEFT:
+                return com.ibm.icu.text.Bidi.DIRECTION_RIGHT_TO_LEFT;
+            // If the parameter was unrecognized use LEFT_TO_RIGHT.
+            default:
+                return com.ibm.icu.text.Bidi.DIRECTION_LEFT_TO_RIGHT;
         }
     }
 
+    private boolean isUnidirectional() {
+        return icuBidi.getRunCount() == 0;
+    }
+
+    private final com.ibm.icu.text.Bidi icuBidi;
+
     /**
      * Creates a {@code Bidi} object from the {@code
      * AttributedCharacterIterator} of a paragraph text. The RUN_DIRECTION
@@ -114,65 +104,7 @@
             throw new IllegalArgumentException("paragraph is null");
         }
 
-        int begin = paragraph.getBeginIndex();
-        int end = paragraph.getEndIndex();
-        int length = end - begin;
-        char[] text = new char[length + 1]; // One more char for AttributedCharacterIterator.DONE
-
-        if (length != 0) {
-            text[0] = paragraph.first();
-        } else {
-            paragraph.first();
-        }
-
-        // First check the RUN_DIRECTION attribute.
-        int flags = DIRECTION_DEFAULT_LEFT_TO_RIGHT;
-        Object direction = paragraph.getAttribute(TextAttribute.RUN_DIRECTION);
-        if (direction != null && direction instanceof Boolean) {
-            if (direction.equals(TextAttribute.RUN_DIRECTION_LTR)) {
-                flags = DIRECTION_LEFT_TO_RIGHT;
-            } else {
-                flags = DIRECTION_RIGHT_TO_LEFT;
-            }
-        }
-
-        // Retrieve the text and gather BIDI_EMBEDDINGS
-        byte[] embeddings = null;
-        for (int textLimit = 1, i = 1; i < length; textLimit = paragraph
-                .getRunLimit(TextAttribute.BIDI_EMBEDDING)
-                - begin + 1) {
-            Object embedding = paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING);
-            if (embedding != null && embedding instanceof Integer) {
-                int embLevel = ((Integer) embedding).intValue();
-
-                if (embeddings == null) {
-                    embeddings = new byte[length];
-                }
-
-                for (; i < textLimit; i++) {
-                    text[i] = paragraph.next();
-                    embeddings[i - 1] = (byte) embLevel;
-                }
-            } else {
-                for (; i < textLimit; i++) {
-                    text[i] = paragraph.next();
-                }
-            }
-        }
-
-        // Apply NumericShaper to the text
-        Object numericShaper = paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING);
-        if (numericShaper != null && numericShaper instanceof NumericShaper) {
-            ((NumericShaper) numericShaper).shape(text, 0, length);
-        }
-
-        long bidi = 0;
-        try {
-            bidi = createUBiDi(text, 0, embeddings, 0, length, flags);
-            readBidiInfo(bidi);
-        } finally {
-            ubidi_close(bidi);
-        }
+        this.icuBidi = new com.ibm.icu.text.Bidi(paragraph);
     }
 
     /**
@@ -214,13 +146,11 @@
         if (text == null || text.length - textStart < paragraphLength) {
             throw new IllegalArgumentException();
         }
-
         if (embeddings != null) {
             if (embeddings.length - embStart < paragraphLength) {
                 throw new IllegalArgumentException();
             }
         }
-
         if (textStart < 0) {
             throw new IllegalArgumentException("Negative textStart value " + textStart);
         }
@@ -231,13 +161,9 @@
             throw new IllegalArgumentException("Negative paragraph length " + paragraphLength);
         }
 
-        long bidi = 0;
-        try {
-            bidi = createUBiDi(text, textStart, embeddings, embStart, paragraphLength, flags);
-            readBidiInfo(bidi);
-        } finally {
-            ubidi_close(bidi);
-        }
+        this.icuBidi = new com.ibm.icu.text.Bidi(text, textStart, embeddings, embStart,
+                paragraphLength, translateConstToIcu(flags));
+
     }
 
     /**
@@ -261,109 +187,18 @@
                 (paragraph == null ? 0 : paragraph.length()), flags);
     }
 
-    // create the native UBiDi struct, need to be closed with ubidi_close().
-    private static long createUBiDi(char[] text, int textStart,
-            byte[] embeddings, int embStart, int paragraphLength, int flags) {
-        char[] realText = null;
 
-        byte[] realEmbeddings = null;
-
-        if (text == null || text.length - textStart < paragraphLength) {
-            throw new IllegalArgumentException();
-        }
-        realText = new char[paragraphLength];
-        System.arraycopy(text, textStart, realText, 0, paragraphLength);
-
-        if (embeddings != null) {
-            if (embeddings.length - embStart < paragraphLength) {
-                throw new IllegalArgumentException();
-            }
-            if (paragraphLength > 0) {
-                Bidi temp = new Bidi(text, textStart, null, 0, paragraphLength, flags);
-                realEmbeddings = new byte[paragraphLength];
-                System.arraycopy(temp.offsetLevel, 0, realEmbeddings, 0, paragraphLength);
-                for (int i = 0; i < paragraphLength; i++) {
-                    byte e = embeddings[i];
-                    if (e < 0) {
-                        realEmbeddings[i] = (byte) (UBIDI_LEVEL_OVERRIDE - e);
-                    } else if (e > 0) {
-                        realEmbeddings[i] = e;
-                    } else {
-                        realEmbeddings[i] |= (byte) UBIDI_LEVEL_OVERRIDE;
-                    }
-                }
-            }
-        }
-
-        if (flags > 1 || flags < -2) {
-            flags = 0;
-        }
-
-        long bidi = 0;
-        boolean needsDeletion = true;
-        try {
-            bidi = ubidi_open();
-            ubidi_setPara(bidi, realText, paragraphLength, flags, realEmbeddings);
-            needsDeletion = false;
-        } finally {
-            if (needsDeletion) {
-                ubidi_close(bidi);
-            }
-        }
-        return bidi;
+    private Bidi(com.ibm.icu.text.Bidi icuBidi) {
+        this.icuBidi = icuBidi;
     }
 
-    /* private constructor used by createLineBidi() */
-    private Bidi(long pBidi) {
-        readBidiInfo(pBidi);
-    }
-
-    // read info from the native UBiDi struct
-    private void readBidiInfo(long pBidi) {
-        length = ubidi_getLength(pBidi);
-
-        offsetLevel = (length == 0) ? null : ubidi_getLevels(pBidi);
-
-        baseLevel = ubidi_getParaLevel(pBidi);
-
-        int runCount = ubidi_countRuns(pBidi);
-        if (runCount == 0) {
-            unidirectional = true;
-            runs = null;
-        } else if (runCount < 0) {
-            runs = null;
-        } else {
-            runs = ubidi_getRuns(pBidi);
-
-            // Simplified case for one run which has the base level
-            if (runCount == 1 && runs[0].getLevel() == baseLevel) {
-                unidirectional = true;
-                runs = null;
-            }
-        }
-
-        direction = ubidi_getDirection(pBidi);
-    }
-
-    private int baseLevel;
-
-    private int length;
-
-    private byte[] offsetLevel;
-
-    private Run[] runs;
-
-    private int direction;
-
-    private boolean unidirectional;
-
     /**
      * Returns whether the base level is from left to right.
      *
      * @return true if the base level is from left to right.
      */
     public boolean baseIsLeftToRight() {
-        return baseLevel % 2 == 0 ? true : false;
+        return icuBidi.baseIsLeftToRight();
     }
 
     /**
@@ -382,55 +217,36 @@
      *             than the length of this object's paragraph text.
      */
     public Bidi createLineBidi(int lineStart, int lineLimit) {
-        if (lineStart < 0 || lineLimit < 0 || lineLimit > length || lineStart > lineLimit) {
+        if (lineStart < 0 || lineLimit < 0 || lineLimit > getLength() || lineStart > lineLimit) {
             throw new IllegalArgumentException("Invalid ranges (start=" + lineStart + ", " +
-                    "limit=" + lineLimit + ", length=" + length + ")");
+                    "limit=" + lineLimit + ", length=" + getLength() + ")");
         }
 
-        char[] text = new char[this.length];
-        Arrays.fill(text, 'a');
-        byte[] embeddings = new byte[this.length];
-        for (int i = 0; i < embeddings.length; i++) {
-            embeddings[i] = (byte) -this.offsetLevel[i];
+        // In the special case where the start and end positions are the same, we return a new bidi
+        // instance which is empty. Note that the default constructor for an empty ICU4J bidi
+        // instance is not the same as passing in empty values. This way allows one to call
+        // .getLength() for example and return a correct value instead of an IllegalStateException
+        // being thrown, which happens in the case of using the empty constructor.
+        if (lineStart == lineLimit) {
+            return new Bidi(new com.ibm.icu.text.Bidi(new char[] {}, 0, new byte[] {}, 0, 0,
+                    translateConstToIcu(DIRECTION_LEFT_TO_RIGHT)));
         }
 
-        int dir = this.baseIsLeftToRight()
-                ? Bidi.DIRECTION_LEFT_TO_RIGHT
-                : Bidi.DIRECTION_RIGHT_TO_LEFT;
-        long parent = 0;
-        try {
-            parent = createUBiDi(text, 0, embeddings, 0, this.length, dir);
-            if (lineStart == lineLimit) {
-                return createEmptyLineBidi(parent);
-            }
-            return new Bidi(ubidi_setLine(parent, lineStart, lineLimit));
-        } finally {
-            ubidi_close(parent);
-        }
-    }
-
-    private Bidi createEmptyLineBidi(long parent) {
-        // ICU4C doesn't allow this case, but the RI does.
-        Bidi result = new Bidi(parent);
-        result.length = 0;
-        result.offsetLevel = null;
-        result.runs = null;
-        result.unidirectional = true;
-        return result;
+        return new Bidi(icuBidi.createLineBidi(lineStart, lineLimit));
     }
 
     /**
      * Returns the base level.
      */
     public int getBaseLevel() {
-        return baseLevel;
+        return icuBidi.getBaseLevel();
     }
 
     /**
      * Returns the length of the text.
      */
     public int getLength() {
-        return length;
+        return icuBidi.getLength();
     }
 
     /**
@@ -438,9 +254,9 @@
      */
     public int getLevelAt(int offset) {
         try {
-            return offsetLevel[offset] & ~UBIDI_LEVEL_OVERRIDE;
-        } catch (RuntimeException e) {
-            return baseLevel;
+            return icuBidi.getLevelAt(offset);
+        } catch (IllegalArgumentException e) {
+            return getBaseLevel();
         }
     }
 
@@ -448,28 +264,43 @@
      * Returns the number of runs in the text, at least 1.
      */
     public int getRunCount() {
-        return unidirectional ? 1 : runs.length;
+        return isUnidirectional() ? 1 : icuBidi.getRunCount();
     }
 
     /**
      * Returns the level of the given run.
      */
     public int getRunLevel(int run) {
-        return unidirectional ? baseLevel : runs[run].getLevel();
+        // Paper over a the ICU4J behaviour of strictly enforcing run must be strictly less than
+        // the number of runs. Done to maintain compatibility with previous C implementation.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        return isUnidirectional() ? icuBidi.getBaseLevel() : icuBidi.getRunLevel(run);
     }
 
     /**
      * Returns the limit offset of the given run.
      */
     public int getRunLimit(int run) {
-        return unidirectional ? length : runs[run].getLimit();
+        // Paper over a the ICU4J behaviour of strictly enforcing run must be strictly less than
+        // the number of runs. Done to maintain compatibility with previous C implementation.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        return isUnidirectional() ? icuBidi.getLength() : icuBidi.getRunLimit(run);
     }
 
     /**
      * Returns the start offset of the given run.
      */
     public int getRunStart(int run) {
-        return unidirectional ? 0 : runs[run].getStart();
+        // Paper over a the ICU4J behaviour of strictly enforcing run must be strictly less than
+        // the number of runs. Done to maintain compatibility with previous C implementation.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        return isUnidirectional() ? 0 : icuBidi.getRunStart(run);
     }
 
     /**
@@ -477,14 +308,14 @@
      * direction and the text direction is from left to right.
      */
     public boolean isLeftToRight() {
-        return direction == UBiDiDirection_UBIDI_LTR;
+        return icuBidi.isLeftToRight();
     }
 
     /**
      * Returns true if the text direction is mixed.
      */
     public boolean isMixed() {
-        return direction == UBiDiDirection_UBIDI_MIXED;
+        return icuBidi.isMixed();
     }
 
     /**
@@ -492,7 +323,7 @@
      * direction and the text direction is from right to left.
      */
     public boolean isRightToLeft() {
-        return direction == UBiDiDirection_UBIDI_RTL;
+        return icuBidi.isRightToLeft();
     }
 
     /**
@@ -519,6 +350,7 @@
      */
     public static void reorderVisually(byte[] levels, int levelStart,
             Object[] objects, int objectStart, int count) {
+
         if (count < 0 || levelStart < 0 || objectStart < 0
                 || count > levels.length - levelStart
                 || count > objects.length - objectStart) {
@@ -527,17 +359,7 @@
                     ", objectStart=" + objectStart + ", count=" + count + ")");
         }
 
-        byte[] realLevels = new byte[count];
-        System.arraycopy(levels, levelStart, realLevels, 0, count);
-
-        int[] indices = ubidi_reorderVisual(realLevels, count);
-
-        ArrayList<Object> result = new ArrayList<Object>(count);
-        for (int i = 0; i < count; i++) {
-            result.add(objects[objectStart + indices[i]]);
-        }
-
-        System.arraycopy(result.toArray(), 0, objects, objectStart, count);
+        com.ibm.icu.text.Bidi.reorderVisually(levels, levelStart, objects, objectStart, count);
     }
 
     /**
@@ -562,33 +384,13 @@
             throw new IllegalArgumentException();
         }
 
-        Bidi bidi = new Bidi(text, start, null, 0, limit - start, 0);
-        return !bidi.isLeftToRight();
+        return com.ibm.icu.text.Bidi.requiresBidi(text, start, limit);
     }
 
     @Override
     public String toString() {
         return getClass().getName()
-                + "[direction: " + direction + " baseLevel: " + baseLevel
-                + " length: " + length + " runs: " + Arrays.toString(runs) + "]";
+                + "[direction: " + icuBidi.getDirection() + " baseLevel: " + icuBidi.getBaseLevel()
+                + " length: " + icuBidi.getLength() + " runs: " + icuBidi.getRunCount() + "]";
     }
-
-    // ICU4C constants.
-    private static final int UBIDI_LEVEL_OVERRIDE = 0x80;
-    private static final int UBiDiDirection_UBIDI_LTR = 0;
-    private static final int UBiDiDirection_UBIDI_RTL = 1;
-    private static final int UBiDiDirection_UBIDI_MIXED = 2;
-
-    // ICU4C functions.
-    private static native long ubidi_open();
-    private static native void ubidi_close(long pBiDi);
-    private static native void ubidi_setPara(long pBiDi, char[] text, int length, int paraLevel, byte[] embeddingLevels);
-    private static native long ubidi_setLine(final long pParaBiDi, int start, int limit);
-    private static native int ubidi_getDirection(final long pBiDi);
-    private static native int ubidi_getLength(final long pBiDi);
-    private static native byte ubidi_getParaLevel(final long pBiDi);
-    private static native byte[] ubidi_getLevels(long pBiDi);
-    private static native int ubidi_countRuns(long pBiDi);
-    private static native Bidi.Run[] ubidi_getRuns(long pBidi);
-    private static native int[] ubidi_reorderVisual(byte[] levels, int length);
 }
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index b27ea88..c455119 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -512,8 +512,9 @@
         // Try each of the transforms and keep track of the first exception
         // encountered.
         Exception cause = null;
-        for (Transform transform : transforms) {
-            if (provider != null) {
+
+        if (provider != null) {
+            for (Transform transform : transforms) {
                 Provider.Service service = provider.getService(SERVICE, transform.name);
                 if (service == null) {
                     continue;
@@ -521,22 +522,40 @@
                 return tryTransformWithProvider(initParams, transformParts, transform.needToSet,
                         service);
             }
-            ArrayList<Provider.Service> services = ENGINE.getServices(transform.name);
-            if (services == null || services.isEmpty()) {
-                continue;
-            }
+        } else {
+            ArrayList<Provider.Service> services = ENGINE.getServices();
             for (Provider.Service service : services) {
-                if (initParams == null || initParams.key == null
-                        || service.supportsParameter(initParams.key)) {
-                    try {
-                        Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
-                                transformParts, transform.needToSet, service);
-                        if (sap != null) {
-                            return sap;
+                String serviceAlgorithmUC = service.getAlgorithm().toUpperCase(Locale.US);
+                for (Transform transform : transforms) {
+                    // Check that this service offers the algorithm we're after
+                    // since none of the services have been filtered yet.
+                    boolean matchesAlgorithm = false;
+                    if (transform.name.equals(serviceAlgorithmUC)) {
+                        matchesAlgorithm = true;
+                    } else {
+                        for (String alias : Engine.door.getAliases(service)) {
+                            if (transform.name.equals(alias.toUpperCase(Locale.US))) {
+                                matchesAlgorithm = true;
+                                break;
+                            }
                         }
-                    } catch (Exception e) {
-                        if (cause == null) {
-                            cause = e;
+                    }
+                    if (!matchesAlgorithm) {
+                        continue;
+                    }
+
+                    if (initParams == null || initParams.key == null
+                            || service.supportsParameter(initParams.key)) {
+                        try {
+                            Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
+                                    transformParts, transform.needToSet, service);
+                            if (sap != null) {
+                                return sap;
+                            }
+                        } catch (Exception e) {
+                            if (cause == null) {
+                                cause = e;
+                            }
                         }
                     }
                 }
diff --git a/luni/src/main/java/libcore/icu/AlphabeticIndex.java b/luni/src/main/java/libcore/icu/AlphabeticIndex.java
deleted file mode 100644
index 322384d..0000000
--- a/luni/src/main/java/libcore/icu/AlphabeticIndex.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package libcore.icu;
-
-import java.util.Locale;
-
-/**
- * Exposes icu4c's AlphabeticIndex.
- */
-public final class AlphabeticIndex {
-
-  /**
-   * Exposes icu4c's ImmutableIndex (new to icu 51). This exposes a read-only,
-   * thread safe snapshot view of an AlphabeticIndex at the moment it was
-   * created, and allows for random access to buckets by index.
-   */
-  public static final class ImmutableIndex {
-    private long peer;
-
-    private ImmutableIndex(long peer) {
-      this.peer = peer;
-    }
-
-    @Override protected synchronized void finalize() throws Throwable {
-      try {
-        destroy(peer);
-        peer = 0;
-      } finally {
-        super.finalize();
-      }
-    }
-
-    /**
-     * Returns the number of the label buckets in this index.
-     */
-    public int getBucketCount() {
-      return getBucketCount(peer);
-    }
-
-    /**
-     * Returns the index of the bucket in which 's' should appear.
-     * Function is synchronized because underlying routine walks an iterator
-     * whose state is maintained inside the index object.
-     */
-    public int getBucketIndex(String s) {
-      return getBucketIndex(peer, s);
-    }
-
-    /**
-     * Returns the label for the bucket at the given index (as returned by getBucketIndex).
-     */
-    public String getBucketLabel(int index) {
-      return getBucketLabel(peer, index);
-    }
-
-    private static native int getBucketCount(long peer);
-    private static native int getBucketIndex(long peer, String s);
-    private static native String getBucketLabel(long peer, int index);
-  }
-
-  private long peer;
-
-  /**
-   * Creates a new AlphabeticIndex for the given locale.
-   */
-  public AlphabeticIndex(Locale locale) {
-    peer = create(locale.toString());
-  }
-
-  @Override protected synchronized void finalize() throws Throwable {
-    try {
-      destroy(peer);
-      peer = 0;
-    } finally {
-      super.finalize();
-    }
-  }
-
-  /**
-   * Returns the max number of the label buckets allowed in this index.
-   */
-  public synchronized int getMaxLabelCount() {
-    return getMaxLabelCount(peer);
-  }
-
-  /**
-   * Sets the max number of the label buckets in this index.
-   * (ICU 51 default is 99)
-   */
-  public synchronized AlphabeticIndex setMaxLabelCount(int count) {
-    setMaxLabelCount(peer, count);
-    return this;
-  }
-
-  /**
-   * Adds the index characters from the given locale to the index.
-   * The labels are added to those that are already in the index;
-   * they do not replace the existing index characters.
-   * The collation order for this index is not changed;
-   * it remains that of the locale that was originally specified
-   * when creating this index.
-   */
-  public synchronized AlphabeticIndex addLabels(Locale locale) {
-    addLabels(peer, locale.toString());
-    return this;
-  }
-
-  /**
-   * Adds the index characters in the range between the specified start and
-   * end code points, inclusive.
-   */
-  public synchronized AlphabeticIndex addLabelRange(int codePointStart, int codePointEnd) {
-    addLabelRange(peer, codePointStart, codePointEnd);
-    return this;
-  }
-
-  /**
-   * Returns the number of the label buckets in this index.
-   */
-  public synchronized int getBucketCount() {
-    return getBucketCount(peer);
-  }
-
-  /**
-   * Returns the index of the bucket in which 's' should appear.
-   * Function is synchronized because underlying routine walks an iterator
-   * whose state is maintained inside the index object.
-   */
-  public synchronized int getBucketIndex(String s) {
-    return getBucketIndex(peer, s);
-  }
-
-  /**
-   * Returns the label for the bucket at the given index (as returned by getBucketIndex).
-   */
-  public synchronized String getBucketLabel(int index) {
-    return getBucketLabel(peer, index);
-  }
-
-  /**
-   * Returns an ImmutableIndex created from this AlphabeticIndex.
-   */
-  public synchronized ImmutableIndex getImmutableIndex() {
-    return new ImmutableIndex(buildImmutableIndex(peer));
-  }
-
-  private static native long create(String locale);
-  private static native void destroy(long peer);
-  private static native int getMaxLabelCount(long peer);
-  private static native void setMaxLabelCount(long peer, int count);
-  private static native void addLabels(long peer, String locale);
-  private static native void addLabelRange(long peer, int codePointStart, int codePointEnd);
-  private static native int getBucketCount(long peer);
-  private static native int getBucketIndex(long peer, String s);
-  private static native String getBucketLabel(long peer, int index);
-  private static native long buildImmutableIndex(long peer);
-}
diff --git a/luni/src/main/java/libcore/icu/NativeIDN.java b/luni/src/main/java/libcore/icu/NativeIDN.java
deleted file mode 100644
index db93379..0000000
--- a/luni/src/main/java/libcore/icu/NativeIDN.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package libcore.icu;
-
-public final class NativeIDN {
-    public static String toASCII(String s, int flags) {
-        return convert(s, flags, true);
-    }
-
-    public static String toUnicode(String s, int flags) {
-        try {
-            return convert(s, flags, false);
-        } catch (IllegalArgumentException ex) {
-            // The RI documentation explicitly states that this method can't fail.
-            // ICU4C disagrees, as does the RI in practice.
-            // The RI just returns the input string if it can't
-            return s;
-        }
-    }
-
-    private static String convert(String s, int flags, boolean toAscii) {
-        if (s == null) {
-            throw new NullPointerException("s == null");
-        }
-        return convertImpl(s, flags, toAscii);
-    }
-    private static native String convertImpl(String s, int flags, boolean toAscii);
-
-    private NativeIDN() {}
-}
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index 3413a5d..daa915e 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -22,6 +22,7 @@
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
 import libcore.util.BasicLruCache;
 import libcore.util.ZoneInfoDB;
 
@@ -58,7 +59,7 @@
         }
 
         @Override protected String[][] create(Locale locale) {
-            long start = System.currentTimeMillis();
+            long start = System.nanoTime();
 
             // Set up the 2D array used to hold the names. The first column contains the Olson ids.
             String[][] result = new String[availableTimeZoneIds.length][5];
@@ -66,17 +67,17 @@
                 result[i][0] = availableTimeZoneIds[i];
             }
 
-            long nativeStart = System.currentTimeMillis();
+            long nativeStart = System.nanoTime();
             fillZoneStrings(locale.toString(), result);
-            long nativeEnd = System.currentTimeMillis();
+            long nativeEnd = System.nanoTime();
 
             internStrings(result);
             // Ending up in this method too often is an easy way to make your app slow, so we ensure
             // it's easy to tell from the log (a) what we were doing, (b) how long it took, and
             // (c) that it's all ICU's fault.
-            long end = System.currentTimeMillis();
-            long nativeDuration = nativeEnd - nativeStart;
-            long duration = end - start;
+            long end = System.nanoTime();
+            long nativeDuration = TimeUnit.NANOSECONDS.toMillis(nativeEnd - nativeStart);
+            long duration = TimeUnit.NANOSECONDS.toMillis(end - start);
             System.logI("Loaded time zone names for \"" + locale + "\" in " + duration + "ms" +
                         " (" + nativeDuration + "ms in ICU)");
             return result;
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index fcb30dd..acf9b39 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -42,6 +42,8 @@
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
 import static android.system.OsConstants.*;
 
 /**
@@ -149,7 +151,7 @@
         IoUtils.setBlocking(fd, false);
 
         // 2. call connect(2) non-blocking.
-        long finishTimeMs = System.currentTimeMillis() + timeoutMs;
+        long finishTimeNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
         try {
             Libcore.os.connect(fd, inetAddress, port);
             IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
@@ -164,7 +166,8 @@
         // 3. loop using poll(2).
         int remainingTimeoutMs;
         do {
-            remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
+            remainingTimeoutMs =
+                    (int) TimeUnit.NANOSECONDS.toMillis(finishTimeNanos - System.nanoTime());
             if (remainingTimeoutMs <= 0) {
                 throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
             }
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index 1c794e5..3c929c4 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -152,6 +152,14 @@
     }
 
     /**
+     * Returns a list of all providers for this type of service or {@code null}
+     * if no matches were found.
+     */
+    public ArrayList<Provider.Service> getServices() {
+        return Services.getServices(serviceName);
+    }
+
+    /**
      * Returns a list of all possible matches for a given algorithm. Returns
      * {@code null} if no matches were found.
      */
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index 234f4a2..232b6d2 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -21,7 +21,7 @@
 import java.security.Security;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Locale;
+import java.util.Iterator;
 
 
 /**
@@ -134,12 +134,37 @@
     }
 
     /**
+     * Looks up the requested service by type. The service {@code type} and
+     * should be provided in the same format used when registering a service
+     * with a provider, for example, "KeyFactory". Callers can cache the
+     * returned service information but such caches should be validated against
+     * the result of Service.getCacheVersion() before use. Returns {@code null}
+     * if there are no services of the given {@code type} found.
+     */
+    public static synchronized ArrayList<Provider.Service> getServices(String type) {
+        ArrayList<Provider.Service> services = null;
+        for (Provider p : providers) {
+            Iterator<Provider.Service> i = p.getServices().iterator();
+            while (i.hasNext()) {
+                Provider.Service s = i.next();
+                if (type.equals(s.getType())) {
+                    if (services == null) {
+                        services = new ArrayList<>(providers.size());
+                    }
+                    services.add(s);
+                }
+            }
+        }
+        return services;
+    }
+
+    /**
      * Looks up the requested service by type and algorithm. The service
      * {@code type} and should be provided in the same format used when
-     * registering a service with a provider, for example, "KeyFactory.RSA".
-     * Callers can cache the returned service information but such caches should
-     * be validated against the result of Service.getCacheVersion() before use.
-     * Returns {@code null} if there are no services found.
+     * registering a service with a provider, for example, "KeyFactory" and
+     * "RSA". Callers can cache the returned service information but such caches
+     * should be validated against the result of Service.getCacheVersion()
+     * before use. Returns {@code null} if there are no services found.
      */
     public static synchronized ArrayList<Provider.Service> getServices(String type,
             String algorithm) {
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 0e30da7..c32e675 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -47,7 +47,6 @@
     REGISTER(register_java_lang_StringToReal);
     REGISTER(register_java_lang_System);
     REGISTER(register_java_math_NativeBN);
-    REGISTER(register_java_text_Bidi);
     REGISTER(register_java_util_jar_StrictJarFile);
     REGISTER(register_java_util_regex_Matcher);
     REGISTER(register_java_util_regex_Pattern);
@@ -55,12 +54,10 @@
     REGISTER(register_java_util_zip_CRC32);
     REGISTER(register_java_util_zip_Deflater);
     REGISTER(register_java_util_zip_Inflater);
-    REGISTER(register_libcore_icu_AlphabeticIndex);
     REGISTER(register_libcore_icu_ICU);
     REGISTER(register_libcore_icu_NativeCollation);
     REGISTER(register_libcore_icu_NativeConverter);
     REGISTER(register_libcore_icu_NativeDecimalFormat);
-    REGISTER(register_libcore_icu_NativeIDN);
     REGISTER(register_libcore_icu_TimeZoneNames);
     REGISTER(register_libcore_io_AsynchronousCloseMonitor);
     REGISTER(register_libcore_io_Memory);
diff --git a/luni/src/main/native/java_text_Bidi.cpp b/luni/src/main/native/java_text_Bidi.cpp
deleted file mode 100644
index 6a3e751..0000000
--- a/luni/src/main/native/java_text_Bidi.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-#define LOG_TAG "Bidi"
-
-#include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ScopedPrimitiveArray.h"
-#include "unicode/ubidi.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <memory>
-
-struct BiDiData {
-    BiDiData(UBiDi* biDi) : mBiDi(biDi) {
-    }
-
-    ~BiDiData() {
-        ubidi_close(mBiDi);
-    }
-
-    UBiDiLevel* embeddingLevels() {
-        return reinterpret_cast<UBiDiLevel*>(&mEmbeddingLevels[0]);
-    }
-
-    void setEmbeddingLevels(jbyte* newEmbeddingLevels) {
-        mEmbeddingLevels.reset(newEmbeddingLevels);
-    }
-
-    UBiDi* uBiDi() {
-        return mBiDi;
-    }
-
-private:
-    UBiDi* mBiDi;
-    std::unique_ptr<jbyte[]> mEmbeddingLevels;
-
-    // Disallow copy and assignment.
-    BiDiData(const BiDiData&);
-    void operator=(const BiDiData&);
-};
-
-static BiDiData* biDiData(jlong ptr) {
-    return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr));
-}
-
-static UBiDi* uBiDi(jlong ptr) {
-    return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr))->uBiDi();
-}
-
-static jlong Bidi_ubidi_open(JNIEnv*, jclass) {
-    return reinterpret_cast<uintptr_t>(new BiDiData(ubidi_open()));
-}
-
-static void Bidi_ubidi_close(JNIEnv*, jclass, jlong ptr) {
-    delete biDiData(ptr);
-}
-
-static void Bidi_ubidi_setPara(JNIEnv* env, jclass, jlong ptr, jcharArray text, jint length, jint paraLevel, jbyteArray newEmbeddingLevels) {
-    BiDiData* data = biDiData(ptr);
-    // Copy the new embedding levels from the Java heap to the native heap.
-    if (newEmbeddingLevels != NULL) {
-        jbyte* dst;
-        data->setEmbeddingLevels(dst = new jbyte[length]);
-        env->GetByteArrayRegion(newEmbeddingLevels, 0, length, dst);
-    } else {
-        data->setEmbeddingLevels(NULL);
-    }
-    ScopedCharArrayRO chars(env, text);
-    if (chars.get() == NULL) {
-        return;
-    }
-    UErrorCode err = U_ZERO_ERROR;
-    ubidi_setPara(data->uBiDi(), chars.get(), length, paraLevel, data->embeddingLevels(), &err);
-    maybeThrowIcuException(env, "ubidi_setPara", err);
-}
-
-static jlong Bidi_ubidi_setLine(JNIEnv* env, jclass, jlong ptr, jint start, jint limit) {
-    UErrorCode status = U_ZERO_ERROR;
-    UBiDi* sized = ubidi_openSized(limit - start, 0, &status);
-    if (maybeThrowIcuException(env, "ubidi_openSized", status)) {
-        return 0;
-    }
-    std::unique_ptr<BiDiData> lineData(new BiDiData(sized));
-    ubidi_setLine(uBiDi(ptr), start, limit, lineData->uBiDi(), &status);
-    maybeThrowIcuException(env, "ubidi_setLine", status);
-    return reinterpret_cast<uintptr_t>(lineData.release());
-}
-
-static jint Bidi_ubidi_getDirection(JNIEnv*, jclass, jlong ptr) {
-    return ubidi_getDirection(uBiDi(ptr));
-}
-
-static jint Bidi_ubidi_getLength(JNIEnv*, jclass, jlong ptr) {
-    return ubidi_getLength(uBiDi(ptr));
-}
-
-static jbyte Bidi_ubidi_getParaLevel(JNIEnv*, jclass, jlong ptr) {
-    return ubidi_getParaLevel(uBiDi(ptr));
-}
-
-static jbyteArray Bidi_ubidi_getLevels(JNIEnv* env, jclass, jlong ptr) {
-    UErrorCode status = U_ZERO_ERROR;
-    const UBiDiLevel* levels = ubidi_getLevels(uBiDi(ptr), &status);
-    if (maybeThrowIcuException(env, "ubidi_getLevels", status)) {
-        return NULL;
-    }
-    int len = ubidi_getLength(uBiDi(ptr));
-    jbyteArray result = env->NewByteArray(len);
-    env->SetByteArrayRegion(result, 0, len, reinterpret_cast<const jbyte*>(levels));
-    return result;
-}
-
-static jint Bidi_ubidi_countRuns(JNIEnv* env, jclass, jlong ptr) {
-    UErrorCode status = U_ZERO_ERROR;
-    int count = ubidi_countRuns(uBiDi(ptr), &status);
-    maybeThrowIcuException(env, "ubidi_countRuns", status);
-    return count;
-}
-
-/**
- * TODO: if we care about performance, we might just want to use an int[] instead of a Run[].
- */
-static jobjectArray Bidi_ubidi_getRuns(JNIEnv* env, jclass, jlong ptr) {
-    UBiDi* ubidi = uBiDi(ptr);
-    UErrorCode status = U_ZERO_ERROR;
-    int runCount = ubidi_countRuns(ubidi, &status);
-    if (maybeThrowIcuException(env, "ubidi_countRuns", status)) {
-        return NULL;
-    }
-    static jmethodID bidiRunConstructor =
-            env->GetMethodID(JniConstants::bidiRunClass, "<init>", "(III)V");
-    jobjectArray runs = env->NewObjectArray(runCount, JniConstants::bidiRunClass, NULL);
-    UBiDiLevel level = 0;
-    int start = 0;
-    int limit = 0;
-    for (int i = 0; i < runCount; ++i) {
-        ubidi_getLogicalRun(ubidi, start, &limit, &level);
-        jobject run = env->NewObject(JniConstants::bidiRunClass, bidiRunConstructor, start, limit, level);
-        env->SetObjectArrayElement(runs, i, run);
-        start = limit;
-    }
-    return runs;
-}
-
-static jintArray Bidi_ubidi_reorderVisual(JNIEnv* env, jclass, jbyteArray javaLevels, jint length) {
-    ScopedByteArrayRO levelBytes(env, javaLevels);
-    if (levelBytes.get() == NULL) {
-        return NULL;
-    }
-
-    const UBiDiLevel* levels = reinterpret_cast<const UBiDiLevel*>(levelBytes.get());
-
-    std::unique_ptr<int[]> indexMap(new int[length]);
-    ubidi_reorderVisual(levels, length, &indexMap[0]);
-
-    jintArray result = env->NewIntArray(length);
-    env->SetIntArrayRegion(result, 0, length, &indexMap[0]);
-    return result;
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(Bidi, ubidi_close, "(J)V"),
-    NATIVE_METHOD(Bidi, ubidi_countRuns, "(J)I"),
-    NATIVE_METHOD(Bidi, ubidi_getDirection, "(J)I"),
-    NATIVE_METHOD(Bidi, ubidi_getLength, "(J)I"),
-    NATIVE_METHOD(Bidi, ubidi_getLevels, "(J)[B"),
-    NATIVE_METHOD(Bidi, ubidi_getParaLevel, "(J)B"),
-    NATIVE_METHOD(Bidi, ubidi_getRuns, "(J)[Ljava/text/Bidi$Run;"),
-    NATIVE_METHOD(Bidi, ubidi_open, "()J"),
-    NATIVE_METHOD(Bidi, ubidi_reorderVisual, "([BI)[I"),
-    NATIVE_METHOD(Bidi, ubidi_setLine, "(JII)J"),
-    NATIVE_METHOD(Bidi, ubidi_setPara, "(J[CII[B)V"),
-};
-void register_java_text_Bidi(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/text/Bidi", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
deleted file mode 100644
index acc247b..0000000
--- a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#define LOG_TAG "AlphabeticIndex"
-
-#include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ScopedIcuLocale.h"
-#include "ScopedJavaUnicodeString.h"
-#include "unicode/alphaindex.h"
-#include "unicode/uniset.h"
-
-static icu::AlphabeticIndex* fromPeer(jlong peer) {
-  return reinterpret_cast<icu::AlphabeticIndex*>(static_cast<uintptr_t>(peer));
-}
-
-static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) {
-  UErrorCode status = U_ZERO_ERROR;
-  ScopedIcuLocale icuLocale(env, javaLocaleName);
-  if (!icuLocale.valid()) {
-    return 0;
-  }
-  icu::AlphabeticIndex* ai = new icu::AlphabeticIndex(icuLocale.locale(), status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex", status)) {
-    return 0;
-  }
-  return reinterpret_cast<uintptr_t>(ai);
-}
-
-static void AlphabeticIndex_destroy(JNIEnv*, jclass, jlong peer) {
-  delete fromPeer(peer);
-}
-
-static jint AlphabeticIndex_getMaxLabelCount(JNIEnv*, jclass, jlong peer) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  return ai->getMaxLabelCount();
-}
-
-static void AlphabeticIndex_setMaxLabelCount(JNIEnv* env, jclass, jlong peer, jint count) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  UErrorCode status = U_ZERO_ERROR;
-  ai->setMaxLabelCount(count, status);
-  maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status);
-}
-
-static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  ScopedIcuLocale icuLocale(env, javaLocaleName);
-  if (!icuLocale.valid()) {
-    return;
-  }
-  UErrorCode status = U_ZERO_ERROR;
-  ai->addLabels(icuLocale.locale(), status);
-  maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
-}
-
-static void AlphabeticIndex_addLabelRange(JNIEnv* env, jclass, jlong peer,
-                                          jint codePointStart, jint codePointEnd) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  UErrorCode status = U_ZERO_ERROR;
-  ai->addLabels(icu::UnicodeSet(codePointStart, codePointEnd), status);
-  maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
-}
-
-static jint AlphabeticIndex_getBucketCount(JNIEnv* env, jclass, jlong peer) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  UErrorCode status = U_ZERO_ERROR;
-  jint result = ai->getBucketCount(status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketCount", status)) {
-    return -1;
-  }
-  return result;
-}
-
-static jint AlphabeticIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  ScopedJavaUnicodeString string(env, javaString);
-  if (!string.valid()) {
-    return -1;
-  }
-  UErrorCode status = U_ZERO_ERROR;
-  jint result = ai->getBucketIndex(string.unicodeString(), status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketIndex", status)) {
-    return -1;
-  }
-  return result;
-}
-
-static jstring AlphabeticIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) {
-  if (index < 0) {
-    jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
-    return NULL;
-  }
-
-  // Iterate to the nth bucket.
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  UErrorCode status = U_ZERO_ERROR;
-  ai->resetBucketIterator(status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex::resetBucketIterator", status)) {
-    return NULL;
-  }
-  for (jint i = 0; i <= index; ++i) {
-    if (!ai->nextBucket(status)) {
-      jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
-      return NULL;
-    }
-    if (maybeThrowIcuException(env, "AlphabeticIndex::nextBucket", status)) {
-      return NULL;
-    }
-  }
-
-  // Return "" for the underflow/inflow/overflow buckets.
-  if (ai->getBucketLabelType() != U_ALPHAINDEX_NORMAL) {
-    return env->NewStringUTF("");
-  }
-
-  const icu::UnicodeString& label(ai->getBucketLabel());
-  return env->NewString(label.getBuffer(), label.length());
-}
-
-static jlong AlphabeticIndex_buildImmutableIndex(JNIEnv* env, jclass, jlong peer) {
-  icu::AlphabeticIndex* ai = fromPeer(peer);
-  UErrorCode status = U_ZERO_ERROR;
-  icu::AlphabeticIndex::ImmutableIndex* ii = ai->buildImmutableIndex(status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex::buildImmutableIndex", status)) {
-    return 0;
-  }
-  return reinterpret_cast<uintptr_t>(ii);
-}
-
-static icu::AlphabeticIndex::ImmutableIndex* immutableIndexFromPeer(jlong peer) {
-  return reinterpret_cast<icu::AlphabeticIndex::ImmutableIndex*>(static_cast<uintptr_t>(peer));
-}
-
-static jint ImmutableIndex_getBucketCount(JNIEnv*, jclass, jlong peer) {
-  icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
-  return ii->getBucketCount();
-}
-
-static jint ImmutableIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) {
-  icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
-  ScopedJavaUnicodeString string(env, javaString);
-  if (!string.valid()) {
-    return -1;
-  }
-  UErrorCode status = U_ZERO_ERROR;
-  jint result = ii->getBucketIndex(string.unicodeString(), status);
-  if (maybeThrowIcuException(env, "AlphabeticIndex::ImmutableIndex::getBucketIndex", status)) {
-    return -1;
-  }
-  return result;
-}
-
-static jstring ImmutableIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) {
-  icu::AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer);
-  const icu::AlphabeticIndex::Bucket* bucket = ii->getBucket(index);
-  if (bucket == NULL) {
-    jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index);
-    return NULL;
-  }
-
-  // Return "" for the underflow/inflow/overflow buckets.
-  if (bucket->getLabelType() != U_ALPHAINDEX_NORMAL) {
-    return env->NewStringUTF("");
-  }
-
-  const icu::UnicodeString& label(bucket->getLabel());
-  return env->NewString(label.getBuffer(), label.length());
-}
-
-static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(AlphabeticIndex, create, "(Ljava/lang/String;)J"),
-  NATIVE_METHOD(AlphabeticIndex, destroy, "(J)V"),
-  NATIVE_METHOD(AlphabeticIndex, getMaxLabelCount, "(J)I"),
-  NATIVE_METHOD(AlphabeticIndex, setMaxLabelCount, "(JI)V"),
-  NATIVE_METHOD(AlphabeticIndex, addLabels, "(JLjava/lang/String;)V"),
-  NATIVE_METHOD(AlphabeticIndex, addLabelRange, "(JII)V"),
-  NATIVE_METHOD(AlphabeticIndex, getBucketCount, "(J)I"),
-  NATIVE_METHOD(AlphabeticIndex, getBucketIndex, "(JLjava/lang/String;)I"),
-  NATIVE_METHOD(AlphabeticIndex, getBucketLabel, "(JI)Ljava/lang/String;"),
-  NATIVE_METHOD(AlphabeticIndex, buildImmutableIndex, "(J)J"),
-};
-static JNINativeMethod gImmutableIndexMethods[] = {
-  NATIVE_METHOD(ImmutableIndex, getBucketCount, "(J)I"),
-  NATIVE_METHOD(ImmutableIndex, getBucketIndex, "(JLjava/lang/String;)I"),
-  NATIVE_METHOD(ImmutableIndex, getBucketLabel, "(JI)Ljava/lang/String;"),
-};
-void register_libcore_icu_AlphabeticIndex(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex", gMethods, NELEM(gMethods));
-  jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex$ImmutableIndex", gImmutableIndexMethods, NELEM(gImmutableIndexMethods));
-}
diff --git a/luni/src/main/native/libcore_icu_NativeIDN.cpp b/luni/src/main/native/libcore_icu_NativeIDN.cpp
deleted file mode 100644
index 43f3ce5..0000000
--- a/luni/src/main/native/libcore_icu_NativeIDN.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "NativeIDN"
-
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "ScopedStringChars.h"
-#include "unicode/uidna.h"
-
-static bool isLabelSeparator(const UChar ch) {
-    switch (ch) {
-    case 0x3002: // ideographic full stop
-    case 0xff0e: // fullwidth full stop
-    case 0xff61: // halfwidth ideographic full stop
-        return true;
-    default:
-        return false;
-    }
-}
-
-static jstring NativeIDN_convertImpl(JNIEnv* env, jclass, jstring javaSrc, jint flags, jboolean toAscii) {
-    ScopedStringChars src(env, javaSrc);
-    if (src.get() == NULL) {
-        return NULL;
-    }
-    UChar dst[256];
-    UErrorCode status = U_ZERO_ERROR;
-
-    // We're stuck implementing IDNA-2003 for now since that's what we specify.
-    //
-    // TODO: Change our spec to IDNA-2008 + UTS-46 compatibility processing if
-    // it's safe enough.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-    size_t resultLength = toAscii
-        ? uidna_IDNToASCII(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status)
-        : uidna_IDNToUnicode(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status);
-#pragma GCC diagnostic pop
-
-    if (U_FAILURE(status)) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", u_errorName(status));
-        return NULL;
-    }
-    if (!toAscii) {
-        // ICU only translates separators to ASCII for toASCII.
-        // Java expects the translation for toUnicode too.
-        // We may as well do this here, while the string is still mutable.
-        for (size_t i = 0; i < resultLength; ++i) {
-            if (isLabelSeparator(dst[i])) {
-                dst[i] = '.';
-            }
-        }
-    }
-    return env->NewString(&dst[0], resultLength);
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(NativeIDN, convertImpl, "(Ljava/lang/String;IZ)Ljava/lang/String;"),
-};
-void register_libcore_icu_NativeIDN(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "libcore/icu/NativeIDN", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 783a1bb..bfe2380 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -135,9 +135,9 @@
  */
 #define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
     return_type _rc = -1; \
+    int _syscallErrno; \
     do { \
         bool _wasSignaled; \
-        int _syscallErrno; \
         { \
             int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
             AsynchronousCloseMonitor _monitor(_fd); \
@@ -156,6 +156,10 @@
             break; \
         } \
     } while (_rc == -1); /* _syscallErrno == EINTR && !_wasSignaled */ \
+    if (_rc == -1) { \
+        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
+        errno = _syscallErrno; \
+    } \
     _rc; })
 
 /**
@@ -170,9 +174,9 @@
  */
 #define IO_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
     return_type _rc = -1; \
+    int _syscallErrno; \
     do { \
         bool _wasSignaled; \
-        int _syscallErrno; \
         { \
             int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
             AsynchronousCloseMonitor _monitor(_fd); \
@@ -191,6 +195,10 @@
             break; \
         } \
     } while (_rc == -1); /* && _syscallErrno == EINTR && !_wasSignaled */ \
+    if (_rc == -1) { \
+        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
+        errno = _syscallErrno; \
+    } \
     _rc; })
 
 #define NULL_ADDR_OK         true
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index ec39596..b227793 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -27,7 +27,6 @@
     java_lang_StringToReal.cpp \
     java_lang_System.cpp \
     java_math_NativeBN.cpp \
-    java_text_Bidi.cpp \
     java_util_jar_StrictJarFile.cpp \
     java_util_regex_Matcher.cpp \
     java_util_regex_Pattern.cpp \
@@ -35,12 +34,10 @@
     java_util_zip_CRC32.cpp \
     java_util_zip_Deflater.cpp \
     java_util_zip_Inflater.cpp \
-    libcore_icu_AlphabeticIndex.cpp \
     libcore_icu_ICU.cpp \
     libcore_icu_NativeCollation.cpp \
     libcore_icu_NativeConverter.cpp \
     libcore_icu_NativeDecimalFormat.cpp \
-    libcore_icu_NativeIDN.cpp \
     libcore_icu_TimeZoneNames.cpp \
     libcore_io_AsynchronousCloseMonitor.cpp \
     libcore_io_Memory.cpp \
diff --git a/luni/src/test/java/libcore/icu/AlphabeticIndexTest.java b/luni/src/test/java/libcore/icu/AlphabeticIndexTest.java
deleted file mode 100644
index 6c7452d..0000000
--- a/luni/src/test/java/libcore/icu/AlphabeticIndexTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package libcore.icu;
-
-import java.util.Locale;
-
-public class AlphabeticIndexTest extends junit.framework.TestCase {
-  private static AlphabeticIndex.ImmutableIndex createIndex(Locale locale) {
-    return new AlphabeticIndex(locale).addLabels(Locale.US).getImmutableIndex();
-  }
-
-  private static void assertHasLabel(AlphabeticIndex.ImmutableIndex ii, String string, String expectedLabel) {
-    int index = ii.getBucketIndex(string);
-    String label = ii.getBucketLabel(index);
-    assertEquals(expectedLabel, label);
-  }
-
-  public void test_en() throws Exception {
-    // English [A-Z]
-    AlphabeticIndex.ImmutableIndex en = createIndex(Locale.ENGLISH);
-    assertHasLabel(en, "Allen", "A");
-    assertHasLabel(en, "allen", "A");
-  }
-
-  public void test_ja() throws Exception {
-    AlphabeticIndex.ImmutableIndex ja = createIndex(Locale.JAPANESE);
-
-    // Japanese
-    //   sorts hiragana/katakana, Kanji/Chinese, English, other
-    // …, あ, か, さ, た, な, は, ま, や, ら, わ, …
-    // hiragana "a"
-    assertHasLabel(ja, "Allen", "A");
-    assertHasLabel(ja, "\u3041", "\u3042");
-    // katakana "a"
-    assertHasLabel(ja, "\u30a1", "\u3042");
-
-    // Kanji (sorts to inflow section)
-    assertHasLabel(ja, "\u65e5", "");
-
-    // http://bugs.icu-project.org/trac/ticket/10423 / http://b/10809397
-    assertHasLabel(ja, "\u95c7", "");
-    assertHasLabel(ja, "\u308f", "わ");
-
-    // English
-    assertHasLabel(ja, "Smith", "S");
-
-    // Chinese (sorts to inflow section)
-    assertHasLabel(ja, "\u6c88" /* Shen/Chen */, "");
-
-    // Korean Hangul (sorts to overflow section)
-    assertHasLabel(ja, "\u1100", "");
-  }
-
-  public void test_ko() throws Exception {
-    // Korean (sorts Korean, then English)
-    // …, ᄀ, ᄂ, ᄃ, ᄅ, ᄆ, ᄇ, ᄉ, ᄋ, ᄌ, ᄎ, ᄏ, ᄐ, ᄑ, ᄒ, …
-    AlphabeticIndex.ImmutableIndex ko = createIndex(Locale.KOREAN);
-    assertHasLabel(ko, "\u1100", "\u3131");
-    assertHasLabel(ko, "\u3131", "\u3131");
-    assertHasLabel(ko, "\u1101", "\u3131");
-    assertHasLabel(ko, "\u1161", "\u314e");
-  }
-
-  public void test_cs() throws Exception {
-    // Czech
-    // …, [A-C], Č,[D-H], CH, [I-R], Ř, S, Š, [T-Z], Ž, …
-    AlphabeticIndex.ImmutableIndex cs = createIndex(new Locale("cs"));
-    assertHasLabel(cs, "Cena", "C");
-    assertHasLabel(cs, "Čáp", "\u010c");
-    assertHasLabel(cs, "Ruda", "R");
-    assertHasLabel(cs, "Řada", "\u0158");
-    assertHasLabel(cs, "Selka", "S");
-    assertHasLabel(cs, "Šála", "\u0160");
-    assertHasLabel(cs, "Zebra", "Z");
-    assertHasLabel(cs, "Žába", "\u017d");
-    assertHasLabel(cs, "Chata", "CH");
-  }
-
-  public void test_fr() throws Exception {
-    // French: [A-Z] (no accented chars)
-    AlphabeticIndex.ImmutableIndex fr = createIndex(Locale.FRENCH);
-    assertHasLabel(fr, "Øfer", "O");
-    assertHasLabel(fr, "Œster", "O");
-  }
-
-  public void test_da() throws Exception {
-    // Danish: [A-Z], Æ, Ø, Å
-    AlphabeticIndex.ImmutableIndex da = createIndex(new Locale("da"));
-    assertHasLabel(da, "Ænes", "\u00c6");
-    assertHasLabel(da, "Øfer", "\u00d8");
-    assertHasLabel(da, "Œster", "\u00d8");
-    assertHasLabel(da, "Ågård", "\u00c5");
-  }
-
-  public void test_de() throws Exception {
-    // German: [A-Z] (no ß or umlauted characters in standard alphabet)
-    AlphabeticIndex.ImmutableIndex de = createIndex(Locale.GERMAN);
-    assertHasLabel(de, "ßind", "S");
-    // We no longer split out "S", "Sch", and "St".
-    assertHasLabel(de, "Sacher", "S");
-    assertHasLabel(de, "Schiller", "S");
-    assertHasLabel(de, "Steiff", "S");
-  }
-
-  public void test_th() throws Exception {
-    // Thai (sorts English then Thai)
-    // …, ก, ข, ฃ, ค, ฅ, ฆ, ง, จ, ฉ, ช, ซ, ฌ, ญ, ฎ, ฏ, ฐ, ฑ, ฒ, ณ, ด, ต, ถ, ท, ธ, น, บ, ป, ผ, ฝ, พ, ฟ, ภ, ม, ย, ร, ฤ, ล, ฦ, ว, ศ, ษ, ส, ห, ฬ, อ, ฮ, …,
-    AlphabeticIndex.ImmutableIndex th = createIndex(new Locale("th"));
-    assertHasLabel(th, "\u0e2d\u0e07\u0e04\u0e4c\u0e40\u0e25\u0e47\u0e01", "\u0e2d");
-    assertHasLabel(th, "\u0e2a\u0e34\u0e07\u0e2b\u0e40\u0e2a\u0e19\u0e35", "\u0e2a");
-  }
-
-  public void test_ar() throws Exception {
-    // Arabic (sorts English then Arabic)
-    // …, ا, ب, ت, ث, ج, ح, خ, د, ذ, ر, ز, س, ش, ص, ض, ط, ظ, ع, غ, ف, ق, ك, ل, م, ن, ه, و, ي, …
-    AlphabeticIndex.ImmutableIndex ar = createIndex(new Locale("ar"));
-    assertHasLabel(ar, "\u0646\u0648\u0631", /* Noor */ "\u0646");
-  }
-
-  public void test_he() throws Exception {
-    // Hebrew (sorts English then Hebrew)
-    // …, א, ב, ג, ד, ה, ו, ז, ח, ט, י, כ, ל, מ, נ, ס, ע, פ, צ, ק, ר, ש, ת, …
-    AlphabeticIndex.ImmutableIndex he = createIndex(new Locale("he"));
-    assertHasLabel(he, "\u05e4\u05e8\u05d9\u05d3\u05de\u05df", "\u05e4");
-  }
-
-  public void test_zh_CN() throws Exception {
-    // Simplified Chinese (default collator Pinyin): [A-Z]
-    AlphabeticIndex.ImmutableIndex zh_CN = createIndex(new Locale("zh", "CN"));
-
-    // Jia/Gu: should be, usually, 'J' for name collator and 'G' for apps/other
-    assertHasLabel(zh_CN, "\u8d3e", "J");
-
-    // Shen/Chen (simplified): should usually be 'S' for names and 'C' for apps/other.
-    // icu4c does not specialize for names and defaults to 'C'.
-    // Some OEMs prefer to default to 'S'.
-    // We allow either to pass CTS since neither choice is right all the time.
-    // assertHasLabel(zh_CN, "\u6c88", "C");
-    String shenChenLabel = zh_CN.getBucketLabel(zh_CN.getBucketIndex("\u6c88"));
-    assertTrue(shenChenLabel.equals("C") || shenChenLabel.equals("S"));
-
-    // Shen/Chen (traditional)
-    assertHasLabel(zh_CN, "\u700b", "S");
-  }
-
-  public void test_zh_HK() throws Exception {
-    // Traditional Chinese (strokes).
-    // …, [1-33, 35, 36, 39, 48]劃, …
-    // Shen/Chen
-    AlphabeticIndex.ImmutableIndex zh_HK = createIndex(new Locale("zh", "HK"));
-    assertHasLabel(zh_HK, "\u6c88", "7\u5283");
-    assertHasLabel(zh_HK, "\u700b", "18\u5283");
-    // Jia/Gu
-    assertHasLabel(zh_HK, "\u8d3e", "10\u5283");
-  }
-
-  public void test_constructor_NPE() throws Exception {
-    try {
-      new AlphabeticIndex(null);
-      fail();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  public void test_addLabels_NPE() throws Exception {
-    AlphabeticIndex ai = new AlphabeticIndex(Locale.US);
-    try {
-      ai.addLabels(null);
-      fail();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  // ICU 51 default max label count is 99. Test to make sure can create an
-  // index with a larger number of labels.
-  public void test_setMaxLabelCount() throws Exception {
-    final int MAX_LABEL_COUNT = 500;
-    AlphabeticIndex ai = new AlphabeticIndex(Locale.US)
-      .setMaxLabelCount(MAX_LABEL_COUNT)
-      .addLabels(Locale.JAPANESE)
-      .addLabels(Locale.KOREAN)
-      .addLabels(new Locale("th"))
-      .addLabels(new Locale("ar"))
-      .addLabels(new Locale("he"))
-      .addLabels(new Locale("el"))
-      .addLabels(new Locale("ru"));
-    assertEquals(MAX_LABEL_COUNT, ai.getMaxLabelCount());
-    assertEquals(208, ai.getBucketCount());
-    AlphabeticIndex.ImmutableIndex ii = ai.getImmutableIndex();
-    assertEquals(ai.getBucketCount(), ii.getBucketCount());
-  }
-
-  public void test_getBucketIndex_NPE() throws Exception {
-    AlphabeticIndex.ImmutableIndex ii = createIndex(Locale.US);
-    try {
-      ii.getBucketIndex(null);
-      fail();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  public void test_getBucketLabel_invalid() throws Exception {
-    AlphabeticIndex.ImmutableIndex ii = createIndex(Locale.US);
-    try {
-      ii.getBucketLabel(-1);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-
-    try {
-      ii.getBucketLabel(123456);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-  }
-}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index f1d6668..1dcc3c6 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -426,6 +426,23 @@
     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
   }
 
+  public void test_Ipv4Fallback() throws Exception {
+    // This number of iterations gives a ~60% chance of creating the conditions that caused
+    // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using
+    // vogar, this test takes about 4s.
+    final int ITERATIONS = 10000;
+    for (int i = 0; i < ITERATIONS; i++) {
+      FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      try {
+          Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0);
+      } catch(ErrnoException e) {
+          fail("ErrnoException after " + i + " iterations: " + e);
+      } finally {
+          Libcore.os.close(mUdpSock);
+      }
+    }
+  }
+
   public void test_unlink() throws Exception {
     File f = File.createTempFile("OsTest", "tst");
     assertTrue(f.exists());
diff --git a/luni/src/test/java/libcore/java/io/SerializationTest.java b/luni/src/test/java/libcore/java/io/SerializationTest.java
index 32bc402..03e7d94 100644
--- a/luni/src/test/java/libcore/java/io/SerializationTest.java
+++ b/luni/src/test/java/libcore/java/io/SerializationTest.java
@@ -49,7 +49,9 @@
 
     static class FieldMadeTransient implements Serializable {
         private static final long serialVersionUID = 0L;
+        @SuppressWarnings("unused")
         private transient int transientInt;
+        @SuppressWarnings("unused")
         private int nonTransientInt;
     }
 
@@ -64,7 +66,7 @@
                 + "374244669656c644d6164655374617469630000000000000000020001490009737461746963496e7"
                 + "47870000022b8";
         FieldMadeStatic deserialized = (FieldMadeStatic) SerializationTester.deserializeHex(s);
-        // The field data is simply ignored if it is static.
+        // The field data must be ignored if it is static.
         assertEquals(9999, deserialized.staticInt);
     }
 
@@ -74,73 +76,101 @@
         private static int staticInt = 9999;
     }
 
+    public static boolean serializableContainer1InitializedFlag = false;
+    public static boolean unserializable1InitializedFlag = false;
+
+    public static class Unserializable1 {
+        static {
+            SerializationTest.unserializable1InitializedFlag = true;
+        }
+    }
+
+    static class SerializableContainer1 implements Serializable {
+        private static final long serialVersionUID = 0L;
+        private Unserializable1 unserializable = null;
+
+        static {
+            serializableContainer1InitializedFlag = true;
+        }
+    }
+
     // We can serialize an object that has an unserializable field providing it is null.
     public void testDeserializeNullUnserializableField() throws Exception {
         // This was created by creating a new SerializableContainer and not setting the
         // unserializable field. A canned serialized form is used so we can tell if the static
         // initializers were executed during deserialization.
-        // SerializationTester.serializeHex(new SerializableContainer());
-        String s = "aced0005737200376c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
-                + "3742453657269616c697a61626c65436f6e7461696e657200000000000000000200014c000e756e7"
-                + "3657269616c697a61626c657400334c6c6962636f72652f6a6176612f696f2f53657269616c697a6"
-                + "174696f6e546573742457617353657269616c697a61626c653b787070";
+        // SerializationTester.serializeHex(new SerializableContainer1());
+        String s = "aced0005737200386c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
+                  + "3742453657269616c697a61626c65436f6e7461696e65723100000000000000000200014c000e7"
+                  + "56e73657269616c697a61626c657400124c6a6176612f6c616e672f4f626a6563743b787070";
 
-        serializableContainerInitializedFlag = false;
-        wasSerializableInitializedFlag = false;
+        assertFalse(serializableContainer1InitializedFlag);
+        assertFalse(unserializable1InitializedFlag);
 
-        SerializableContainer sc = (SerializableContainer) SerializationTester.deserializeHex(s);
+        SerializableContainer1 sc = (SerializableContainer1) SerializationTester.deserializeHex(s);
         assertNull(sc.unserializable);
 
         // Confirm the container was initialized, but the class for the null field was not.
-        assertTrue(serializableContainerInitializedFlag);
-        assertFalse(wasSerializableInitializedFlag);
+        assertTrue(serializableContainer1InitializedFlag);
+        assertFalse(unserializable1InitializedFlag);
     }
 
-    public static boolean serializableContainerInitializedFlag = false;
+    static class Unserializable2 {
+    }
 
-    static class SerializableContainer implements Serializable {
+    static class HasUnserializableField implements Serializable {
         private static final long serialVersionUID = 0L;
-        private Object unserializable = null;
-
-        static {
-            serializableContainerInitializedFlag = true;
-        }
+        @SuppressWarnings("unused") // Required to make objects unserializable.
+        private Unserializable2 unserializable = new Unserializable2();
     }
 
     // We must not serialize an object that has a non-null unserializable field.
     public void testSerializeUnserializableField() throws Exception {
-        SerializableContainer sc = new SerializableContainer();
-        sc.unserializable = new WasSerializable();
+        HasUnserializableField uf = new HasUnserializableField();
         try {
-            SerializationTester.serializeHex(sc);
+            SerializationTester.serializeHex(uf);
             fail();
         } catch (NotSerializableException expected) {
         }
     }
 
+    public static boolean serializableContainer2InitializedFlag = false;
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    static class SerializableContainer2 implements Serializable {
+        private static final long serialVersionUID = 0L;
+        private WasSerializable unserializable = null;
+
+        static {
+            serializableContainer2InitializedFlag = true;
+        }
+    }
+
     // It must not be possible to deserialize an object if a field is no longer serializable.
     public void testDeserializeUnserializableField() throws Exception {
-        // This was generated by creating a SerializableContainer and setting the unserializable
+        // This was generated by creating a SerializableContainer2 and setting the unserializable
         // field to a WasSerializable when it was still Serializable. A canned serialized form is
         // used so we can tell if the static initializers were executed during deserialization.
-        // SerializableContainer sc = new SerializableContainer();
+        // SerializableContainer2 sc = new SerializableContainer2();
         // sc.unserializable = new WasSerializable();
         // SerializationTester.serializeHex(sc);
-        String s = "aced0005737200376c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
-                + "3742453657269616c697a61626c65436f6e7461696e657200000000000000000200014c000e756e7"
-                + "3657269616c697a61626c657400124c6a6176612f6c616e672f4f626a6563743b7870737200316c6"
-                + "962636f72652e6a6176612e696f2e53657269616c697a6174696f6e5465737424576173536572696"
-                + "16c697a61626c65000000000000000002000149000169787000000000";
+        String s = "aced0005737200386c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
+                  + "3742453657269616c697a61626c65436f6e7461696e65723200000000000000000200014c000e7"
+                  + "56e73657269616c697a61626c657400334c6c6962636f72652f6a6176612f696f2f53657269616"
+                  + "c697a6174696f6e546573742457617353657269616c697a61626c653b7870737200316c6962636"
+                  + "f72652e6a6176612e696f2e53657269616c697a6174696f6e546573742457617353657269616c6"
+                  + "97a61626c65000000000000000002000149000169787000000000";
 
-        serializableContainerInitializedFlag = false;
-        wasSerializableInitializedFlag = false;
+        assertFalse(serializableContainer2InitializedFlag);
+        assertFalse(wasSerializableInitializedFlag);
         try {
             SerializationTester.deserializeHex(s);
             fail();
         } catch (InvalidClassException expected) {
         }
-        // Confirm neither the container nor the contained class was initialized.
-        assertFalse(serializableContainerInitializedFlag);
+        // The container class will be initialized to establish the serialVersionUID.
+        assertTrue(serializableContainer2InitializedFlag);
+        // Confirm the contained class was initialized.
         assertFalse(wasSerializableInitializedFlag);
     }
 
@@ -196,7 +226,7 @@
                 + "e546573742457617353657269616c697a61626c65000000000000000002000149000169787000000"
                 + "000";
 
-        wasSerializableInitializedFlag = false;
+        assertFalse(wasSerializableInitializedFlag);
         try {
             SerializationTester.deserializeHex(s);
             fail();
@@ -239,7 +269,7 @@
         final String s = "aced0005737200336c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
                 + "e546573742457617345787465726e616c697a61626c6500000000000000000c0000787078";
 
-        wasExternalizableInitializedFlag = false;
+        assertFalse(wasExternalizableInitializedFlag);
         try {
             SerializationTester.deserializeHex(s);
             fail();
@@ -275,7 +305,7 @@
                 + "e5465737424576173456e756d00000000000000001200007872000e6a6176612e6c616e672e456e7"
                 + "56d0000000000000000120000787074000556414c5545";
 
-        wasEnumInitializedFlag = false;
+        assertFalse(wasEnumInitializedFlag);
         try {
             SerializationTester.deserializeHex(s);
             fail();
@@ -309,7 +339,7 @@
         final String s = "aced00057372002b6c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
                 + "e54657374245761734f626a656374000000000000000002000149000169787000000000";
 
-        wasObjectInitializedFlag = false;
+        assertFalse(wasObjectInitializedFlag);
         try {
             SerializationTester.deserializeHex(s);
             fail();
diff --git a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
index 4fa6e0c..db2be53 100644
--- a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
+++ b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
@@ -85,7 +85,11 @@
 
     private static byte[] encode(String charsetName, String s) throws Exception {
         CharsetEncoder encoder = Charset.forName(charsetName).newEncoder();
-        return encoder.encode(CharBuffer.wrap(s)).array();
+        ByteBuffer buf = encoder.encode(CharBuffer.wrap(s));
+        byte[] out = new byte[buf.remaining()];
+        buf.get(out);
+        assertEquals(0, buf.remaining());
+        return out;
     }
 
     public void testUtf8BytesSplitAcrossMultipleWrites() throws Exception {
diff --git a/luni/src/test/java/libcore/java/text/OldBidiTest.java b/luni/src/test/java/libcore/java/text/OldBidiTest.java
index 45fe258..fbf68ea 100644
--- a/luni/src/test/java/libcore/java/text/OldBidiTest.java
+++ b/luni/src/test/java/libcore/java/text/OldBidiTest.java
@@ -70,4 +70,126 @@
         assertEquals(1, bd.getRunStart(1));
         assertEquals(2, bd.getRunStart(2));
     }
+
+    public void testReorderVisuallyIllegalArguments() {
+        // Negative index.
+        try {
+            Bidi.reorderVisually(new byte[] {}, -1, new Object[] {}, 0, 0);
+            fail();
+        } catch (IllegalArgumentException  expected) {
+            // Expected.
+        }
+
+        try {
+            Bidi.reorderVisually(new byte[] {}, 0, new Object[] {}, -1, 0);
+            fail();
+        } catch (IllegalArgumentException  expected) {
+            // Expected.
+        }
+
+        try {
+            Bidi.reorderVisually(new byte[] {}, 0, new Object[] {}, 0, -1);
+            fail();
+        } catch (IllegalArgumentException  expected) {
+            // Expected.
+        }
+
+        // Count > levels.length.
+        try {
+            Bidi.reorderVisually(new byte[] {}, 0, new Object[] {}, 0, 1);
+            fail();
+        } catch (IllegalArgumentException  expected) {
+            // Expected.
+        }
+
+        // Count > levels.length - levelStart.
+        try {
+            Bidi.reorderVisually(new byte[] {1, 2, 3}, 2, new Object[] {}, 0, 2);
+            fail();
+        } catch (IllegalArgumentException  expected) {
+            // Expected.
+        }
+    }
+
+    public void testRequiresBidiIllegalArguments() {
+        // Negative param.
+        try {
+            Bidi.requiresBidi(new char[] {}, 0, -1);
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        try {
+            Bidi.requiresBidi(new char[] {}, -1, 0);
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        // Limit > start.
+        try {
+            Bidi.requiresBidi(new char[] {}, 1, 0);
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        // Limit > text.length.
+        try {
+            Bidi.requiresBidi(new char[] {'a', 'b', 'c'}, 0, 4);
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testCreateLineBidiIllegalArguments() {
+        Bidi bidi = new Bidi("test", Bidi.DIRECTION_LEFT_TO_RIGHT);
+
+        try {
+            bidi.createLineBidi(-1, 0);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        try {
+            bidi.createLineBidi(0, -1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        // Linelimit > getLength().
+        try {
+            bidi.createLineBidi(0, 5);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        // lineStart > lineLimit.
+         try {
+            bidi.createLineBidi(2, 1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
+    public void testConstructorIllegalArguments() {
+        try {
+            new Bidi(null, Bidi.DIRECTION_LEFT_TO_RIGHT);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+
+        // text.length - textStart < paragraphLength.
+        try {
+            new Bidi(new char[] {'a', 'b', 'c', 'd', 'e'}, 1, new byte[] {}, 0, 5,
+                    Bidi.DIRECTION_LEFT_TO_RIGHT);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            // Expected.
+        }
+    }
+
 }
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 13d54b4..bad8a74 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -979,6 +979,76 @@
         }
     }
 
+    public void testCipher_getInstance_CorrectPriority_AlgorithmOnlyFirst() throws Exception {
+        Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") {
+            public void setup() {
+                put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+            }
+        };
+        Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") {
+            public void setup() {
+                put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName());
+            }
+        };
+
+        Security.addProvider(mockProviderOnlyAlgorithm);
+        Security.addProvider(mockProviderFullTransformSpecified);
+        try {
+            Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+            assertEquals(mockProviderOnlyAlgorithm, c.getProvider());
+        } finally {
+            Security.removeProvider(mockProviderOnlyAlgorithm.getName());
+            Security.removeProvider(mockProviderFullTransformSpecified.getName());
+        }
+    }
+
+    public void testCipher_getInstance_CorrectPriority_FullTransformFirst() throws Exception {
+        Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") {
+            public void setup() {
+                put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+            }
+        };
+        Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") {
+            public void setup() {
+                put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName());
+            }
+        };
+
+        Security.addProvider(mockProviderFullTransformSpecified);
+        Security.addProvider(mockProviderOnlyAlgorithm);
+        try {
+            Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+            assertEquals(mockProviderFullTransformSpecified, c.getProvider());
+        } finally {
+            Security.removeProvider(mockProviderOnlyAlgorithm.getName());
+            Security.removeProvider(mockProviderFullTransformSpecified.getName());
+        }
+    }
+
+    public void testCipher_getInstance_CorrectPriority_AliasedAlgorithmFirst() throws Exception {
+        Provider mockProviderAliasedAlgorithm = new MockProvider("MockProviderAliasedAlgorithm") {
+            public void setup() {
+                put("Cipher.BAR", MockCipherSpi.AllKeyTypes.class.getName());
+                put("Alg.Alias.Cipher.FOO", "BAR");
+            }
+        };
+        Provider mockProviderAlgorithmOnly = new MockProvider("MockProviderAlgorithmOnly") {
+            public void setup() {
+                put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+            }
+        };
+
+        Security.addProvider(mockProviderAliasedAlgorithm);
+        Security.addProvider(mockProviderAlgorithmOnly);
+        try {
+            Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+            assertEquals(mockProviderAliasedAlgorithm, c.getProvider());
+        } finally {
+            Security.removeProvider(mockProviderAliasedAlgorithm.getName());
+            Security.removeProvider(mockProviderAlgorithmOnly.getName());
+        }
+    }
+
     public void testCipher_getInstance_WrongType_Failure() throws Exception {
         Provider mockProviderInvalid = new MockProvider("MockProviderInvalid") {
             public void setup() {