src/java.base/share/classes/sun/misc/Unsafe.java

Print this page

        

@@ -1141,6 +1141,319 @@
      */
     private static void throwIllegalAccessError() {
        throw new IllegalAccessError();
     }
 
+    public final static boolean LITTLE_ENDIAN = false;
+    public final static boolean BIG_ENDIAN = true;
+    
+    public native boolean getByteOrder();
+
+    public native boolean unalignedAccess();
+
+    public long getLongUnaligned(Object o, long offset) {
+        if ((offset & 7) == 0) {
+            return getLong(o, offset);
+        } else if ((offset & 3) == 0) {
+            return mem.makeLong(getInt(o, offset),
+                                getInt(o, offset + 4));
+        } else if ((offset & 1) == 0) {
+            return mem.makeLong(getShort(o, offset),
+                                getShort(o, offset + 2),
+                                getShort(o, offset + 4),
+                                getShort(o, offset + 6));
+        } else {
+            return mem.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));
+}
+    }
+    public long getLongUnaligned(Object o, long offset, boolean bigEndian) {
+        return mem.fromEndian(bigEndian, getLongUnaligned(o, offset));
+    }
+        
+    public int getIntUnaligned(Object o, long offset) {
+        if ((offset & 3) == 0) {
+            return getInt(o, offset);
+        } else if ((offset & 1) == 0) {
+            return mem.makeInt(getShort(o, offset),
+                               getShort(o, offset + 2));
+        } else {
+            return mem.makeInt(getByte(o, offset),
+                               getByte(o, offset + 1),
+                               getByte(o, offset + 2),
+                               getByte(o, offset + 3));
+        }
+    }
+    public int getIntUnaligned(Object o, long offset, boolean bigEndian) {
+        return mem.fromEndian(bigEndian, getIntUnaligned(o, offset));
+    }
+    
+    public short getShortUnaligned(Object o, long offset) {
+        if ((offset & 1) == 0) {
+            return getShort(o, offset);
+        } else {
+            return mem.makeShort(getByte(o, offset),
+                                 getByte(o, offset + 1));
+        }
+    }
+    public short getShortUnaligned(Object o, long offset, boolean bigEndian) {
+        return mem.fromEndian(bigEndian, getShortUnaligned(o, offset));
+    }
+
+    public char getCharUnaligned(Object o, long offset) {
+        return (char)getShortUnaligned(o, offset);
+    }
+    public char getCharUnaligned(Object o, long offset, boolean bigEndian) {
+        return mem.fromEndian(bigEndian, getCharUnaligned(o, offset));
+    }
+
+    public void putLongUnaligned(Object o, long offset, long x) {
+        if ((offset & 7) == 0) {
+            putLong(o, offset, x);
+        } else if ((offset & 3) == 0) {
+            mem.putLongParts(this, o, offset,
+                             (int)(x >> 0),
+                             (int)(x >>> 32));
+        } else if ((offset & 1) == 0) {
+            mem.putLongParts(this, o, offset,
+                             (short)(x >>> 0),
+                             (short)(x >>> 16),
+                             (short)(x >>> 32),
+                             (short)(x >>> 48));
+        } else {
+            mem.putLongParts(this, 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));
+        }
+    }
+
+    public void putIntUnaligned(Object o, long offset, int x) {
+        if ((offset & 3) == 0) {
+            putInt(o, offset, x);
+        } else if ((offset & 1) == 0) {
+            mem.putIntParts(this, o, offset,
+                            (short)(x >> 0),
+                            (short)(x >>> 16));
+        } else {
+            mem.putIntParts(this, o, offset, 
+                            (byte)(x >>> 0),
+                            (byte)(x >>> 8),
+                            (byte)(x >>> 16),
+                            (byte)(x >>> 24));
+        }
+    }
+
+    public void putShortUnaligned(Object o, long offset, short x) {
+        if ((offset & 1) == 0) {
+            putShort(o, offset, x);
+        } else {
+            mem.putShortParts(this, o, offset, 
+                              (byte)(x >>> 0),
+                              (byte)(x >>> 8));
+        }
+    }
+
+    public void putCharUnaligned(Object o, long offset, char x) {
+        putShortUnaligned(o, offset, (short)x);
+    }
+
+    private static final boolean byteOrder = theUnsafe.getByteOrder();
+
+    private static final NativeAccess mem
+        = (byteOrder == LITTLE_ENDIAN) ? new NativeLittleEndian() : new NativeBigEndian();
+
+    private abstract static class NativeAccess {
+        // Native-enianness-dependent scatter/gather methods for integer types
+        abstract long makeLong(int i0, int i1);
+        abstract long makeLong(short i0, short i1, short i2, short i3);
+        abstract long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7);
+        abstract int makeInt(short i0, short i1);
+        abstract int makeInt(byte i0, byte i1, byte i2, byte i3);
+        abstract short makeShort(byte i0, byte i1);
+
+        abstract void putLongParts(Unsafe theUnsafe, Object o, long offset, int i0, int i1);
+        abstract void putLongParts(Unsafe theUnsafe, Object o, long offset,
+                                   short i0, short i1, short i2, short i3);
+        abstract void putLongParts(Unsafe theUnsafe, Object o, long offset,
+                                   byte i0, byte i1, byte i2, byte i3, byte i4,
+                                   byte i5, byte i6, byte i7);
+        abstract void putIntParts(Unsafe theUnsafe, Object o, long offset, short i0, short i1);
+        abstract void putIntParts(Unsafe theUnsafe, Object o, long offset,
+                                  byte i0, byte i1, byte i2, byte i3);
+        abstract void putShortParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1);
+
+        // Byte-reverse an integer if necessary
+        abstract char fromEndian(boolean big, char n);
+        abstract short fromEndian(boolean big, short n);
+        abstract int fromEndian(boolean big, int n);
+        abstract long fromEndian(boolean big, long n);
+
+        // Zero-extend an integer type
+        final int toUnsignedInt(byte n) { return n & 0xff; }
+        final int toUnsignedInt(short n) { return n & 0xffff; }
+        final long toUnsignedLong(byte n) { return n & 0xffl; }
+        final long toUnsignedLong(short n) { return n & 0xffffl; }
+        final long toUnsignedLong(int n) { return n & 0xffffffffl; }
+    }
+
+    private static class NativeLittleEndian extends NativeAccess {
+        long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+            return ((toUnsignedLong(i0) << 0)
+                  | (toUnsignedLong(i1) << 8)
+                  | (toUnsignedLong(i2) << 16)
+                  | (toUnsignedLong(i3) << 24)
+                  | (toUnsignedLong(i4) << 32)
+                  | (toUnsignedLong(i5) << 40)
+                  | (toUnsignedLong(i6) << 48)
+                  | (toUnsignedLong(i7) << 56));
+        }
+        long makeLong(short i0, short i1, short i2, short i3) {
+            return ((toUnsignedLong(i0) << 0)
+                  | (toUnsignedLong(i1) << 16)
+                  | (toUnsignedLong(i2) << 32)
+                  | (toUnsignedLong(i3) << 48));
+        }
+        long makeLong(int i0, int i1) {
+            return (toUnsignedLong(i0) << 0)
+                 | (toUnsignedLong(i1) << 32);
+        }
+        int makeInt(short i0, short i1) {
+            return (toUnsignedInt(i0) << 0)
+                 | (toUnsignedInt(i1) << 16);
+        }
+        int makeInt(byte i0, byte i1, byte i2, byte i3) {
+            return ((toUnsignedInt(i0) << 0)
+                  | (toUnsignedInt(i1) << 8)
+                  | (toUnsignedInt(i2) << 16)
+                  | (toUnsignedInt(i3) << 24));
+        }
+        short makeShort(byte i0, byte i1) {
+            return (short)((toUnsignedInt(i0) << 0)
+                         | (toUnsignedInt(i1) << 8));
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+            theUnsafe.putByte(o, offset + 0, i0);
+            theUnsafe.putByte(o, offset + 1, i1);
+            theUnsafe.putByte(o, offset + 2, i2);
+            theUnsafe.putByte(o, offset + 3, i3);
+            theUnsafe.putByte(o, offset + 4, i4);
+            theUnsafe.putByte(o, offset + 5, i5);
+            theUnsafe.putByte(o, offset + 6, i6);
+            theUnsafe.putByte(o, offset + 7, i7);
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, short i0, short i1, short i2, short i3) {
+            theUnsafe.putShort(o, offset + 0, i0);
+            theUnsafe.putShort(o, offset + 2, i1);
+            theUnsafe.putShort(o, offset + 4, i2);
+            theUnsafe.putShort(o, offset + 6, i3);
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, int i0, int i1) {
+            theUnsafe.putInt(o, offset + 0, i0);
+            theUnsafe.putInt(o, offset + 4, i1);
+        }
+        void putIntParts(Unsafe theUnsafe, Object o, long offset, short i0, short i1) {
+            theUnsafe.putShort(o, offset + 0, i0);
+            theUnsafe.putShort(o, offset + 2, i1);
+        }
+        void putIntParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1, byte i2, byte i3) {
+            theUnsafe.putByte(o, offset + 0, i0);
+            theUnsafe.putByte(o, offset + 1, i1);
+            theUnsafe.putByte(o, offset + 2, i2);
+            theUnsafe.putByte(o, offset + 3, i3);
+        }
+        void putShortParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1) {
+            theUnsafe.putByte(o, offset + 0, i0);
+            theUnsafe.putByte(o, offset + 1, i1);
+        }
+        char fromEndian(boolean big, char n) { return big ? Character.reverseBytes(n) : n; }
+        short fromEndian(boolean big, short n) { return big ? Short.reverseBytes(n) : n; }
+        int fromEndian(boolean big, int n) { return big ? Integer.reverseBytes(n) : n; }
+        long fromEndian(boolean big, long n) { return big ? Long.reverseBytes(n) : n; }
+    }
+
+    private static class NativeBigEndian extends NativeAccess {
+        long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+            return ((toUnsignedLong(i0) << 56)
+                  | (toUnsignedLong(i1) << 48)
+                  | (toUnsignedLong(i2) << 40)
+                  | (toUnsignedLong(i3) << 32)
+                  | (toUnsignedLong(i4) << 24)
+                  | (toUnsignedLong(i5) << 16)
+                  | (toUnsignedLong(i6) << 8)
+                  | (toUnsignedLong(i7) << 0));
+        }
+        long makeLong(short i0, short i1, short i2, short i3) {
+            return ((toUnsignedLong(i0) << 48)
+                  | (toUnsignedLong(i1) << 32)
+                  | (toUnsignedLong(i2) << 16)
+                  | (toUnsignedLong(i3) << 0));
+        }
+        long makeLong(int i0, int i1) {
+            return (toUnsignedLong(i0) << 32)
+                 | (toUnsignedLong(i1) << 0);
+        }
+        int makeInt(byte i0, byte i1, byte i2, byte i3) {
+            return ((toUnsignedInt(i0) << 24)
+                  | (toUnsignedInt(i1) << 16)
+                  | (toUnsignedInt(i2) << 8)
+                  | (toUnsignedInt(i3) << 0));
+        }
+        int makeInt(short i0, short i1) {
+            return ((toUnsignedInt(i0) << 16)
+                  | (toUnsignedInt(i1) << 0));
+        }
+        short makeShort(byte i0, byte i1) {
+            return (short)((toUnsignedInt(i0) << 8)
+                         | (toUnsignedInt(i1) << 0));
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+            theUnsafe.putByte(o, offset + 0, i7);
+            theUnsafe.putByte(o, offset + 1, i6);
+            theUnsafe.putByte(o, offset + 2, i5);
+            theUnsafe.putByte(o, offset + 3, i4);
+            theUnsafe.putByte(o, offset + 4, i3);
+            theUnsafe.putByte(o, offset + 5, i2);
+            theUnsafe.putByte(o, offset + 6, i1);
+            theUnsafe.putByte(o, offset + 7, i0);
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, short i0, short i1, short i2, short i3) {
+            theUnsafe.putShort(o, offset + 0, i3);
+            theUnsafe.putShort(o, offset + 2, i2);
+            theUnsafe.putShort(o, offset + 4, i1);
+            theUnsafe.putShort(o, offset + 6, i0);
+        }
+        void putLongParts(Unsafe theUnsafe, Object o, long offset, int i0, int i1) {
+            theUnsafe.putInt(o, offset + 0, i1);
+            theUnsafe.putInt(o, offset + 4, i0);
+        }
+        void putIntParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1, byte i2, byte i3) {
+            theUnsafe.putByte(o, offset + 0, i3);
+            theUnsafe.putByte(o, offset + 1, i2);
+            theUnsafe.putByte(o, offset + 2, i1);
+            theUnsafe.putByte(o, offset + 3, i0);
+        }
+        void putIntParts(Unsafe theUnsafe, Object o, long offset, short i0, short i1) {
+            theUnsafe.putShort(o, offset + 0, i1);
+            theUnsafe.putShort(o, offset + 2, i0);
+        }
+        void putShortParts(Unsafe theUnsafe, Object o, long offset, byte i0, byte i1) {
+            theUnsafe.putByte(o, offset + 0, i1);
+            theUnsafe.putByte(o, offset + 1, i0);
+        }
+        char fromEndian(boolean big, char n) { return big ? n : Character.reverseBytes(n); }
+        short fromEndian(boolean big, short n) { return big ? n : Short.reverseBytes(n); }
+        int fromEndian(boolean big, int n) { return big ? n : Integer.reverseBytes(n); }
+        long fromEndian(boolean big, long n) { return big ? n : Long.reverseBytes(n); }
+    }
 }