Merge "Revert "Revert "Limit access to the device's fixed 802.11 MAC address."""
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index 6862987..fa71e32 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -120,10 +120,9 @@
         "//frameworks/base",
     ],
     srcs: [
-        ":android_icu4j_src_files",
+        ":android_icu4j_public_api_files",
         ":core_oj_api_files",
         ":core_libart_api_files",
-        ":conscrypt_public_api_files",
     ],
 }
 
@@ -142,8 +141,12 @@
     tools: [
         "merge_zips",
     ],
+    srcs: [
+        ":conscrypt-module-public-api-stubs-source",
+    ],
     out: ["core-current-stubs-source.srcjar"],
-    cmd: "$(location merge_zips) $(out)",
+    cmd: "$(location merge_zips) $(out)" +
+        " $(location :conscrypt-module-public-api-stubs-source)",
 }
 
 // The set of files for the ART module that contribute to one or more API
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 13769e1..14d554a 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -136,8 +136,9 @@
      */
     @libcore.api.CorePlatformApi
     public static void postForkCommon() {
-        Daemons.startPostZygoteFork();
+        // Notify the runtime before creating new threads.
         nativePostZygoteFork();
+        Daemons.startPostZygoteFork();
     }
 
 
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
deleted file mode 100644
index f695694..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
- /**
-  * A JNI interface for ICU converters.
-  *
-  *
-  * @author Ram Viswanadha, IBM
-  */
-package java.nio.charset;
-
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import libcore.icu.ICU;
-import libcore.icu.NativeConverter;
-import libcore.util.EmptyArray;
-
-final class CharsetDecoderICU extends CharsetDecoder {
-    private static final int MAX_CHARS_PER_BYTE = 2;
-
-    private static final int INPUT_OFFSET = 0;
-    private static final int OUTPUT_OFFSET = 1;
-    private static final int INVALID_BYTE_COUNT = 2;
-    /*
-     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input bytes consumed
-     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output chars written
-     * data[INVALID_BYTE_COUNT]  = number of invalid bytes
-     */
-    private final int[] data = new int[3];
-
-    /* Handle to the ICU converter that is opened, cleaned up via NativeAllocationRegistry. */
-    @ReachabilitySensitive
-    private long converterHandle = 0;
-
-    private byte[] input = null;
-    private char[] output= null;
-
-    private byte[] allocatedInput = null;
-    private char[] allocatedOutput = null;
-
-    // These instance variables are always assigned in the methods before being used. This class
-    // is inherently thread-unsafe so we don't have to worry about synchronization.
-    private int inEnd;
-    private int outEnd;
-
-    public static CharsetDecoderICU newInstance(Charset cs, String icuCanonicalName) {
-        // This complexity is necessary to ensure that even if the constructor, superclass
-        // constructor, or call to updateCallback throw, we still free the native peer.
-        long address = 0;
-        CharsetDecoderICU result;
-        try {
-            address = NativeConverter.openConverter(icuCanonicalName);
-            float averageCharsPerByte = NativeConverter.getAveCharsPerByte(address);
-            result = new CharsetDecoderICU(cs, averageCharsPerByte, address);
-        } catch (Throwable t) {
-            if (address != 0) {
-                NativeConverter.closeConverter(address);
-            }
-            throw t;
-        }
-        // An exception in registerConverter() will deallocate address:
-        NativeConverter.registerConverter(result, address);
-        result.updateCallback();
-        return result;
-    }
-
-    private CharsetDecoderICU(Charset cs, float averageCharsPerByte, long address) {
-        super(cs, averageCharsPerByte, MAX_CHARS_PER_BYTE);
-        this.converterHandle = address;
-    }
-
-    @Override protected void implReplaceWith(String newReplacement) {
-        updateCallback();
-    }
-
-    @Override protected final void implOnMalformedInput(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    @Override protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    private void updateCallback() {
-        NativeConverter.setCallbackDecode(converterHandle, this);
-    }
-
-    @Override protected void implReset() {
-        NativeConverter.resetByteToChar(converterHandle);
-        data[INPUT_OFFSET] = 0;
-        data[OUTPUT_OFFSET] = 0;
-        data[INVALID_BYTE_COUNT] = 0;
-        output = null;
-        input = null;
-        allocatedInput = null;
-        allocatedOutput = null;
-        inEnd = 0;
-        outEnd = 0;
-    }
-
-    @Override protected final CoderResult implFlush(CharBuffer out) {
-        try {
-            // ICU needs to see an empty input.
-            input = EmptyArray.BYTE;
-            inEnd = 0;
-            data[INPUT_OFFSET] = 0;
-
-            data[OUTPUT_OFFSET] = getArray(out);
-            data[INVALID_BYTE_COUNT] = 0; // Make sure we don't see earlier errors.
-
-            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
-                    if (data[INVALID_BYTE_COUNT] > 0) {
-                        return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
-                    }
-                }
-            }
-            return CoderResult.UNDERFLOW;
-       } finally {
-            setPosition(out);
-            implReset();
-       }
-    }
-
-    @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
-        if (!in.hasRemaining()) {
-            return CoderResult.UNDERFLOW;
-        }
-
-        data[INPUT_OFFSET] = getArray(in);
-        data[OUTPUT_OFFSET]= getArray(out);
-
-        try {
-            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
-                    return CoderResult.unmappableForLength(data[INVALID_BYTE_COUNT]);
-                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
-                    return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
-                } else {
-                    throw new AssertionError(error);
-                }
-            }
-            // Decoding succeeded: give us more data.
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(in);
-            setPosition(out);
-        }
-    }
-
-
-    private int getArray(CharBuffer out) {
-        if (out.hasArray()) {
-            output = out.array();
-            outEnd = out.arrayOffset() + out.limit();
-            return out.arrayOffset() + out.position();
-        } else {
-            outEnd = out.remaining();
-            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
-                allocatedOutput = new char[outEnd];
-            }
-            // The array's start position is 0.
-            output = allocatedOutput;
-            return 0;
-        }
-    }
-
-    private  int getArray(ByteBuffer in) {
-        if (in.hasArray()) {
-            input = in.array();
-            inEnd = in.arrayOffset() + in.limit();
-            return in.arrayOffset() + in.position();
-        } else {
-            inEnd = in.remaining();
-            if (allocatedInput == null || inEnd > allocatedInput.length) {
-                allocatedInput = new byte[inEnd];
-            }
-            // Copy the input buffer into the allocated array.
-            int pos = in.position();
-            in.get(allocatedInput, 0, inEnd);
-            in.position(pos);
-            // The array's start position is 0.
-            input = allocatedInput;
-            return 0;
-        }
-    }
-
-    private void setPosition(CharBuffer out) {
-        if (out.hasArray()) {
-            out.position(out.position() + data[OUTPUT_OFFSET]);
-        } else {
-            out.put(output, 0, data[OUTPUT_OFFSET]);
-        }
-        // release reference to output array, which may not be ours
-        output = null;
-    }
-
-    private void setPosition(ByteBuffer in) {
-        in.position(in.position() + data[INPUT_OFFSET]);
-        // release reference to input array, which may not be ours
-        input = null;
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
deleted file mode 100644
index c57aafd..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                  *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-/**
- * A JNI interface for ICU converters.
- *
- *
- * @author Ram Viswanadha, IBM
- */
-package java.nio.charset;
-
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.util.HashMap;
-import java.util.Map;
-import libcore.icu.ICU;
-import libcore.icu.NativeConverter;
-import libcore.util.EmptyArray;
-
-final class CharsetEncoderICU extends CharsetEncoder {
-    private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
-    static {
-        // ICU has different default replacements to the RI in some cases. There are many
-        // additional cases, but this covers all the charsets that Java guarantees will be
-        // available, which is where compatibility seems most important. (The RI even uses
-        // the byte corresponding to '?' in ASCII as the replacement byte for charsets where that
-        // byte corresponds to an entirely different character.)
-        // It's odd that UTF-8 doesn't use U+FFFD, given that (unlike ISO-8859-1 and US-ASCII) it
-        // can represent it, but this is what the RI does...
-        byte[] questionMark = new byte[] { (byte) '?' };
-        DEFAULT_REPLACEMENTS.put("UTF-8",      questionMark);
-        DEFAULT_REPLACEMENTS.put("ISO-8859-1", questionMark);
-        DEFAULT_REPLACEMENTS.put("US-ASCII",   questionMark);
-    }
-
-    private static final int INPUT_OFFSET = 0;
-    private static final int OUTPUT_OFFSET = 1;
-    private static final int INVALID_CHAR_COUNT = 2;
-    /*
-     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input chars consumed
-     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output bytes written
-     * data[INVALID_CHARS]  = number of invalid chars
-     */
-    private int[] data = new int[3];
-
-    /* handle to the ICU converter that is opened */
-    @ReachabilitySensitive
-    private final long converterHandle;
-
-    private char[] input = null;
-    private byte[] output = null;
-
-    private char[] allocatedInput = null;
-    private byte[] allocatedOutput = null;
-
-    // These instance variables are always assigned in the methods before being used. This class
-    // is inherently thread-unsafe so we don't have to worry about synchronization.
-    private int inEnd;
-    private int outEnd;
-
-    public static CharsetEncoderICU newInstance(Charset cs, String icuCanonicalName) {
-        // This complexity is necessary to ensure that even if the constructor, superclass
-        // constructor, or call to updateCallback throw, we still free the native peer.
-        long address = 0;
-        CharsetEncoderICU result;
-        try {
-            address = NativeConverter.openConverter(icuCanonicalName);
-            float averageBytesPerChar = NativeConverter.getAveBytesPerChar(address);
-            float maxBytesPerChar = NativeConverter.getMaxBytesPerChar(address);
-            byte[] replacement = makeReplacement(icuCanonicalName, address);
-            result = new CharsetEncoderICU(cs, averageBytesPerChar, maxBytesPerChar, replacement, address);
-        } catch (Throwable t) {
-            if (address != 0) {
-                NativeConverter.closeConverter(address);
-            }
-            throw t;
-        }
-        // An exception in registerConverter() will deallocate address:
-        NativeConverter.registerConverter(result, address);
-        result.updateCallback();
-        return result;
-    }
-
-    private static byte[] makeReplacement(String icuCanonicalName, long address) {
-        // We have our own map of RI-compatible default replacements (where ICU disagrees)...
-        byte[] replacement = DEFAULT_REPLACEMENTS.get(icuCanonicalName);
-        if (replacement != null) {
-            return replacement.clone();
-        }
-        // ...but fall back to asking ICU.
-        return NativeConverter.getSubstitutionBytes(address);
-    }
-
-    private CharsetEncoderICU(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, long address) {
-        super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true);
-        // Our native peer needs to know what just happened...
-        this.converterHandle = address;
-    }
-
-    @Override protected void implReplaceWith(byte[] newReplacement) {
-        updateCallback();
-    }
-
-    @Override protected void implOnMalformedInput(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    @Override protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    private void updateCallback() {
-        NativeConverter.setCallbackEncode(converterHandle, this);
-    }
-
-    @Override protected void implReset() {
-        NativeConverter.resetCharToByte(converterHandle);
-        data[INPUT_OFFSET] = 0;
-        data[OUTPUT_OFFSET] = 0;
-        data[INVALID_CHAR_COUNT] = 0;
-        output = null;
-        input = null;
-        allocatedInput = null;
-        allocatedOutput = null;
-        inEnd = 0;
-        outEnd = 0;
-    }
-
-    @Override protected CoderResult implFlush(ByteBuffer out) {
-        try {
-            // ICU needs to see an empty input.
-            input = EmptyArray.CHAR;
-            inEnd = 0;
-            data[INPUT_OFFSET] = 0;
-
-            data[OUTPUT_OFFSET] = getArray(out);
-            data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors.
-
-            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
-                    if (data[INVALID_CHAR_COUNT] > 0) {
-                        return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]);
-                    }
-                }
-            }
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(out);
-            implReset();
-        }
-    }
-
-    @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
-        if (!in.hasRemaining()) {
-            return CoderResult.UNDERFLOW;
-        }
-
-        data[INPUT_OFFSET] = getArray(in);
-        data[OUTPUT_OFFSET]= getArray(out);
-        data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors.
-
-        try {
-            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
-                    return CoderResult.unmappableForLength(data[INVALID_CHAR_COUNT]);
-                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
-                    return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]);
-                } else {
-                    throw new AssertionError(error);
-                }
-            }
-            // Decoding succeeded: give us more data.
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(in);
-            setPosition(out);
-        }
-    }
-
-    private int getArray(ByteBuffer out) {
-        if (out.hasArray()) {
-            output = out.array();
-            outEnd = out.arrayOffset() + out.limit();
-            return out.arrayOffset() + out.position();
-        } else {
-            outEnd = out.remaining();
-            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
-                allocatedOutput = new byte[outEnd];
-            }
-            // The array's start position is 0
-            output = allocatedOutput;
-            return 0;
-        }
-    }
-
-    private int getArray(CharBuffer in) {
-        if (in.hasArray()) {
-            input = in.array();
-            inEnd = in.arrayOffset() + in.limit();
-            return in.arrayOffset() + in.position();
-        } else {
-            inEnd = in.remaining();
-            if (allocatedInput == null || inEnd > allocatedInput.length) {
-                allocatedInput = new char[inEnd];
-            }
-            // Copy the input buffer into the allocated array.
-            int pos = in.position();
-            in.get(allocatedInput, 0, inEnd);
-            in.position(pos);
-            // The array's start position is 0
-            input = allocatedInput;
-            return 0;
-        }
-    }
-
-    private void setPosition(ByteBuffer out) {
-        if (out.hasArray()) {
-            out.position(data[OUTPUT_OFFSET] - out.arrayOffset());
-        } else {
-            out.put(output, 0, data[OUTPUT_OFFSET]);
-        }
-        // release reference to output array, which may not be ours
-        output = null;
-    }
-
-    private void setPosition(CharBuffer in) {
-        int position = in.position() + data[INPUT_OFFSET] - data[INVALID_CHAR_COUNT];
-        if (position < 0) {
-            // The calculated position might be negative if we encountered an
-            // invalid char that spanned input buffers. We adjust it to 0 in this case.
-            //
-            // NOTE: The API doesn't allow us to adjust the position of the previous
-            // input buffer. (Doing that wouldn't serve any useful purpose anyway.)
-            position = 0;
-        }
-
-        in.position(position);
-        // release reference to input array, which may not be ours
-        input = null;
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/CharsetICU.java b/luni/src/main/java/java/nio/charset/CharsetICU.java
deleted file mode 100644
index 63ffd3e..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetICU.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2005, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-
-package java.nio.charset;
-
-import libcore.icu.NativeConverter;
-
-/**
- * This class is used from native code associated with {@link NativeConverter}.
- */
-final class CharsetICU extends Charset {
-    private final String icuCanonicalName;
-
-    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
-         super(canonicalName, aliases);
-         icuCanonicalName = icuCanonName;
-    }
-
-    public CharsetDecoder newDecoder() {
-        return CharsetDecoderICU.newInstance(this, icuCanonicalName);
-    }
-
-    public CharsetEncoder newEncoder() {
-        return CharsetEncoderICU.newInstance(this, icuCanonicalName);
-    }
-
-    public boolean contains(Charset cs) {
-        if (cs == null) {
-            return false;
-        } else if (this.equals(cs)) {
-            return true;
-        }
-        return NativeConverter.contains(this.name(), cs.name());
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/TEST_MAPPING b/luni/src/main/java/java/nio/charset/TEST_MAPPING
deleted file mode 100644
index ec926f9..0000000
--- a/luni/src/main/java/java/nio/charset/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsLibcoreTestCases",
-      "options": [
-        {
-          "include-filter": "libcore.java.nio.charset"
-        },
-        {
-          "include-filter": "org.apache.harmony.tests.java.nio.charset"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index 2114523..a200970 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -364,17 +364,6 @@
 
   // --- Errors.
 
-  // Just the subset of error codes needed by CharsetDecoderICU/CharsetEncoderICU.
-  public static final int U_ZERO_ERROR = 0;
-  public static final int U_INVALID_CHAR_FOUND = 10;
-  public static final int U_TRUNCATED_CHAR_FOUND = 11;
-  public static final int U_ILLEGAL_CHAR_FOUND = 12;
-  public static final int U_BUFFER_OVERFLOW_ERROR = 15;
-
-  public static boolean U_FAILURE(int error) {
-    return error > U_ZERO_ERROR;
-  }
-
   // --- Native methods accessing ICU's database.
 
   private static native String[] getAvailableCollatorLocalesNative();
diff --git a/luni/src/main/java/libcore/icu/NativeConverter.java b/luni/src/main/java/libcore/icu/NativeConverter.java
deleted file mode 100644
index 956c701..0000000
--- a/luni/src/main/java/libcore/icu/NativeConverter.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-
-package libcore.icu;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
-
-public final class NativeConverter {
-    private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            NativeConverter.class.getClassLoader(), getNativeFinalizer(), getNativeSize());
-
-    public static native int decode(long converterHandle, byte[] input, int inEnd,
-            char[] output, int outEnd, int[] data, boolean flush);
-
-    public static native int encode(long converterHandle, char[] input, int inEnd,
-            byte[] output, int outEnd, int[] data, boolean flush);
-
-    public static native long openConverter(String charsetName);
-    public static native void closeConverter(long converterHandle);
-
-    public static void registerConverter(Object referrent, long converterHandle) {
-        registry.registerNativeAllocation(referrent, converterHandle);
-    }
-
-    public static native void resetByteToChar(long converterHandle);
-    public static native void resetCharToByte(long converterHandle);
-
-    public static native byte[] getSubstitutionBytes(long converterHandle);
-
-    public static native int getMaxBytesPerChar(long converterHandle);
-    public static native int getMinBytesPerChar(long converterHandle);
-    public static native float getAveBytesPerChar(long converterHandle);
-    public static native float getAveCharsPerByte(long converterHandle);
-
-    public static native boolean contains(String converterName1, String converterName2);
-
-    public static native String[] getAvailableCharsetNames();
-    public static native Charset charsetForName(String charsetName);
-
-    // Translates from Java's enum to the magic numbers #defined in "NativeConverter.cpp".
-    private static int translateCodingErrorAction(CodingErrorAction action) {
-        if (action == CodingErrorAction.REPORT) {
-            return 0;
-        } else if (action == CodingErrorAction.IGNORE) {
-            return 1;
-        } else if (action == CodingErrorAction.REPLACE) {
-            return 2;
-        } else {
-            throw new AssertionError(); // Someone changed the enum.
-        }
-    }
-
-    public static void setCallbackDecode(long converterHandle, CharsetDecoder decoder) {
-        setCallbackDecode(converterHandle,
-                          translateCodingErrorAction(decoder.malformedInputAction()),
-                          translateCodingErrorAction(decoder.unmappableCharacterAction()),
-                          decoder.replacement());
-    }
-    private static native void setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, String subChars);
-
-    public static void setCallbackEncode(long converterHandle, CharsetEncoder encoder) {
-        setCallbackEncode(converterHandle,
-                          translateCodingErrorAction(encoder.malformedInputAction()),
-                          translateCodingErrorAction(encoder.unmappableCharacterAction()),
-                          encoder.replacement());
-    }
-    private static native void setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
-
-    public static native long getNativeFinalizer();
-    public static native long getNativeSize();
-}
diff --git a/luni/src/main/java/libcore/util/FP16.java b/luni/src/main/java/libcore/util/FP16.java
index 9157f85..7eef20a 100644
--- a/luni/src/main/java/libcore/util/FP16.java
+++ b/luni/src/main/java/libcore/util/FP16.java
@@ -212,8 +212,8 @@
         // Collapse NaNs, akin to halfToIntBits(), but we want to keep
         // (signed) short value types to preserve the ordering of -0.0
         // and +0.0
-        short xBits = (x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY ? NaN : x;
-        short yBits = (y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY ? NaN : y;
+        short xBits = isNaN(x) ? NaN : x;
+        short yBits = isNaN(y) ? NaN : y;
 
         return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
     }
@@ -237,16 +237,16 @@
     @libcore.api.CorePlatformApi
     public static short rint(short h) {
         int bits = h & 0xffff;
-        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
         int result = bits;
 
-        if (e < 0x3c00) {
+        if (abs < 0x3c00) {
             result &= SIGN_MASK;
-            result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0));
-        } else if (e < 0x6400) {
-            e = 25 - (e >> 10);
-            int mask = (1 << e) - 1;
-            result += (1 << (e - 1));
+            result |= (0x3c00 & (abs >= 0x3800 ? 0xffff : 0x0));
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
+            result += (1 << (abs - 1));
             result &= ~mask;
         }
 
@@ -272,15 +272,15 @@
     @libcore.api.CorePlatformApi
     public static short ceil(short h) {
         int bits = h & 0xffff;
-        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
         int result = bits;
 
-        if (e < 0x3c00) {
+        if (abs < 0x3c00) {
             result &= SIGN_MASK;
-            result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0));
-        } else if (e < 0x6400) {
-            e = 25 - (e >> 10);
-            int mask = (1 << e) - 1;
+            result |= 0x3c00 & -(~(bits >> 15) & (abs != 0 ? 1 : 0));
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
             result += mask & ((bits >> 15) - 1);
             result &= ~mask;
         }
@@ -307,18 +307,23 @@
     @libcore.api.CorePlatformApi
     public static short floor(short h) {
         int bits = h & 0xffff;
-        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
         int result = bits;
 
-        if (e < 0x3c00) {
+        if (abs < 0x3c00) {
             result &= SIGN_MASK;
             result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
-        } else if (e < 0x6400) {
-            e = 25 - (e >> 10);
-            int mask = (1 << e) - 1;
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
             result += mask & -(bits >> 15);
             result &= ~mask;
         }
+        if (isNaN((short) result)) {
+            // if result is NaN mask with qNaN
+            // i.e. (Mask the most significant mantissa bit with 1)
+            result |= NaN;
+        }
 
         return (short) result;
     }
@@ -341,14 +346,14 @@
     @libcore.api.CorePlatformApi
     public static short trunc(short h) {
         int bits = h & 0xffff;
-        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
         int result = bits;
 
-        if (e < 0x3c00) {
+        if (abs < 0x3c00) {
             result &= SIGN_MASK;
-        } else if (e < 0x6400) {
-            e = 25 - (e >> 10);
-            int mask = (1 << e) - 1;
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
             result &= ~mask;
         }
 
@@ -369,8 +374,8 @@
      */
     @libcore.api.CorePlatformApi
     public static short min(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+        if (isNaN(x)) return NaN;
+        if (isNaN(y)) return NaN;
 
         if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
             return (x & SIGN_MASK) != 0 ? x : y;
@@ -395,8 +400,8 @@
      */
     @libcore.api.CorePlatformApi
     public static short max(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+        if (isNaN(x)) return NaN;
+        if (isNaN(y)) return NaN;
 
         if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
             return (x & SIGN_MASK) != 0 ? y : x;
@@ -418,8 +423,8 @@
      */
     @libcore.api.CorePlatformApi
     public static boolean less(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
 
         return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
                ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
@@ -437,8 +442,8 @@
      */
     @libcore.api.CorePlatformApi
     public static boolean lessEquals(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
 
         return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
                ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
@@ -456,8 +461,8 @@
      */
     @libcore.api.CorePlatformApi
     public static boolean greater(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
 
         return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
                ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
@@ -475,8 +480,8 @@
      */
     @libcore.api.CorePlatformApi
     public static boolean greaterEquals(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
 
         return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
                ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
@@ -494,8 +499,8 @@
      */
     @libcore.api.CorePlatformApi
     public static boolean equals(short x, short y) {
-        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
-        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
 
         return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0;
     }
diff --git a/luni/src/main/native/Android.bp b/luni/src/main/native/Android.bp
index f94ff95..423cdd1 100644
--- a/luni/src/main/native/Android.bp
+++ b/luni/src/main/native/Android.bp
@@ -32,7 +32,6 @@
         "java_lang_invoke_VarHandle.cpp",
         "java_math_NativeBN.cpp",
         "libcore_icu_ICU.cpp",
-        "libcore_icu_NativeConverter.cpp",
         "libcore_icu_TimeZoneNames.cpp",
         "libcore_io_AsynchronousCloseMonitor.cpp",
         "libcore_io_Linux.cpp",
diff --git a/luni/src/main/native/JniConstants.cpp b/luni/src/main/native/JniConstants.cpp
index 6f93d08..478d015 100644
--- a/luni/src/main/native/JniConstants.cpp
+++ b/luni/src/main/native/JniConstants.cpp
@@ -45,7 +45,6 @@
 
 // Constants
 jclass booleanClass;
-jclass charsetICUClass;
 jclass doubleClass;
 jclass errnoExceptionClass;
 jclass fileDescriptorClass;
@@ -91,7 +90,6 @@
     }
 
     booleanClass = findClass(env, "java/lang/Boolean");
-    charsetICUClass = findClass(env, "java/nio/charset/CharsetICU");
     doubleClass = findClass(env, "java/lang/Double");
     errnoExceptionClass = findClass(env, "android/system/ErrnoException");
     fileDescriptorClass = findClass(env, "java/io/FileDescriptor");
@@ -150,11 +148,6 @@
     return booleanClass;
 }
 
-jclass JniConstants::GetCharsetICUClass(JNIEnv* env) {
-    EnsureJniConstantsInitialized(env);
-    return charsetICUClass;
-}
-
 jclass JniConstants::GetDoubleClass(JNIEnv* env) {
     EnsureJniConstantsInitialized(env);
     return doubleClass;
diff --git a/luni/src/main/native/JniConstants.h b/luni/src/main/native/JniConstants.h
index 2931411..868e928 100644
--- a/luni/src/main/native/JniConstants.h
+++ b/luni/src/main/native/JniConstants.h
@@ -30,7 +30,6 @@
     static void Invalidate();
 
     static jclass GetBooleanClass(JNIEnv* env);
-    static jclass GetCharsetICUClass(JNIEnv* env);
     static jclass GetDoubleClass(JNIEnv* env);
     static jclass GetErrnoExceptionClass(JNIEnv* env);
     static jclass GetFileDescriptorClass(JNIEnv* env);
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 40e580e..17ca839 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -41,7 +41,6 @@
     REGISTER(register_java_lang_invoke_VarHandle);
     REGISTER(register_java_math_NativeBN);
     REGISTER(register_libcore_icu_ICU);
-    REGISTER(register_libcore_icu_NativeConverter);
     REGISTER(register_libcore_icu_TimeZoneNames);
     REGISTER(register_libcore_io_AsynchronousCloseMonitor);
     REGISTER(register_libcore_io_Linux);
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
deleted file mode 100644
index 480c07a..0000000
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ /dev/null
@@ -1,701 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*
-*******************************************************************************
-*/
-/*
- * (C) Copyright IBM Corp. 2000 - All Rights Reserved
- *  A JNI wrapper to ICU native converter Interface
- * @author: Ram Viswanadha
- */
-
-#define LOG_TAG "NativeConverter"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <memory>
-#include <vector>
-
-#include <android/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedStringChars.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <nativehelper/jni_macros.h>
-#include <nativehelper/toStringArray.h>
-
-#include "IcuUtilities.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ustrenum.h"
-#include "unicode/ucnv.h"
-#include "unicode/ucnv_cb.h"
-#include "unicode/uniset.h"
-#include "unicode/ustring.h"
-#include "unicode/utypes.h"
-
-#define NativeConverter_REPORT 0
-#define NativeConverter_IGNORE 1
-#define NativeConverter_REPLACE 2
-
-#define MAX_REPLACEMENT_LENGTH 32 // equivalent to UCNV_ERROR_BUFFER_LENGTH
-
-struct DecoderCallbackContext {
-    UChar replacementChars[MAX_REPLACEMENT_LENGTH];
-    size_t replacementCharCount;
-    UConverterToUCallback onUnmappableInput;
-    UConverterToUCallback onMalformedInput;
-};
-
-struct EncoderCallbackContext {
-    char replacementBytes[MAX_REPLACEMENT_LENGTH];
-    size_t replacementByteCount;
-    UConverterFromUCallback onUnmappableInput;
-    UConverterFromUCallback onMalformedInput;
-};
-
-static UConverter* toUConverter(jlong address) {
-    return reinterpret_cast<UConverter*>(static_cast<uintptr_t>(address));
-}
-
-static bool collectStandardNames(JNIEnv* env, const char* canonicalName, const char* standard,
-                                 std::vector<std::string>& result) {
-  UErrorCode status = U_ZERO_ERROR;
-  icu::UStringEnumeration e(ucnv_openStandardNames(canonicalName, standard, &status));
-  if (maybeThrowIcuException(env, "ucnv_openStandardNames", status)) {
-    return false;
-  }
-
-  int32_t count = e.count(status);
-  if (maybeThrowIcuException(env, "StringEnumeration::count", status)) {
-    return false;
-  }
-
-  for (int32_t i = 0; i < count; ++i) {
-    const icu::UnicodeString* string = e.snext(status);
-    if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
-      return false;
-    }
-    std::string s;
-    string->toUTF8String(s);
-    if (s.find_first_of("+,") == std::string::npos) {
-      result.push_back(s);
-    }
-  }
-
-  return true;
-}
-
-static const char* getICUCanonicalName(const char* name) {
-  UErrorCode error = U_ZERO_ERROR;
-  const char* canonicalName = NULL;
-  if ((canonicalName = ucnv_getCanonicalName(name, "MIME", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getCanonicalName(name, "IANA", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getCanonicalName(name, "", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getAlias(name, 0, &error)) != NULL) {
-    // We have some aliases in the form x-blah .. match those first.
-    return canonicalName;
-  } else if (strstr(name, "x-") == name) {
-    // Check if the converter can be opened with the name given.
-    error = U_ZERO_ERROR;
-    icu::LocalUConverterPointer cnv(ucnv_open(name + 2, &error));
-    if (U_SUCCESS(error)) {
-      return name + 2;
-    }
-  }
-  return NULL;
-}
-
-// If a charset listed in the IANA Charset Registry is supported by an implementation
-// of the Java platform then its canonical name must be the name listed in the registry.
-// Many charsets are given more than one name in the registry, in which case the registry
-// identifies one of the names as MIME-preferred. If a charset has more than one registry
-// name then its canonical name must be the MIME-preferred name and the other names in
-// the registry must be valid aliases. If a supported charset is not listed in the IANA
-// registry then its canonical name must begin with one of the strings "X-" or "x-".
-static jstring getJavaCanonicalName(JNIEnv* env, const char* icuCanonicalName) {
-  UErrorCode status = U_ZERO_ERROR;
-
-  // Check to see if this is a well-known MIME or IANA name.
-  const char* cName = NULL;
-  if ((cName = ucnv_getStandardName(icuCanonicalName, "MIME", &status)) != NULL) {
-    return env->NewStringUTF(cName);
-  } else if ((cName = ucnv_getStandardName(icuCanonicalName, "IANA", &status)) != NULL) {
-    return env->NewStringUTF(cName);
-  }
-
-  // Check to see if an alias already exists with "x-" prefix, if yes then
-  // make that the canonical name.
-  int32_t aliasCount = ucnv_countAliases(icuCanonicalName, &status);
-  for (int i = 0; i < aliasCount; ++i) {
-    const char* name = ucnv_getAlias(icuCanonicalName, i, &status);
-    if (name != NULL && name[0] == 'x' && name[1] == '-') {
-      return env->NewStringUTF(name);
-    }
-  }
-
-  // As a last resort, prepend "x-" to any alias and make that the canonical name.
-  status = U_ZERO_ERROR;
-  const char* name = ucnv_getStandardName(icuCanonicalName, "UTR22", &status);
-  if (name == NULL && strchr(icuCanonicalName, ',') != NULL) {
-    name = ucnv_getAlias(icuCanonicalName, 1, &status);
-  }
-  // If there is no UTR22 canonical name then just return the original name.
-  if (name == NULL) {
-    name = icuCanonicalName;
-  }
-  std::unique_ptr<char[]> result(new char[2 + strlen(name) + 1]);
-  strcpy(&result[0], "x-");
-  strcat(&result[0], name);
-  return env->NewStringUTF(&result[0]);
-}
-
-// Returns a canonical ICU converter name which may have a version number appended to it, based on
-// the normal canonical name. This is used to determine the actual native converter to use (the
-// normal unversioned name is used to determine the aliases and the Java name).
-static char const * getVersionedIcuCanonicalName(char const * icuCanonicalName) {
-  if (strcmp(icuCanonicalName, "UTF-16") == 0) {
-    // The ICU UTF-16 converter encodes strings as platform-endian bytes with a BOM. The
-    // UTF-16,version=2 one encodes as big-endian with a BOM, as what the Charset javadoc requires.
-    return "UTF-16,version=2";
-  } else {
-    return icuCanonicalName;
-  }
-}
-
-static jlong NativeConverter_openConverter(JNIEnv* env, jclass, jstring converterName) {
-    ScopedUtfChars converterNameChars(env, converterName);
-    if (converterNameChars.c_str() == NULL) {
-        // Extra debugging check that we do have an exception if the we could not
-        // create a string. See b/62612946.
-        if (env->ExceptionCheck()) {
-            return 0;
-        }
-        maybeThrowIcuException(env, "openConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return 0;
-    }
-    UErrorCode status = U_ZERO_ERROR;
-    UConverter* cnv = ucnv_open(converterNameChars.c_str(), &status);
-    maybeThrowIcuException(env, "ucnv_open", status);
-    if (env->ExceptionCheck()) {
-        return 0;
-    }
-    if (cnv == NULL) {
-        // Extra debugging exception in case cnv is null but ICU did not report
-        // an error. See b/62612946.
-        maybeThrowIcuException(env, "openConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return 0;
-    }
-    return reinterpret_cast<uintptr_t>(cnv);
-}
-
-static void NativeConverter_closeConverter(JNIEnv*, jclass, jlong address) {
-    ucnv_close(toUConverter(address));
-}
-
-static bool shouldCodecThrow(jboolean flush, UErrorCode error) {
-    if (flush) {
-        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_TRUNCATED_CHAR_FOUND);
-    } else {
-        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_INVALID_CHAR_FOUND && error != U_ILLEGAL_CHAR_FOUND);
-    }
-}
-
-static jint NativeConverter_encode(JNIEnv* env, jclass, jlong address,
-        jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd,
-        jintArray data, jboolean flush) {
-
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedCharArrayRO uSource(env, source);
-    if (uSource.get() == NULL) {
-        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedByteArrayRW uTarget(env, target);
-    if (uTarget.get() == NULL) {
-        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedIntArrayRW myData(env, data);
-    if (myData.get() == NULL) {
-        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    // Do the conversion.
-    jint* sourceOffset = &myData[0];
-    jint* targetOffset = &myData[1];
-    const jchar* mySource = uSource.get() + *sourceOffset;
-    const UChar* mySourceLimit= reinterpret_cast<const UChar*>(uSource.get()) + sourceEnd;
-    char* cTarget = reinterpret_cast<char*>(uTarget.get() + *targetOffset);
-    const char* cTargetLimit = reinterpret_cast<const char*>(uTarget.get() + targetEnd);
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_fromUnicode(cnv, &cTarget, cTargetLimit, reinterpret_cast<const UChar**>(&mySource), mySourceLimit, NULL, (UBool) flush, &errorCode);
-    *sourceOffset = (mySource - uSource.get()) - *sourceOffset;
-    *targetOffset = (reinterpret_cast<jbyte*>(cTarget) - uTarget.get());
-
-    // If there was an error, count the problematic characters.
-    if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND ||
-        errorCode == U_TRUNCATED_CHAR_FOUND) {
-        int8_t invalidUCharCount = 32;
-        UChar invalidUChars[32];
-        UErrorCode minorErrorCode = U_ZERO_ERROR;
-        ucnv_getInvalidUChars(cnv, invalidUChars, &invalidUCharCount, &minorErrorCode);
-        if (U_SUCCESS(minorErrorCode)) {
-            myData[2] = invalidUCharCount;
-        }
-    }
-
-    // Managed code handles some cases; throw all other errors.
-    if (shouldCodecThrow(flush, errorCode)) {
-        maybeThrowIcuException(env, "ucnv_fromUnicode", errorCode);
-    }
-    return errorCode;
-}
-
-static jint NativeConverter_decode(JNIEnv* env, jclass, jlong address,
-        jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd,
-        jintArray data, jboolean flush) {
-
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedByteArrayRO uSource(env, source);
-    if (uSource.get() == NULL) {
-        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedCharArrayRW uTarget(env, target);
-    if (uTarget.get() == NULL) {
-        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedIntArrayRW myData(env, data);
-    if (myData.get() == NULL) {
-        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    // Do the conversion.
-    jint* sourceOffset = &myData[0];
-    jint* targetOffset = &myData[1];
-    const char* mySource = reinterpret_cast<const char*>(uSource.get() + *sourceOffset);
-    const char* mySourceLimit = reinterpret_cast<const char*>(uSource.get() + sourceEnd);
-    UChar* cTarget = reinterpret_cast<UChar*>(uTarget.get()) + *targetOffset;
-    const UChar* cTargetLimit = reinterpret_cast<UChar*>(uTarget.get()) + targetEnd;
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_toUnicode(cnv, &cTarget, cTargetLimit, &mySource, mySourceLimit, NULL, flush, &errorCode);
-    *sourceOffset = mySource - reinterpret_cast<const char*>(uSource.get()) - *sourceOffset;
-    *targetOffset = cTarget - reinterpret_cast<UChar*>(uTarget.get()) - *targetOffset;
-
-    // If there was an error, count the problematic bytes.
-    if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND ||
-        errorCode == U_TRUNCATED_CHAR_FOUND) {
-        int8_t invalidByteCount = 32;
-        char invalidBytes[32] = {'\0'};
-        UErrorCode minorErrorCode = U_ZERO_ERROR;
-        ucnv_getInvalidChars(cnv, invalidBytes, &invalidByteCount, &minorErrorCode);
-        if (U_SUCCESS(minorErrorCode)) {
-            myData[2] = invalidByteCount;
-        }
-    }
-
-    // Managed code handles some cases; throw all other errors.
-    if (shouldCodecThrow(flush, errorCode)) {
-        maybeThrowIcuException(env, "ucnv_toUnicode", errorCode);
-    }
-    return errorCode;
-}
-
-static void NativeConverter_resetByteToChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv) {
-        ucnv_resetToUnicode(cnv);
-    }
-}
-
-static void NativeConverter_resetCharToByte(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv) {
-        ucnv_resetFromUnicode(cnv);
-    }
-}
-
-static jint NativeConverter_getMaxBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ucnv_getMaxCharSize(cnv) : -1;
-}
-
-static jint NativeConverter_getMinBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ucnv_getMinCharSize(cnv) : -1;
-}
-
-static jfloat NativeConverter_getAveBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ((ucnv_getMaxCharSize(cnv) + ucnv_getMinCharSize(cnv)) / 2.0) : -1;
-}
-
-static jobjectArray NativeConverter_getAvailableCharsetNames(JNIEnv* env, jclass) {
-    int32_t num = ucnv_countAvailable();
-    jobjectArray result = env->NewObjectArray(num, JniConstants::GetStringClass(env), NULL);
-    if (result == NULL) {
-        return NULL;
-    }
-    for (int i = 0; i < num; ++i) {
-        const char* name = ucnv_getAvailableName(i);
-        ScopedLocalRef<jstring> javaCanonicalName(env, getJavaCanonicalName(env, name));
-        if (javaCanonicalName.get() == NULL) {
-            return NULL;
-        }
-        env->SetObjectArrayElement(result, i, javaCanonicalName.get());
-        if (env->ExceptionCheck()) {
-            return NULL;
-        }
-    }
-    return result;
-}
-
-static void CHARSET_ENCODER_CALLBACK(const void* rawContext, UConverterFromUnicodeArgs* args,
-        const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason,
-        UErrorCode* status) {
-    if (!rawContext) {
-        return;
-    }
-    const EncoderCallbackContext* ctx = reinterpret_cast<const EncoderCallbackContext*>(rawContext);
-    switch(reason) {
-    case UCNV_UNASSIGNED:
-        ctx->onUnmappableInput(ctx, args, codeUnits, length, codePoint, reason, status);
-        return;
-    case UCNV_ILLEGAL:
-    case UCNV_IRREGULAR:
-        ctx->onMalformedInput(ctx, args, codeUnits, length, codePoint, reason, status);
-        return;
-    case UCNV_CLOSE:
-        delete ctx;
-        return;
-    default:
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
-}
-
-static void encoderReplaceCallback(const void* rawContext,
-        UConverterFromUnicodeArgs* fromArgs, const UChar*, int32_t, UChar32,
-        UConverterCallbackReason, UErrorCode * err) {
-    if (rawContext == NULL) {
-        return;
-    }
-    const EncoderCallbackContext* context = reinterpret_cast<const EncoderCallbackContext*>(rawContext);
-    *err = U_ZERO_ERROR;
-    ucnv_cbFromUWriteBytes(fromArgs, context->replacementBytes, context->replacementByteCount, 0, err);
-}
-
-static UConverterFromUCallback getFromUCallback(int32_t mode) {
-    switch(mode) {
-    case NativeConverter_IGNORE: return UCNV_FROM_U_CALLBACK_SKIP;
-    case NativeConverter_REPLACE: return encoderReplaceCallback;
-    case NativeConverter_REPORT: return UCNV_FROM_U_CALLBACK_STOP;
-    }
-    abort();
-}
-
-static void NativeConverter_setCallbackEncode(JNIEnv* env, jclass, jlong address,
-        jint onMalformedInput, jint onUnmappableInput, jbyteArray javaReplacement) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-
-    UConverterFromUCallback oldCallback = NULL;
-    const void* oldCallbackContext = NULL;
-    ucnv_getFromUCallBack(cnv, &oldCallback, const_cast<const void**>(&oldCallbackContext));
-
-    EncoderCallbackContext* callbackContext = const_cast<EncoderCallbackContext*>(
-            reinterpret_cast<const EncoderCallbackContext*>(oldCallbackContext));
-    // Hold the reference to any new callbackContext we create in a unique_ptr
-    // so that the default behavior is to collect it automatically if we exit
-    // early.
-    std::unique_ptr<EncoderCallbackContext> callbackContextDeleter;
-    if (callbackContext == NULL) {
-        callbackContext = new EncoderCallbackContext;
-        callbackContextDeleter.reset(callbackContext);
-    }
-
-    callbackContext->onMalformedInput = getFromUCallback(onMalformedInput);
-    callbackContext->onUnmappableInput = getFromUCallback(onUnmappableInput);
-
-    ScopedByteArrayRO replacementBytes(env, javaReplacement);
-    if (replacementBytes.get() == NULL
-            || replacementBytes.size() > sizeof(callbackContext->replacementBytes)) {
-        maybeThrowIcuException(env, "replacementBytes", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-    memcpy(callbackContext->replacementBytes, replacementBytes.get(), replacementBytes.size());
-    callbackContext->replacementByteCount = replacementBytes.size();
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_setFromUCallBack(cnv, CHARSET_ENCODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    // Iff callbackContextDeleter holds a reference to a callbackContext we can
-    // prevent it being automatically deleted here as responsibility for deletion
-    // has passed to the code that closes the NativeConverter.
-    callbackContextDeleter.release();
-    maybeThrowIcuException(env, "ucnv_setFromUCallBack", errorCode);
-}
-
-static void decoderIgnoreCallback(const void*, UConverterToUnicodeArgs*, const char*, int32_t, UConverterCallbackReason, UErrorCode* err) {
-    // The icu4c UCNV_FROM_U_CALLBACK_SKIP callback requires that the context is NULL, which is
-    // never true for us.
-    *err = U_ZERO_ERROR;
-}
-
-static void decoderReplaceCallback(const void* rawContext,
-        UConverterToUnicodeArgs* toArgs, const char*, int32_t, UConverterCallbackReason,
-        UErrorCode* err) {
-    if (!rawContext) {
-        return;
-    }
-    const DecoderCallbackContext* context = reinterpret_cast<const DecoderCallbackContext*>(rawContext);
-    *err = U_ZERO_ERROR;
-    ucnv_cbToUWriteUChars(toArgs,context->replacementChars, context->replacementCharCount, 0, err);
-}
-
-static UConverterToUCallback getToUCallback(int32_t mode) {
-    switch (mode) {
-    case NativeConverter_IGNORE: return decoderIgnoreCallback;
-    case NativeConverter_REPLACE: return decoderReplaceCallback;
-    case NativeConverter_REPORT: return UCNV_TO_U_CALLBACK_STOP;
-    }
-    abort();
-}
-
-static void CHARSET_DECODER_CALLBACK(const void* rawContext, UConverterToUnicodeArgs* args,
-        const char* codeUnits, int32_t length,
-        UConverterCallbackReason reason, UErrorCode* status) {
-    if (!rawContext) {
-        return;
-    }
-    const DecoderCallbackContext* ctx = reinterpret_cast<const DecoderCallbackContext*>(rawContext);
-    switch(reason) {
-    case UCNV_UNASSIGNED:
-        ctx->onUnmappableInput(ctx, args, codeUnits, length, reason, status);
-        return;
-    case UCNV_ILLEGAL:
-    case UCNV_IRREGULAR:
-        ctx->onMalformedInput(ctx, args, codeUnits, length, reason, status);
-        return;
-    case UCNV_CLOSE:
-        delete ctx;
-        return;
-    default:
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
-}
-
-static void NativeConverter_setCallbackDecode(JNIEnv* env, jclass, jlong address,
-        jint onMalformedInput, jint onUnmappableInput, jstring javaReplacement) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-
-    UConverterToUCallback oldCallback;
-    const void* oldCallbackContext;
-    ucnv_getToUCallBack(cnv, &oldCallback, &oldCallbackContext);
-
-    DecoderCallbackContext* callbackContext = const_cast<DecoderCallbackContext*>(
-            reinterpret_cast<const DecoderCallbackContext*>(oldCallbackContext));
-    // Hold the reference to any new callbackContext we create in a unique_ptr
-    // so that the default behavior is to collect it automatically if we exit
-    // early.
-    std::unique_ptr<DecoderCallbackContext> callbackContextDeleter;
-    if (callbackContext == NULL) {
-        callbackContext = new DecoderCallbackContext;
-        callbackContextDeleter.reset(callbackContext);
-    }
-
-    callbackContext->onMalformedInput = getToUCallback(onMalformedInput);
-    callbackContext->onUnmappableInput = getToUCallback(onUnmappableInput);
-
-    ScopedStringChars replacement(env, javaReplacement);
-    if (replacement.get() == NULL
-                || replacement.size() > sizeof(callbackContext->replacementChars) / sizeof(UChar)) {
-        maybeThrowIcuException(env, "replacement", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-    u_strncpy(callbackContext->replacementChars, reinterpret_cast<const UChar*>(replacement.get()), replacement.size());
-    callbackContext->replacementCharCount = replacement.size();
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_setToUCallBack(cnv, CHARSET_DECODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    // Iff callbackContextDeleter holds a reference to a callbackContext we can
-    // prevent it being automatically deleted here as responsibility for deletion
-    // has passed to the code that closes the NativeConverter.
-    callbackContextDeleter.release();
-    maybeThrowIcuException(env, "ucnv_setToUCallBack", errorCode);
-}
-
-static jfloat NativeConverter_getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) {
-    return (1 / (jfloat) NativeConverter_getMaxBytesPerChar(env, NULL, handle));
-}
-
-static jbyteArray NativeConverter_getSubstitutionBytes(JNIEnv* env, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        return NULL;
-    }
-    UErrorCode status = U_ZERO_ERROR;
-    char replacementBytes[MAX_REPLACEMENT_LENGTH];
-    int8_t len = sizeof(replacementBytes);
-    ucnv_getSubstChars(cnv, replacementBytes, &len, &status);
-    if (!U_SUCCESS(status)) {
-        return env->NewByteArray(0);
-    }
-    jbyteArray result = env->NewByteArray(len);
-    if (result == NULL) {
-        return NULL;
-    }
-    env->SetByteArrayRegion(result, 0, len, reinterpret_cast<jbyte*>(replacementBytes));
-    return result;
-}
-
-static jboolean NativeConverter_contains(JNIEnv* env, jclass, jstring name1, jstring name2) {
-    ScopedUtfChars name1Chars(env, name1);
-    if (name1Chars.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-    ScopedUtfChars name2Chars(env, name2);
-    if (name2Chars.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    icu::LocalUConverterPointer converter1(ucnv_open(name1Chars.c_str(), &errorCode));
-    icu::UnicodeSet set1;
-    ucnv_getUnicodeSet(&*converter1, set1.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
-
-    icu::LocalUConverterPointer converter2(ucnv_open(name2Chars.c_str(), &errorCode));
-    icu::UnicodeSet set2;
-    ucnv_getUnicodeSet(&*converter2, set2.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
-
-    return U_SUCCESS(errorCode) && set1.containsAll(set2);
-}
-
-static jobject NativeConverter_charsetForName(JNIEnv* env, jclass, jstring charsetName) {
-    ScopedUtfChars charsetNameChars(env, charsetName);
-    if (charsetNameChars.c_str() == NULL) {
-        return NULL;
-    }
-
-    // Get ICU's canonical name for this charset.
-    const char* icuCanonicalName = getICUCanonicalName(charsetNameChars.c_str());
-    if (icuCanonicalName == NULL) {
-        return NULL;
-    }
-
-    // Get Java's canonical name for this charset.
-    jstring javaCanonicalName = getJavaCanonicalName(env, icuCanonicalName);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    // Check that this charset is supported.
-    {
-        // ICU doesn't offer any "isSupported", so we just open and immediately close.
-        UErrorCode error = U_ZERO_ERROR;
-        icu::LocalUConverterPointer cnv(ucnv_open(icuCanonicalName, &error));
-        if (!U_SUCCESS(error)) {
-            return NULL;
-        }
-    }
-
-    // Get the aliases for this charset.
-    std::vector<std::string> aliases;
-    if (!collectStandardNames(env, icuCanonicalName, "IANA", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "MIME", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "JAVA", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "WINDOWS", aliases)) {
-        return NULL;
-    }
-    jobjectArray javaAliases = toStringArray(env, aliases);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    // Construct the CharsetICU object.
-    static jmethodID charsetConstructor = env->GetMethodID(JniConstants::GetCharsetICUClass(env), "<init>",
-            "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V");
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    char const * versionedIcuCanonicalName = getVersionedIcuCanonicalName(icuCanonicalName);
-    jstring versionedIcuCanonicalNameStr = env->NewStringUTF(versionedIcuCanonicalName);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    return env->NewObject(JniConstants::GetCharsetICUClass(env), charsetConstructor,
-            javaCanonicalName, versionedIcuCanonicalNameStr, javaAliases);
-}
-
-static void FreeNativeConverter(void *converter) {
-    ucnv_close(reinterpret_cast<UConverter*>(converter));
-}
-
-static jlong NativeConverter_getNativeFinalizer(JNIEnv*, jclass) {
-    return reinterpret_cast<jlong>(&FreeNativeConverter);
-}
-
-static jlong NativeConverter_getNativeSize(JNIEnv*, jclass) {
-    // TODO: Improve estimate.
-    return 200;
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(NativeConverter, charsetForName, "(Ljava/lang/String;)Ljava/nio/charset/Charset;"),
-    NATIVE_METHOD(NativeConverter, closeConverter, "(J)V"),
-    NATIVE_METHOD(NativeConverter, contains, "(Ljava/lang/String;Ljava/lang/String;)Z"),
-    NATIVE_METHOD(NativeConverter, decode, "(J[BI[CI[IZ)I"),
-    NATIVE_METHOD(NativeConverter, encode, "(J[CI[BI[IZ)I"),
-    NATIVE_METHOD(NativeConverter, getAvailableCharsetNames, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(NativeConverter, getAveBytesPerChar, "(J)F"),
-    NATIVE_METHOD(NativeConverter, getAveCharsPerByte, "(J)F"),
-    NATIVE_METHOD(NativeConverter, getMaxBytesPerChar, "(J)I"),
-    NATIVE_METHOD(NativeConverter, getMinBytesPerChar, "(J)I"),
-    NATIVE_METHOD(NativeConverter, getSubstitutionBytes, "(J)[B"),
-    NATIVE_METHOD(NativeConverter, openConverter, "(Ljava/lang/String;)J"),
-    NATIVE_METHOD(NativeConverter, resetByteToChar, "(J)V"),
-    NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"),
-    NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"),
-    NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"),
-    NATIVE_METHOD(NativeConverter, getNativeFinalizer, "()J"),
-    NATIVE_METHOD(NativeConverter, getNativeSize, "()J")
-};
-void register_libcore_icu_NativeConverter(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/test/java/libcore/libcore/util/FP16Test.java b/luni/src/test/java/libcore/libcore/util/FP16Test.java
new file mode 100644
index 0000000..d2a136c
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/util/FP16Test.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2019 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.libcore.util;
+
+import static libcore.util.FP16.*;
+import libcore.util.FP16;
+
+import junit.framework.TestCase;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class FP16Test extends TestCase {
+
+    public void testSingleToHalf() {
+        // Zeroes, NaN and infinities
+        assertEquals(POSITIVE_ZERO, toHalf(0.0f));
+        assertEquals(NEGATIVE_ZERO, toHalf(-0.0f));
+        assertEquals(NaN, toHalf(Float.NaN));
+        assertEquals(POSITIVE_INFINITY, toHalf(Float.POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, toHalf(Float.NEGATIVE_INFINITY));
+        // Known values
+        assertEquals((short) 0x3c01, toHalf(1.0009765625f));
+        assertEquals((short) 0xc000, toHalf(-2.0f));
+        assertEquals((short) 0x0400, toHalf(6.10352e-5f));
+        assertEquals((short) 0x7bff, toHalf(65504.0f));
+        assertEquals((short) 0x3555, toHalf(1.0f / 3.0f));
+        // Subnormals
+        assertEquals((short) 0x03ff, toHalf(6.09756e-5f));
+        assertEquals(MIN_VALUE, toHalf(5.96046e-8f));
+        assertEquals((short) 0x83ff, toHalf(-6.09756e-5f));
+        assertEquals((short) 0x8001, toHalf(-5.96046e-8f));
+        // Subnormals (flushed to +/-0)
+        assertEquals(POSITIVE_ZERO, toHalf(5.96046e-9f));
+        assertEquals(NEGATIVE_ZERO, toHalf(-5.96046e-9f));
+        // Test for values that overflow the mantissa bits into exp bits
+        assertEquals((short) 0x1000, toHalf(Float.intBitsToFloat(0x39fff000)));
+        assertEquals((short) 0x0400, toHalf(Float.intBitsToFloat(0x387fe000)));
+        // Floats with absolute value above +/-65519 are rounded to +/-inf
+        // when using round-to-even
+        assertEquals((short) 0x7bff, toHalf(65519.0f));
+        assertEquals((short) 0x7bff, toHalf(65519.9f));
+        assertEquals(POSITIVE_INFINITY, toHalf(65520.0f));
+        assertEquals(NEGATIVE_INFINITY, toHalf(-65520.0f));
+        // Check if numbers are rounded to nearest even when they
+        // cannot be accurately represented by Half
+        assertEquals((short) 0x6800, toHalf(2049.0f));
+        assertEquals((short) 0x6c00, toHalf(4098.0f));
+        assertEquals((short) 0x7000, toHalf(8196.0f));
+        assertEquals((short) 0x7400, toHalf(16392.0f));
+        assertEquals((short) 0x7800, toHalf(32784.0f));
+    }
+
+    public void testHalfToSingle() {
+        // Zeroes, NaN and infinities
+        assertEquals(0.0f, toFloat(toHalf(0.0f)), 0.0f);
+        assertEquals(-0.0f, toFloat(toHalf(-0.0f)), 0.0f);
+        assertEquals(Float.NaN, toFloat(toHalf(Float.NaN)), 0.0f);
+        assertEquals(Float.POSITIVE_INFINITY, toFloat(toHalf(Float.POSITIVE_INFINITY)), 0.0f);
+        assertEquals(Float.NEGATIVE_INFINITY, toFloat(toHalf(Float.NEGATIVE_INFINITY)), 0.0f);
+        // Known values
+        assertEquals(1.0009765625f, toFloat(toHalf(1.0009765625f)), 0.0f);
+        assertEquals(-2.0f, toFloat(toHalf(-2.0f)), 0.0f);
+        assertEquals(6.1035156e-5f, toFloat(toHalf(6.10352e-5f)), 0.0f); // Inexact
+        assertEquals(65504.0f, toFloat(toHalf(65504.0f)), 0.0f);
+        assertEquals(0.33325195f, toFloat(toHalf(1.0f / 3.0f)), 0.0f); // Inexact
+        // Denormals (flushed to +/-0)
+        assertEquals(6.097555e-5f, toFloat(toHalf(6.09756e-5f)), 0.0f);
+        assertEquals(5.9604645e-8f, toFloat(toHalf(5.96046e-8f)), 0.0f);
+        assertEquals(-6.097555e-5f, toFloat(toHalf(-6.09756e-5f)), 0.0f);
+        assertEquals(-5.9604645e-8f, toFloat(toHalf(-5.96046e-8f)), 0.0f);
+    }
+
+    public void testHexString() {
+        assertEquals("NaN", toHexString(NaN));
+        assertEquals("Infinity", toHexString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", toHexString(NEGATIVE_INFINITY));
+        assertEquals("0x0.0p0", toHexString(POSITIVE_ZERO));
+        assertEquals("-0x0.0p0", toHexString(NEGATIVE_ZERO));
+        assertEquals("0x1.0p0", toHexString(toHalf(1.0f)));
+        assertEquals("-0x1.0p0", toHexString(toHalf(-1.0f)));
+        assertEquals("0x1.0p1", toHexString(toHalf(2.0f)));
+        assertEquals("0x1.0p8", toHexString(toHalf(256.0f)));
+        assertEquals("0x1.0p-1", toHexString(toHalf(0.5f)));
+        assertEquals("0x1.0p-2", toHexString(toHalf(0.25f)));
+        assertEquals("0x1.3ffp15", toHexString(MAX_VALUE));
+        assertEquals("0x0.1p-14", toHexString(MIN_VALUE));
+        assertEquals("0x1.0p-14", toHexString(MIN_NORMAL));
+        assertEquals("-0x1.3ffp15", toHexString(LOWEST_VALUE));
+    }
+
+    public void testIsInfinite() {
+        assertTrue(FP16.isInfinite(POSITIVE_INFINITY));
+        assertTrue(FP16.isInfinite(NEGATIVE_INFINITY));
+        assertFalse(FP16.isInfinite(POSITIVE_ZERO));
+        assertFalse(FP16.isInfinite(NEGATIVE_ZERO));
+        assertFalse(FP16.isInfinite(NaN));
+        assertFalse(FP16.isInfinite(MAX_VALUE));
+        assertFalse(FP16.isInfinite(LOWEST_VALUE));
+        assertFalse(FP16.isInfinite(toHalf(-128.3f)));
+        assertFalse(FP16.isInfinite(toHalf(128.3f)));
+    }
+
+    public void testIsNaN() {
+        assertFalse(FP16.isNaN(POSITIVE_INFINITY));
+        assertFalse(FP16.isNaN(NEGATIVE_INFINITY));
+        assertFalse(FP16.isNaN(POSITIVE_ZERO));
+        assertFalse(FP16.isNaN(NEGATIVE_ZERO));
+        assertTrue(FP16.isNaN(NaN));
+        assertTrue(FP16.isNaN((short) 0x7c01));
+        assertTrue(FP16.isNaN((short) 0x7c18));
+        assertTrue(FP16.isNaN((short) 0xfc01));
+        assertTrue(FP16.isNaN((short) 0xfc98));
+        assertFalse(FP16.isNaN(MAX_VALUE));
+        assertFalse(FP16.isNaN(LOWEST_VALUE));
+        assertFalse(FP16.isNaN(toHalf(-128.3f)));
+        assertFalse(FP16.isNaN(toHalf(128.3f)));
+    }
+
+    public void testIsNormalized() {
+        assertFalse(FP16.isNormalized(POSITIVE_INFINITY));
+        assertFalse(FP16.isNormalized(NEGATIVE_INFINITY));
+        assertFalse(FP16.isNormalized(POSITIVE_ZERO));
+        assertFalse(FP16.isNormalized(NEGATIVE_ZERO));
+        assertFalse(FP16.isNormalized(NaN));
+        assertTrue(FP16.isNormalized(MAX_VALUE));
+        assertTrue(FP16.isNormalized(MIN_NORMAL));
+        assertTrue(FP16.isNormalized(LOWEST_VALUE));
+        assertTrue(FP16.isNormalized(toHalf(-128.3f)));
+        assertTrue(FP16.isNormalized(toHalf(128.3f)));
+        assertTrue(FP16.isNormalized(toHalf(0.3456f)));
+        assertFalse(FP16.isNormalized(MIN_VALUE));
+        assertFalse(FP16.isNormalized((short) 0x3ff));
+        assertFalse(FP16.isNormalized((short) 0x200));
+        assertFalse(FP16.isNormalized((short) 0x100));
+    }
+
+    public void testCeil() {
+        assertEquals(POSITIVE_INFINITY, FP16.ceil(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.ceil(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.ceil(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.ceil(NaN));
+        assertEquals(LOWEST_VALUE, FP16.ceil(LOWEST_VALUE));
+        assertEquals(1.0f, toFloat(FP16.ceil(MIN_NORMAL)), 0.0f);
+        assertEquals(1.0f, toFloat(FP16.ceil((short) 0x3ff)), 0.0f);
+        assertEquals(1.0f, toFloat(FP16.ceil(toHalf(0.2f))), 0.0f);
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(toHalf(-0.2f)));
+        assertEquals(1.0f, toFloat(FP16.ceil(toHalf(0.7f))), 0.0f);
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(toHalf(-0.7f)));
+        assertEquals(125.0f, toFloat(FP16.ceil(toHalf(124.7f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.ceil(toHalf(-124.7f))), 0.0f);
+        assertEquals(125.0f, toFloat(FP16.ceil(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.ceil(toHalf(-124.2f))), 0.0f);
+    }
+
+    public void testEquals() {
+        assertTrue(FP16.equals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.equals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.equals(POSITIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(FP16.equals(NEGATIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(FP16.equals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.equals(NaN, toHalf(12.4f)));
+        assertFalse(FP16.equals(toHalf(12.4f), NaN));
+        assertFalse(FP16.equals(NaN, NaN));
+        assertTrue(FP16.equals(toHalf(12.4f), toHalf(12.4f)));
+        assertTrue(FP16.equals(toHalf(-12.4f), toHalf(-12.4f)));
+        assertFalse(FP16.equals(toHalf(12.4f), toHalf(0.7f)));
+    }
+
+    public void testFloor() {
+        assertEquals(POSITIVE_INFINITY, FP16.floor(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.floor(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.floor(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.floor(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.floor(NaN));
+        assertEquals(LOWEST_VALUE, FP16.floor(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.floor(MIN_NORMAL));
+        assertEquals(POSITIVE_ZERO, FP16.floor((short) 0x3ff));
+        assertEquals(POSITIVE_ZERO, FP16.floor(toHalf(0.2f)));
+        assertEquals(-1.0f, toFloat(FP16.floor(toHalf(-0.2f))), 0.0f);
+        assertEquals(-1.0f, toFloat(FP16.floor(toHalf(-0.7f))), 0.0f);
+        assertEquals(POSITIVE_ZERO, FP16.floor(toHalf(0.7f)));
+        assertEquals(124.0f, toFloat(FP16.floor(toHalf(124.7f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.floor(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.floor(toHalf(124.2f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.floor(toHalf(-124.2f))), 0.0f);
+        // floor for NaN values
+        assertEquals((short) 0x7e01, FP16.floor((short) 0x7c01));
+        assertEquals((short) 0x7f00, FP16.floor((short) 0x7d00));
+        assertEquals((short) 0xfe01, FP16.floor((short) 0xfc01));
+        assertEquals((short) 0xff00, FP16.floor((short) 0xfd00));
+    }
+
+    public void testRint() {
+        assertEquals(POSITIVE_INFINITY, FP16.rint(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.rint(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.rint(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.rint(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.rint(NaN));
+        assertEquals(LOWEST_VALUE, FP16.rint(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.rint(MIN_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.rint((short) 0x200));
+        assertEquals(POSITIVE_ZERO, FP16.rint((short) 0x3ff));
+        assertEquals(POSITIVE_ZERO, FP16.rint(toHalf(0.2f)));
+        assertEquals(NEGATIVE_ZERO, FP16.rint(toHalf(-0.2f)));
+        assertEquals(1.0f, toFloat(FP16.rint(toHalf(0.7f))), 0.0f);
+        assertEquals(-1.0f, toFloat(FP16.rint(toHalf(-0.7f))), 0.0f);
+        assertEquals(1.0f, toFloat(FP16.rint(toHalf(0.5f))), 0.0f);
+        assertEquals(-1.0f, toFloat(FP16.rint(toHalf(-0.5f))), 0.0f);
+        assertEquals(125.0f, toFloat(FP16.rint(toHalf(124.7f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.rint(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.rint(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.rint(toHalf(-124.2f))), 0.0f);
+    }
+
+    public void testTrunc() {
+        assertEquals(POSITIVE_INFINITY, FP16.trunc(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.trunc(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.trunc(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.trunc(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.trunc(NaN));
+        assertEquals(LOWEST_VALUE, FP16.trunc(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.trunc(toHalf(0.2f)));
+        assertEquals(NEGATIVE_ZERO, FP16.trunc(toHalf(-0.2f)));
+        assertEquals(0.0f, toFloat(FP16.trunc(toHalf(0.7f))), 0.0f);
+        assertEquals(-0.0f, toFloat(FP16.trunc(toHalf(-0.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.trunc(toHalf(124.7f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.trunc(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.trunc(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.trunc(toHalf(-124.2f))), 0.0f);
+    }
+
+    public void testLess() {
+        assertTrue(FP16.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.less(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.less(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.less(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.less(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertFalse(FP16.less(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.less(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.less(NaN, toHalf(12.3f)));
+        assertFalse(FP16.less(toHalf(12.3f), NaN));
+        assertTrue(FP16.less(MIN_VALUE, MIN_NORMAL));
+        assertFalse(FP16.less(MIN_NORMAL, MIN_VALUE));
+        assertTrue(FP16.less(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.less(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.less(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.less(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.less(MIN_VALUE, (short) 0x3ff));
+    }
+
+    public void testLessEquals() {
+        assertTrue(FP16.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.lessEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.lessEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.lessEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.lessEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(FP16.lessEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.lessEquals(NaN, toHalf(12.3f)));
+        assertFalse(FP16.lessEquals(toHalf(12.3f), NaN));
+        assertTrue(FP16.lessEquals(MIN_VALUE, MIN_NORMAL));
+        assertFalse(FP16.lessEquals(MIN_NORMAL, MIN_VALUE));
+        assertTrue(FP16.lessEquals(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.lessEquals(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.lessEquals(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.lessEquals(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.less(MIN_VALUE, (short) 0x3ff));
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
+        assertTrue(FP16.lessEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+    }
+
+    public void testGreater() {
+        assertTrue(FP16.greater(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.greater(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.greater(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.greater(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.greater(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertFalse(FP16.greater(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.greater(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.greater(toHalf(12.3f), NaN));
+        assertFalse(FP16.greater(NaN, toHalf(12.3f)));
+        assertTrue(FP16.greater(MIN_NORMAL, MIN_VALUE));
+        assertFalse(FP16.greater(MIN_VALUE, MIN_NORMAL));
+        assertTrue(FP16.greater(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.greater(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.greater(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.greater(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.greater((short) 0x3ff, MIN_VALUE));
+    }
+
+    public void testGreaterEquals() {
+        assertTrue(FP16.greaterEquals(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.greaterEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.greaterEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.greaterEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(FP16.greaterEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.greaterEquals(toHalf(12.3f), NaN));
+        assertFalse(FP16.greaterEquals(NaN, toHalf(12.3f)));
+        assertTrue(FP16.greaterEquals(MIN_NORMAL, MIN_VALUE));
+        assertFalse(FP16.greaterEquals(MIN_VALUE, MIN_NORMAL));
+        assertTrue(FP16.greaterEquals(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.greaterEquals(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.greaterEquals(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.greaterEquals(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.greater((short) 0x3ff, MIN_VALUE));
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
+        assertTrue(FP16.lessEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+    }
+
+    public void testMin() {
+        assertEquals(NEGATIVE_INFINITY, FP16.min(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(NEGATIVE_ZERO, FP16.min(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.min(NaN, LOWEST_VALUE));
+        assertEquals(NaN, FP16.min(LOWEST_VALUE, NaN));
+        assertEquals(NEGATIVE_INFINITY, FP16.min(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertEquals(MAX_VALUE, FP16.min(POSITIVE_INFINITY, MAX_VALUE));
+        assertEquals(MIN_VALUE, FP16.min(MIN_VALUE, MIN_NORMAL));
+        assertEquals(POSITIVE_ZERO, FP16.min(MIN_VALUE, POSITIVE_ZERO));
+        assertEquals(POSITIVE_ZERO, FP16.min(MIN_NORMAL, POSITIVE_ZERO));
+        assertEquals(toHalf(-3.456f), FP16.min(toHalf(-3.456f), toHalf(-3.453f)));
+        assertEquals(toHalf(3.453f), FP16.min(toHalf(3.456f), toHalf(3.453f)));
+    }
+
+    public void testMax() {
+        assertEquals(POSITIVE_INFINITY, FP16.max(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.max(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.max(NaN, MAX_VALUE));
+        assertEquals(NaN, FP16.max(MAX_VALUE, NaN));
+        assertEquals(LOWEST_VALUE, FP16.max(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertEquals(POSITIVE_INFINITY, FP16.max(POSITIVE_INFINITY, MAX_VALUE));
+        assertEquals(MIN_NORMAL, FP16.max(MIN_VALUE, MIN_NORMAL));
+        assertEquals(MIN_VALUE, FP16.max(MIN_VALUE, POSITIVE_ZERO));
+        assertEquals(MIN_NORMAL, FP16.max(MIN_NORMAL, POSITIVE_ZERO));
+        assertEquals(toHalf(-3.453f), FP16.max(toHalf(-3.456f), toHalf(-3.453f)));
+        assertEquals(toHalf(3.456f), FP16.max(toHalf(3.456f), toHalf(3.453f)));
+    }
+
+    public void testCompare() {
+        assertEquals(0, FP16.compare(NaN, NaN));
+        assertEquals(0, FP16.compare(NaN, (short) 0xfc98));
+        assertEquals(1, FP16.compare(NaN, POSITIVE_INFINITY));
+        assertEquals(-1, FP16.compare(POSITIVE_INFINITY, NaN));
+
+        assertEquals(0, FP16.compare(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertEquals(0, FP16.compare(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(1, FP16.compare(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(-1, FP16.compare(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+
+        assertEquals(0, FP16.compare(POSITIVE_ZERO, POSITIVE_ZERO));
+        assertEquals(0, FP16.compare(NEGATIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(1, FP16.compare(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(-1, FP16.compare(NEGATIVE_ZERO, POSITIVE_ZERO));
+
+        assertEquals(0, FP16.compare(toHalf(12.462f), toHalf(12.462f)));
+        assertEquals(0, FP16.compare(toHalf(-12.462f), toHalf(-12.462f)));
+        assertEquals(1, FP16.compare(toHalf(12.462f), toHalf(-12.462f)));
+        assertEquals(-1, FP16.compare(toHalf(-12.462f), toHalf(12.462f)));
+    }
+}
diff --git a/mmodules/intracoreapi/api/intra/current-api.txt b/mmodules/intracoreapi/api/intra/current-api.txt
index 46a1298..666c47d 100644
--- a/mmodules/intracoreapi/api/intra/current-api.txt
+++ b/mmodules/intracoreapi/api/intra/current-api.txt
@@ -89,6 +89,22 @@
 
 }
 
+package java.nio.charset {
+
+  public abstract class Charset implements java.lang.Comparable<java.nio.charset.Charset> {
+    ctor @libcore.api.IntraCoreApi protected Charset(String, String[]);
+  }
+
+  public abstract class CharsetDecoder {
+    ctor protected CharsetDecoder(java.nio.charset.Charset, float, float);
+  }
+
+  public abstract class CharsetEncoder {
+    ctor protected CharsetEncoder(java.nio.charset.Charset, float, float, byte[], boolean);
+  }
+
+}
+
 package java.security.spec {
 
   public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
@@ -110,7 +126,7 @@
 
 package libcore.icu {
 
-  @libcore.api.IntraCoreApi @libcore.api.CorePlatformApi public final class ICU {
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class ICU {
     method @libcore.api.IntraCoreApi public static String getIcuVersion();
   }
 
diff --git a/non_openjdk_java_files.bp b/non_openjdk_java_files.bp
index 53b17c1..47ef822 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -176,9 +176,6 @@
         "luni/src/main/java/java/net/DefaultFileNameMap.java",
         "luni/src/main/java/java/nio/NIOAccess.java",
         "luni/src/main/java/java/nio/NioUtils.java",
-        "luni/src/main/java/java/nio/charset/CharsetDecoderICU.java",
-        "luni/src/main/java/java/nio/charset/CharsetEncoderICU.java",
-        "luni/src/main/java/java/nio/charset/CharsetICU.java",
         "luni/src/main/java/javax/xml/XMLConstants.java",
         "luni/src/main/java/javax/xml/datatype/DatatypeConfigurationException.java",
         "luni/src/main/java/javax/xml/datatype/DatatypeConstants.java",
@@ -377,7 +374,6 @@
         "luni/src/main/java/libcore/icu/CollationKeyICU.java",
         "luni/src/main/java/libcore/icu/DateTimeFormat.java",
         "luni/src/main/java/libcore/icu/DateUtilsBridge.java",
-        "luni/src/main/java/libcore/icu/NativeConverter.java",
         "luni/src/main/java/libcore/internal/Java9LanguageFeatures.java",
         "luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java",
         "luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java",
diff --git a/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java b/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java
new file mode 100644
index 0000000..ed0f378
--- /dev/null
+++ b/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetDecoder {
+
+@libcore.api.IntraCoreApi
+protected CharsetDecoder(java.nio.charset.Charset cs, float averageCharsPerByte, float maxCharsPerByte) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder replaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final float maxCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult decode(java.nio.ByteBuffer in, java.nio.CharBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out);
+
+public final java.nio.CharBuffer decode(java.nio.ByteBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean isAutoDetecting() { throw new RuntimeException("Stub!"); }
+
+public boolean isCharsetDetected() { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.Charset detectedCharset() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java b/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java
new file mode 100644
index 0000000..ceb323e
--- /dev/null
+++ b/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetEncoder {
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) { throw new RuntimeException("Stub!"); }
+
+@libcore.api.IntraCoreApi
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, boolean trusted) { throw new RuntimeException("Stub!"); }
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final byte[] replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder replaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+public boolean isLegalReplacement(byte[] repl) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final float maxBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult encode(java.nio.CharBuffer in, java.nio.ByteBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out);
+
+public final java.nio.ByteBuffer encode(java.nio.CharBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(char c) { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(java.lang.CharSequence cs) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/src/main/java/java/lang/invoke/Transformers.java b/ojluni/src/main/java/java/lang/invoke/Transformers.java
index fc8727a..390b2e7 100644
--- a/ojluni/src/main/java/java/lang/invoke/Transformers.java
+++ b/ojluni/src/main/java/java/lang/invoke/Transformers.java
@@ -417,7 +417,7 @@
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
-            final Class<?> receiverType = type().rtype();
+            final Class<?> receiverType = constructorHandle.type().parameterType(0);
             checkInstantiable(receiverType);
 
             // Allocate memory for receiver.
diff --git a/ojluni/src/main/java/java/nio/charset/Charset.java b/ojluni/src/main/java/java/nio/charset/Charset.java
index f5c097e..517c94e 100755
--- a/ojluni/src/main/java/java/nio/charset/Charset.java
+++ b/ojluni/src/main/java/java/nio/charset/Charset.java
@@ -27,12 +27,11 @@
 package java.nio.charset;
 
 import java.io.UnsupportedEncodingException;
-import libcore.icu.NativeConverter;
+import com.android.icu.charset.NativeConverter;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.spi.CharsetProvider;
 import java.security.AccessController;
-import java.security.AccessControlException;
 import java.security.PrivilegedAction;
 import java.util.AbstractMap;
 import java.util.Collections;
@@ -686,6 +685,7 @@
      * @throws IllegalCharsetNameException
      *         If the canonical name or any of the aliases are illegal
      */
+    @libcore.api.IntraCoreApi
     protected Charset(String canonicalName, String[] aliases) {
         checkName(canonicalName);
         String[] as = (aliases == null) ? new String[0] : aliases;
diff --git a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
index 540199e..98b4dea 100644
--- a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
+++ b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
@@ -197,8 +197,9 @@
      * This constructor is for subclasses to specify whether {@code replacement} can be used as it
      * is ("trusted"). If it is trusted, {@link #replaceWith(byte[])} and
      * {@link #implReplaceWith(byte[])} will not be called.
+     * @hide
      */
-    CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement,
+    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement,
             boolean trusted)
     {
         // END Android-added: A hidden constructor for the CharsetEncoderICU subclass.