8026049: (bf) Intrinsify ByteBuffer.put{Int, Double, Float, ...} methods
authoraph
Tue, 31 Mar 2015 12:30:52 -0700
changeset 30338 957ee8b5a33a
parent 30337 5d0420f699df
child 30339 ebd762f09224
8026049: (bf) Intrinsify ByteBuffer.put{Int, Double, Float, ...} methods Summary: Use unaligned Unsafe loads and stores for ByteBuffer access on platforms which support unaligned access. Add intrinsics for Unsafe.{get,put}-X-Unaligned methods. Reviewed-by: dholmes, jrose, psandoz, kvn
jdk/src/java.base/share/classes/java/nio/Bits.java
jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
jdk/src/java.base/share/classes/sun/misc/Unsafe.java
jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java
--- a/jdk/src/java.base/share/classes/java/nio/Bits.java	Fri Mar 27 09:02:55 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/nio/Bits.java	Tue Mar 31 12:30:52 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, 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
@@ -567,32 +567,13 @@
 
     // -- Processor and memory-system properties --
 
-    private static final ByteOrder byteOrder;
+    private static final ByteOrder byteOrder
+        = unsafe.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
 
     static ByteOrder byteOrder() {
-        if (byteOrder == null)
-            throw new Error("Unknown byte order");
         return byteOrder;
     }
 
-    static {
-        long a = unsafe.allocateMemory(8);
-        try {
-            unsafe.putLong(a, 0x0102030405060708L);
-            byte b = unsafe.getByte(a);
-            switch (b) {
-            case 0x01: byteOrder = ByteOrder.BIG_ENDIAN;     break;
-            case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN;  break;
-            default:
-                assert false;
-                byteOrder = null;
-            }
-        } finally {
-            unsafe.freeMemory(a);
-        }
-    }
-
-
     private static int pageSize = -1;
 
     static int pageSize() {
@@ -605,17 +586,9 @@
         return (int)(size + (long)pageSize() - 1L) / pageSize();
     }
 
-    private static boolean unaligned;
-    private static boolean unalignedKnown = false;
+    private static boolean unaligned = unsafe.unalignedAccess();
 
     static boolean unaligned() {
-        if (unalignedKnown)
-            return unaligned;
-        String arch = AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("os.arch"));
-        unaligned = arch.equals("i386") || arch.equals("x86")
-            || arch.equals("amd64") || arch.equals("x86_64");
-        unalignedKnown = true;
         return unaligned;
     }
 
--- a/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template	Fri Mar 27 09:02:55 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template	Tue Mar 31 12:30:52 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, 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
@@ -27,6 +27,7 @@
 
 package java.nio;
 
+import sun.misc.Unsafe;
 
 /**
 #if[rw]
@@ -52,6 +53,16 @@
 #end[rw]
     */
 
+#if[byte]
+
+    // Cached unsafe-access object
+    private static final Unsafe unsafe = Bits.unsafe();
+
+    // Cached array base offset
+    private static final long arrayBaseOffset = unsafe.arrayBaseOffset($type$[].class);
+
+#end[byte]
+
     Heap$Type$Buffer$RW$(int cap, int lim) {            // package-private
 #if[rw]
         super(-1, 0, lim, cap, new $type$[cap], 0);
@@ -131,6 +142,12 @@
         return i + offset;
     }
 
+#if[byte]
+    private long byteOffset(long i) {
+        return arrayBaseOffset + i + offset;
+    }
+#end[byte]
+
     public $type$ get() {
         return hb[ix(nextGetIndex())];
     }
