1 /*
   2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.jfr.internal;
  27 
  28 import java.nio.ByteOrder;
  29 
  30 import sun.misc.Unsafe;
  31 
  32 final class Bits {                            // package-private
  33 
  34     private static final Unsafe unsafe = Unsafe.getUnsafe();
  35     // XXX TODO proper value (e.g. copy from java.nio.Bits)
  36     private static final boolean unalignedAccess = false/*unsafe.unalignedAccess()*/;
  37     private static final boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
  38 
  39     private Bits() { }
  40 
  41     // -- Swapping --
  42 
  43     private static short swap(short x) {
  44         return Short.reverseBytes(x);
  45     }
  46 
  47     private static char swap(char x) {
  48         return Character.reverseBytes(x);
  49     }
  50 
  51     private static int swap(int x) {
  52         return Integer.reverseBytes(x);
  53     }
  54 
  55     private static long swap(long x) {
  56         return Long.reverseBytes(x);
  57     }
  58 
  59     private static float swap(float x) {
  60         return Float.intBitsToFloat(swap(Float.floatToIntBits(x)));
  61     }
  62 
  63     private static double swap(double x) {
  64         return Double.longBitsToDouble(swap(Double.doubleToLongBits(x)));
  65     }
  66 
  67     // -- Alignment --
  68 
  69     private static boolean isAddressAligned(long a, int datumSize) {
  70         return (a & datumSize - 1) == 0;
  71     }
  72 
  73     // -- Primitives stored per byte
  74 
  75     private static byte char1(char x) { return (byte)(x >> 8); }
  76     private static byte char0(char x) { return (byte)(x     ); }
  77 
  78     private static byte short1(short x) { return (byte)(x >> 8); }
  79     private static byte short0(short x) { return (byte)(x     ); }
  80 
  81     private static byte int3(int x) { return (byte)(x >> 24); }
  82     private static byte int2(int x) { return (byte)(x >> 16); }
  83     private static byte int1(int x) { return (byte)(x >>  8); }
  84     private static byte int0(int x) { return (byte)(x      ); }
  85 
  86     private static byte long7(long x) { return (byte)(x >> 56); }
  87     private static byte long6(long x) { return (byte)(x >> 48); }
  88     private static byte long5(long x) { return (byte)(x >> 40); }
  89     private static byte long4(long x) { return (byte)(x >> 32); }
  90     private static byte long3(long x) { return (byte)(x >> 24); }
  91     private static byte long2(long x) { return (byte)(x >> 16); }
  92     private static byte long1(long x) { return (byte)(x >>  8); }
  93     private static byte long0(long x) { return (byte)(x      ); }
  94 
  95     private static void putCharBigEndianUnaligned(long a, char x) {
  96         putByte_(a    , char1(x));
  97         putByte_(a + 1, char0(x));
  98     }
  99 
 100     private static void putShortBigEndianUnaligned(long a, short x) {
 101         putByte_(a    , short1(x));
 102         putByte_(a + 1, short0(x));
 103     }
 104 
 105     private static void putIntBigEndianUnaligned(long a, int x) {
 106         putByte_(a    , int3(x));
 107         putByte_(a + 1, int2(x));
 108         putByte_(a + 2, int1(x));
 109         putByte_(a + 3, int0(x));
 110     }
 111 
 112     private static void putLongBigEndianUnaligned(long a, long x) {
 113         putByte_(a    , long7(x));
 114         putByte_(a + 1, long6(x));
 115         putByte_(a + 2, long5(x));
 116         putByte_(a + 3, long4(x));
 117         putByte_(a + 4, long3(x));
 118         putByte_(a + 5, long2(x));
 119         putByte_(a + 6, long1(x));
 120         putByte_(a + 7, long0(x));
 121     }
 122 
 123     private static void putFloatBigEndianUnaligned(long a, float x) {
 124         putIntBigEndianUnaligned(a, Float.floatToRawIntBits(x));
 125     }
 126 
 127     private static void putDoubleBigEndianUnaligned(long a, double x) {
 128         putLongBigEndianUnaligned(a, Double.doubleToRawLongBits(x));
 129     }
 130 
 131     private static void putByte_(long a, byte b) {
 132         unsafe.putByte(a, b);
 133     }
 134 
 135     private static void putBoolean_(long a, boolean x) {
 136         unsafe.putBoolean(null, a, x);
 137     }
 138 
 139     private static void putChar_(long a, char x) {
 140         unsafe.putChar(a, bigEndian ? x : swap(x));
 141     }
 142 
 143     private static void putShort_(long a, short x) {
 144         unsafe.putShort(a, bigEndian ? x : swap(x));
 145     }
 146 
 147     private static void putInt_(long a, int x) {
 148         unsafe.putInt(a, bigEndian ? x : swap(x));
 149     }
 150 
 151     private static void putLong_(long a, long x) {
 152         unsafe.putLong(a, bigEndian ? x : swap(x));
 153     }
 154 
 155     private static void putFloat_(long a, float x) {
 156         unsafe.putFloat(a, bigEndian ? x : swap(x));
 157     }
 158 
 159     private static void putDouble_(long a, double x) {
 160         unsafe.putDouble(a, bigEndian ? x : swap(x));
 161     }
 162 
 163     // external api
 164     static int putByte(long a, byte x) {
 165         putByte_(a, x);
 166         return Byte.BYTES;
 167     }
 168 
 169     static int putBoolean(long a, boolean x) {
 170         putBoolean_(a, x);
 171         return Byte.BYTES;
 172     }
 173 
 174     static int putChar(long a, char x) {
 175         if (unalignedAccess || isAddressAligned(a, Character.BYTES)) {
 176             putChar_(a, x);
 177             return Character.BYTES;
 178         }
 179         putCharBigEndianUnaligned(a, x);
 180         return Character.BYTES;
 181     }
 182 
 183     static int putShort(long a, short x) {
 184         if (unalignedAccess || isAddressAligned(a, Short.BYTES)) {
 185             putShort_(a, x);
 186             return Short.BYTES;
 187         }
 188         putShortBigEndianUnaligned(a, x);
 189         return Short.BYTES;
 190     }
 191 
 192     static int putInt(long a, int x) {
 193         if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
 194             putInt_(a, x);
 195             return Integer.BYTES;
 196         }
 197         putIntBigEndianUnaligned(a, x);
 198         return Integer.BYTES;
 199     }
 200 
 201     static int putLong(long a, long x) {
 202          if (unalignedAccess || isAddressAligned(a, Long.BYTES)) {
 203             putLong_(a, x);
 204             return Long.BYTES;
 205         }
 206         putLongBigEndianUnaligned(a, x);
 207         return Long.BYTES;
 208     }
 209 
 210     static int putFloat(long a, float x) {
 211         if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
 212             putFloat_(a, x);
 213             return Float.BYTES;
 214         }
 215         putFloatBigEndianUnaligned(a, x);
 216         return Float.BYTES;
 217     }
 218 
 219     static int putDouble(long a, double x) {
 220         if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
 221             putDouble_(a, x);
 222             return Double.BYTES;
 223         }
 224         putDoubleBigEndianUnaligned(a, x);
 225         return Double.BYTES;
 226     }
 227 }