@@ -256,18 +273,18 @@
 #if[rw]
 
     public char getChar() {
-        return Bits.getChar(this, ix(nextGetIndex(2)), bigEndian);
+        return unsafe.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
     }
 
     public char getChar(int i) {
-        return Bits.getChar(this, ix(checkIndex(i, 2)), bigEndian);
+        return unsafe.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
     }
 
 #end[rw]
 
     public $Type$Buffer putChar(char x) {
 #if[rw]
-        Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian);
+        unsafe.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -276,7 +293,7 @@
 
     public $Type$Buffer putChar(int i, char x) {
 #if[rw]
-        Bits.putChar(this, ix(checkIndex(i, 2)), x, bigEndian);
+        unsafe.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -307,18 +324,18 @@
 #if[rw]
 
     public short getShort() {
-        return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian);
+        return unsafe.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
     }
 
     public short getShort(int i) {
-        return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian);
+        return unsafe.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
     }
 
 #end[rw]
 
     public $Type$Buffer putShort(short x) {
 #if[rw]
-        Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian);
+        unsafe.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -327,7 +344,7 @@
 
     public $Type$Buffer putShort(int i, short x) {
 #if[rw]
-        Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian);
+        unsafe.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -358,18 +375,18 @@
 #if[rw]
 
     public int getInt() {
-        return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian);
+        return unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
     }
 
     public int getInt(int i) {
-        return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian);
+        return unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
     }
 
 #end[rw]
 
     public $Type$Buffer putInt(int x) {
 #if[rw]
-        Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian);
+        unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -378,7 +395,7 @@
 
     public $Type$Buffer putInt(int i, int x) {
 #if[rw]
-        Bits.putInt(this, ix(checkIndex(i, 4)), x, bigEndian);
+        unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -409,18 +426,18 @@
 #if[rw]
 
     public long getLong() {
-        return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
+        return unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
     }
 
     public long getLong(int i) {
-        return Bits.getLong(this, ix(checkIndex(i, 8)), bigEndian);
+        return unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
     }
 
 #end[rw]
 
     public $Type$Buffer putLong(long x) {
 #if[rw]
-        Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian);
+        unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -429,7 +446,7 @@
 
     public $Type$Buffer putLong(int i, long x) {
 #if[rw]
-        Bits.putLong(this, ix(checkIndex(i, 8)), x, bigEndian);
+        unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -460,18 +477,21 @@
 #if[rw]
 
     public float getFloat() {
-        return Bits.getFloat(this, ix(nextGetIndex(4)), bigEndian);
+        int x = unsafe.getIntUnaligned(hb, byteOffset(nextPutIndex(4)), bigEndian);
+        return Float.intBitsToFloat(x);
     }
 
     public float getFloat(int i) {
-        return Bits.getFloat(this, ix(checkIndex(i, 4)), bigEndian);
+        int x = unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
+        return Float.intBitsToFloat(x);
     }
 
 #end[rw]
 
     public $Type$Buffer putFloat(float x) {
 #if[rw]
-        Bits.putFloat(this, ix(nextPutIndex(4)), x, bigEndian);
+        int y = Float.floatToRawIntBits(x);
+        unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -480,7 +500,8 @@
 
     public $Type$Buffer putFloat(int i, float x) {
 #if[rw]
-        Bits.putFloat(this, ix(checkIndex(i, 4)), x, bigEndian);
+        int y = Float.floatToRawIntBits(x);
+        unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -511,18 +532,21 @@
 #if[rw]
 
     public double getDouble() {
-        return Bits.getDouble(this, ix(nextGetIndex(8)), bigEndian);
+        long x = unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
+        return Double.longBitsToDouble(x);
     }
 
     public double getDouble(int i) {
-        return Bits.getDouble(this, ix(checkIndex(i, 8)), bigEndian);
+        long x = unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
+        return Double.longBitsToDouble(x);
     }
 
 #end[rw]
 
     public $Type$Buffer putDouble(double x) {
 #if[rw]
-        Bits.putDouble(this, ix(nextPutIndex(8)), x, bigEndian);
+        long y = Double.doubleToRawLongBits(x);
+        unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
@@ -531,7 +555,8 @@
 
     public $Type$Buffer putDouble(int i, double x) {
 #if[rw]
-        Bits.putDouble(this, ix(checkIndex(i, 8)), x, bigEndian);
+        long y = Double.doubleToRawLongBits(x);
+        unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
         return this;
 #else[rw]
         throw new ReadOnlyBufferException();
--- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java	Fri Mar 27 09:02:55 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java	Tue Mar 31 12:30:52 2015 -0700
@@ -934,4 +934,347 @@
     private static void throwIllegalAccessError() {
         throw new IllegalAccessError();
     }
+
+    /**
+     * @return Returns true if the native byte ordering of this
+     * platform is big-endian, false if it is little-endian.
+     */
+    public final boolean isBigEndian() { return BE; }
+
+    /**
+     * @return Returns true if this platform is capable of performing
+     * accesses at addresses which are not aligned for the type of the
+     * primitive type being accessed, false otherwise.
+     */
+    public final boolean unalignedAccess() { return unalignedAccess; }
+
+    /**
+     * Fetches a value at some byte offset into a given Java object.
+     * More specifically, fetches a value within the given object
+     * <code>o</code> at the given offset, or (if <code>o</code> is
+     * null) from the memory address whose numerical value is the
+     * given offset.  <p>
+     *
+     * The specification of this method is the same as {@link
+     * #getLong(Object, long)} except that the offset does not need to
+     * have been obtained from {@link #objectFieldOffset} on the
+     * {@link java.lang.reflect.Field} of some Java field.  The value
+     * in memory is raw data, and need not correspond to any Java
+     * variable.  Unless <code>o</code> is null, the value accessed
+     * must be entirely within the allocated object.  The endianness
+     * of the value in memory is the endianness of the native platform.
+     *
+     * <p> The read will be atomic with respect to the largest power
+     * of two that divides the GCD of the offset and the storage size.
+     * For example, getLongUnaligned will make atomic reads of 2-, 4-,
+     * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
+     * respectively.  There are no other guarantees of atomicity.
+     * <p>
+     * 8-byte atomicity is only guaranteed on platforms on which
+     * support atomic accesses to longs.
+     *
+     * @param o Java heap object in which the value resides, if any, else
+     *        null
+     * @param offset The offset in bytes from the start of the object
+     * @return the value fetched from the indicated object
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     * @since 1.9
+     */
+    public final long getLongUnaligned(Object o, long offset) {
+        if ((offset & 7) == 0) {
+            return getLong(o, offset);
+        } else if ((offset & 3) == 0) {
+            return makeLong(getInt(o, offset),
+                            getInt(o, offset + 4));
+        } else if ((offset & 1) == 0) {
+            return makeLong(getShort(o, offset),
+                            getShort(o, offset + 2),
+                            getShort(o, offset + 4),
+                            getShort(o, offset + 6));
+        } else {
+            return makeLong(getByte(o, offset),
+                            getByte(o, offset + 1),
+                            getByte(o, offset + 2),
+                            getByte(o, offset + 3),
+                            getByte(o, offset + 4),
+                            getByte(o, offset + 5),
+                            getByte(o, offset + 6),
+                            getByte(o, offset + 7));
+        }
+    }
+    /**
+     * As {@link #getLongUnaligned(Object, long)} but with an
+     * additional argument which specifies the endianness of the value
+     * as stored in memory.
+     *
+     * @param o Java heap object in which the variable resides
+     * @param offset The offset in bytes from the start of the object
+     * @param bigEndian The endianness of the value
+     * @return the value fetched from the indicated object
+     * @since 1.9
+     */
+    public final long getLongUnaligned(Object o, long offset, boolean bigEndian) {
+        return convEndian(bigEndian, getLongUnaligned(o, offset));
+    }
+
+    /** @see #getLongUnaligned(Object, long) */
+    public final int getIntUnaligned(Object o, long offset) {
+        if ((offset & 3) == 0) {
+            return getInt(o, offset);
+        } else if ((offset & 1) == 0) {
+            return makeInt(getShort(o, offset),
+                           getShort(o, offset + 2));
+        } else {
+            return makeInt(getByte(o, offset),
+                           getByte(o, offset + 1),
+                           getByte(o, offset + 2),
+                           getByte(o, offset + 3));
+        }
+    }
+    /** @see #getLongUnaligned(Object, long, boolean) */
+    public final int getIntUnaligned(Object o, long offset, boolean bigEndian) {
+        return convEndian(bigEndian, getIntUnaligned(o, offset));
+    }
+
+    /** @see #getLongUnaligned(Object, long) */
+    public final short getShortUnaligned(Object o, long offset) {
+        if ((offset & 1) == 0) {
+            return getShort(o, offset);
+        } else {
+            return makeShort(getByte(o, offset),
+                             getByte(o, offset + 1));
+        }
+    }
+    /** @see #getLongUnaligned(Object, long, boolean) */
+    public final short getShortUnaligned(Object o, long offset, boolean bigEndian) {
+        return convEndian(bigEndian, getShortUnaligned(o, offset));
+    }
+
+    /** @see #getLongUnaligned(Object, long) */
+    public final char getCharUnaligned(Object o, long offset) {
+        return (char)getShortUnaligned(o, offset);
+    }
+    /** @see #getLongUnaligned(Object, long, boolean) */
+    public final char getCharUnaligned(Object o, long offset, boolean bigEndian) {
+        return convEndian(bigEndian, getCharUnaligned(o, offset));
+    }
+
+    /**
+     * Stores a value at some byte offset into a given Java object.
+     * <p>
+     * The specification of this method is the same as {@link
+     * #getLong(Object, long)} except that the offset does not need to
+     * have been obtained from {@link #objectFieldOffset} on the
+     * {@link java.lang.reflect.Field} of some Java field.  The value
+     * in memory is raw data, and need not correspond to any Java
+     * variable.  The endianness of the value in memory is the
+     * endianness of the native platform.
+     * <p>
+     * The write will be atomic with respect to the largest power of
+     * two that divides the GCD of the offset and the storage size.
+     * For example, putLongUnaligned will make atomic writes of 2-, 4-,
+     * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
+     * respectively.  There are no other guarantees of atomicity.
+     * <p>
+     * 8-byte atomicity is only guaranteed on platforms on which
+     * support atomic accesses to longs.
+     * <p>
+     *
+     * @param o Java heap object in which the value resides, if any, else
+     *        null
+     * @param offset The offset in bytes from the start of the object
+     * @param x the value to store
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     * @since 1.9
+     */
+    public final void putLongUnaligned(Object o, long offset, long x) {
+        if ((offset & 7) == 0) {
+            putLong(o, offset, x);
+        } else if ((offset & 3) == 0) {
+            putLongParts(o, offset,
+                         (int)(x >> 0),
+                         (int)(x >>> 32));
+        } else if ((offset & 1) == 0) {
+            putLongParts(o, offset,
+                         (short)(x >>> 0),
+                         (short)(x >>> 16),
+                         (short)(x >>> 32),
+                         (short)(x >>> 48));
+        } else {
+            putLongParts(o, offset,
+                         (byte)(x >>> 0),
+                         (byte)(x >>> 8),
+                         (byte)(x >>> 16),
+                         (byte)(x >>> 24),
+                         (byte)(x >>> 32),
+                         (byte)(x >>> 40),
+                         (byte)(x >>> 48),
+                         (byte)(x >>> 56));
+        }
+    }
+    /**
+     * As {@link #putLongUnaligned(Object, long, long)} but with an additional
+     * argument which specifies the endianness of the value as stored in memory.
+     * @param o Java heap object in which the value resides
+     * @param offset The offset in bytes from the start of the object
+     * @param x the value to store
+     * @param bigEndian The endianness of the value
+     * @throws RuntimeException No defined exceptions are thrown, not even
+     *         {@link NullPointerException}
+     * @since 1.9
+     */
+    public final void putLongUnaligned(Object o, long offset, long x, boolean bigEndian) {
+        putLongUnaligned(o, offset, convEndian(bigEndian, x));
+    }
+
+    /** @see #putLongUnaligned(Object, long, long) */
+    public final void putIntUnaligned(Object o, long offset, int x) {
+        if ((offset & 3) == 0) {
+            putInt(o, offset, x);
+        } else if ((offset & 1) == 0) {
+            putIntParts(o, offset,
+                        (short)(x >> 0),
+                        (short)(x >>> 16));
+        } else {
+            putIntParts(o, offset,
+                        (byte)(x >>> 0),
+                        (byte)(x >>> 8),
+                        (byte)(x >>> 16),
+                        (byte)(x >>> 24));
+        }
+    }
+    /** @see #putLongUnaligned(Object, long, long, boolean) */
+    public final void putIntUnaligned(Object o, long offset, int x, boolean bigEndian) {
+        putIntUnaligned(o, offset, convEndian(bigEndian, x));
+    }
+
+    /** @see #putLongUnaligned(Object, long, long) */
+    public final void putShortUnaligned(Object o, long offset, short x) {
+        if ((offset & 1) == 0) {
+            putShort(o, offset, x);
+        } else {
+            putShortParts(o, offset,
+                          (byte)(x >>> 0),
+                          (byte)(x >>> 8));
+        }
+    }
+    /** @see #putLongUnaligned(Object, long, long, boolean) */
+    public final void putShortUnaligned(Object o, long offset, short x, boolean bigEndian) {
+        putShortUnaligned(o, offset, convEndian(bigEndian, x));
+    }
+
+    /** @see #putLongUnaligned(Object, long, long) */
+    public final void putCharUnaligned(Object o, long offset, char x) {
+        putShortUnaligned(o, offset, (short)x);
+    }
+    /** @see #putLongUnaligned(Object, long, long, boolean) */
+    public final void putCharUnaligned(Object o, long offset, char x, boolean bigEndian) {
+        putCharUnaligned(o, offset, convEndian(bigEndian, x));
+    }
+
+    // JVM interface methods
+    private native boolean unalignedAccess0();
+    private native boolean isBigEndian0();
+
+    // BE is true iff the native endianness of this platform is big.
+    private static final boolean BE = theUnsafe.isBigEndian0();
+
+    // unalignedAccess is true iff this platform can perform unaligned accesses.
+    private static final boolean unalignedAccess = theUnsafe.unalignedAccess0();
+
+    private static int pickPos(int top, int pos) { return BE ? top - pos : pos; }
+
+    // These methods construct integers from bytes.  The byte ordering
+    // is the native endianness of this platform.
+    private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+        return ((toUnsignedLong(i0) << pickPos(56, 0))
+              | (toUnsignedLong(i1) << pickPos(56, 8))
+              | (toUnsignedLong(i2) << pickPos(56, 16))
+              | (toUnsignedLong(i3) << pickPos(56, 24))
+              | (toUnsignedLong(i4) << pickPos(56, 32))
+              | (toUnsignedLong(i5) << pickPos(56, 40))
+              | (toUnsignedLong(i6) << pickPos(56, 48))
+              | (toUnsignedLong(i7) << pickPos(56, 56)));
+    }
+    private static long makeLong(short i0, short i1, short i2, short i3) {
+        return ((toUnsignedLong(i0) << pickPos(48, 0))
+              | (toUnsignedLong(i1) << pickPos(48, 16))
+              | (toUnsignedLong(i2) << pickPos(48, 32))
+              | (toUnsignedLong(i3) << pickPos(48, 48)));
+    }
+    private static long makeLong(int i0, int i1) {
+        return (toUnsignedLong(i0) << pickPos(32, 0))
+             | (toUnsignedLong(i1) << pickPos(32, 32));
+    }
+    private static int makeInt(short i0, short i1) {
+        return (toUnsignedInt(i0) << pickPos(16, 0))
+             | (toUnsignedInt(i1) << pickPos(16, 16));
+    }
+    private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
+        return ((toUnsignedInt(i0) << pickPos(24, 0))
+              | (toUnsignedInt(i1) << pickPos(24, 8))
+              | (toUnsignedInt(i2) << pickPos(24, 16))
+              | (toUnsignedInt(i3) << pickPos(24, 24)));
+    }
+    private static short makeShort(byte i0, byte i1) {
+        return (short)((toUnsignedInt(i0) << pickPos(8, 0))
+                     | (toUnsignedInt(i1) << pickPos(8, 8)));
+    }
+
+    private static byte  pick(byte  le, byte  be) { return BE ? be : le; }
+    private static short pick(short le, short be) { return BE ? be : le; }
+    private static int   pick(int   le, int   be) { return BE ? be : le; }
+
+    // These methods write integers to memory from smaller parts
+    // provided by their caller.  The ordering in which these parts
+    // are written is the native endianness of this platform.
+    private void putLongParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+        putByte(o, offset + 0, pick(i0, i7));
+        putByte(o, offset + 1, pick(i1, i6));
+        putByte(o, offset + 2, pick(i2, i5));
+        putByte(o, offset + 3, pick(i3, i4));
+        putByte(o, offset + 4, pick(i4, i3));
+        putByte(o, offset + 5, pick(i5, i2));
+        putByte(o, offset + 6, pick(i6, i1));
+        putByte(o, offset + 7, pick(i7, i0));
+    }
+    private void putLongParts(Object o, long offset, short i0, short i1, short i2, short i3) {
+        putShort(o, offset + 0, pick(i0, i3));
+        putShort(o, offset + 2, pick(i1, i2));
+        putShort(o, offset + 4, pick(i2, i1));
+        putShort(o, offset + 6, pick(i3, i0));
+    }
+    private void putLongParts(Object o, long offset, int i0, int i1) {
+        putInt(o, offset + 0, pick(i0, i1));
+        putInt(o, offset + 4, pick(i1, i0));
+    }
+    private void putIntParts(Object o, long offset, short i0, short i1) {
+        putShort(o, offset + 0, pick(i0, i1));
+        putShort(o, offset + 2, pick(i1, i0));
+    }
+    private void putIntParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3) {
+        putByte(o, offset + 0, pick(i0, i3));
+        putByte(o, offset + 1, pick(i1, i2));
+        putByte(o, offset + 2, pick(i2, i1));
+        putByte(o, offset + 3, pick(i3, i0));
+    }
+    private void putShortParts(Object o, long offset, byte i0, byte i1) {
+        putByte(o, offset + 0, pick(i0, i1));
+        putByte(o, offset + 1, pick(i1, i0));
+    }
+
+    // Zero-extend an integer
+    private static int toUnsignedInt(byte n)    { return n & 0xff; }
+    private static int toUnsignedInt(short n)   { return n & 0xffff; }
+    private static long toUnsignedLong(byte n)  { return n & 0xffl; }
+    private static long toUnsignedLong(short n) { return n & 0xffffl; }
+    private static long toUnsignedLong(int n)   { return n & 0xffffffffl; }
+
+    // Maybe byte-reverse an integer
+    private static char convEndian(boolean big, char n)   { return big == BE ? n : Character.reverseBytes(n); }
+    private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n)    ; }
+    private static int convEndian(boolean big, int n)     { return big == BE ? n : Integer.reverseBytes(n)  ; }
+    private static long convEndian(boolean big, long n)   { return big == BE ? n : Long.reverseBytes(n)     ; }
 }
--- a/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java	Fri Mar 27 09:02:55 2015 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java	Tue Mar 31 12:30:52 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, 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
@@ -88,13 +88,8 @@
 
     // Return whether this platform supports full speed int/long memory access
     // at unaligned addresses.
-    // This code was copied from java.nio.Bits because there is no equivalent
-    // public API.
     private static boolean unaligned() {
-        String arch = java.security.AccessController.doPrivileged
-            (new sun.security.action.GetPropertyAction("os.arch", ""));
-        return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64")
-            || arch.equals("x86_64");
+        return unsafe.unalignedAccess();
     }
 
     /**