1 /*
   2  * Copyright (c) 2016, 2019, 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 import java.security.AccessController;
  30 import sun.misc.Unsafe;
  31 
  32 final class Bits {                            // package-private
  33 
  34     private static final Unsafe unsafe = Unsafe.getUnsafe();
  35     private static final boolean unalignedAccess = unaligned();
  36     private static final boolean bigEndian = (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN);
  37 
  38     private Bits() { }
  39 
  40     private static boolean unaligned;
  41     private static boolean unalignedKnown = false;
  42 
  43     private static boolean unaligned() {
  44         if (unalignedKnown)
  45             return unaligned;
  46         String arch = AccessController.doPrivileged(
  47             new sun.security.action.GetPropertyAction("os.arch"));
  48         unaligned = arch.equals("i386") || arch.equals("x86")
  49             || arch.equals("amd64") || arch.equals("x86_64")
  50             || arch.equals("ppc64") || arch.equals("ppc64le");
  51         unalignedKnown = true;
  52         return unaligned;
  53     }
  54 
  55     // -- Swapping --
  56 
  57     private static short swap(short x) {
  58         return Short.reverseBytes(x);
  59     }
  60 
  61     private static char swap(char x) {
  62         return Character.reverseBytes(x);
  63     }
  64 
  65     private static int swap(int x) {
  66         return Integer.reverseBytes(x);
  67     }
  68 
  69     private static long swap(long x) {
  70         return Long.reverseBytes(x);
  71     }
  72 
  73     private static float swap(float x) {
  74         return Float.intBitsToFloat(swap(Float.floatToIntBits(x)));
  75     }
  76 
  77     private static double swap(double x) {
  78         return Double.longBitsToDouble(swap(Double.doubleToLongBits(x)));
  79     }
  80 
  81     // -- Alignment --
  82 
  83     private static boolean isAddressAligned(long a, int datumSize) {
  84         return (a & datumSize - 1) == 0;
  85     }
  86 
  87     // -- Primitives stored per byte
  88 
  89     private static byte char1(char x) { return (byte)(x >> 8); }
  90     private static byte char0(char x) { return (byte)(x     ); }
  91 
  92     private static byte short1(short x) { return (byte)(x >> 8); }
  93     private static byte short0(short x) { return (byte)(x     ); }
  94 
  95     private static byte int3(int x) { return (byte)(x >> 24); }
  96     private static byte int2(int x) { return (byte)(x >> 16); }
  97     private static byte int1(int x) { return (byte)(x >>  8); }
  98     private static byte int0(int x) { return (byte)(x      ); }
  99 
 100     private static byte long7(long x) { return (byte)(x >> 56); }
 101     private static byte long6(long x) { return (byte)(x >> 48); }
 102     private static byte long5(long x) { return (byte)(x >> 40); }
 103     private static byte long4(long x) { return (byte)(x >> 32); }
 104     private static byte long3(long x) { return (byte)(x >> 24); }
 105     private static byte long2(long x) { return (byte)(x >> 16); }
 106     private static byte long1(long x) { return (byte)(x >>  8); }
 107     private static byte long0(long x) { return (byte)(x      ); }
 108 
 109     private static void putCharBigEndianUnaligned(long a, char x) {
 110         putByte_(a    , char1(x));
 111         putByte_(a + 1, char0(x));
 112     }
 113 
 114     private static void putShortBigEndianUnaligned(long a, short x) {
 115         putByte_(a    , short1(x));
 116         putByte_(a + 1, short0(x));
 117     }
 118 
 119     private static void putIntBigEndianUnaligned(long a, int x) {
 120         putByte_(a    , int3(x));
 121         putByte_(a + 1, int2(x));
 122         putByte_(a + 2, int1(x));
 123         putByte_(a + 3, int0(x));
 124     }
 125 
 126     private static void putLongBigEndianUnaligned(long a, long x) {
 127         putByte_(a    , long7(x));
 128         putByte_(a + 1, long6(x));
 129         putByte_(a + 2, long5(x));
 130         putByte_(a + 3, long4(x));
 131         putByte_(a + 4, long3(x));
 132         putByte_(a + 5, long2(x));
 133         putByte_(a + 6, long1(x));
 134         putByte_(a + 7, long0(x));
 135     }
 136 
 137     private static void putFloatBigEndianUnaligned(long a, float x) {
 138         putIntBigEndianUnaligned(a, Float.floatToRawIntBits(x));
 139     }
 140 
 141     private static void putDoubleBigEndianUnaligned(long a, double x) {
 142         putLongBigEndianUnaligned(a, Double.doubleToRawLongBits(x));
 143     }
 144 
 145     private static void putByte_(long a, byte b) {
 146         unsafe.putByte(a, b);
 147     }
 148 
 149     private static void putBoolean_(long a, boolean x) {
 150         unsafe.putBoolean(null, a, x);
 151     }
 152 
 153     private static void putChar_(long a, char x) {
 154         unsafe.putChar(a, bigEndian ? x : swap(x));
 155     }
 156 
 157     private static void putShort_(long a, short x) {
 158         unsafe.putShort(a, bigEndian ? x : swap(x));
 159     }
 160 
 161     private static void putInt_(long a, int x) {
 162         unsafe.putInt(a, bigEndian ? x : swap(x));
 163     }
 164 
 165     private static void putLong_(long a, long x) {
 166         unsafe.putLong(a, bigEndian ? x : swap(x));
 167     }
 168 
 169     private static void putFloat_(long a, float x) {
 170         unsafe.putFloat(a, bigEndian ? x : swap(x));
 171     }
 172 
 173     private static void putDouble_(long a, double x) {
 174         unsafe.putDouble(a, bigEndian ? x : swap(x));
 175     }
 176 
 177     // external api
 178     static int putByte(long a, byte x) {
 179         putByte_(a, x);
 180         return Byte.BYTES;
 181     }
 182 
 183     static int putBoolean(long a, boolean x) {
 184         putBoolean_(a, x);
 185         return Byte.BYTES;
 186     }
 187 
 188     static int putChar(long a, char x) {
 189         if (unalignedAccess || isAddressAligned(a, Character.BYTES)) {
 190             putChar_(a, x);
 191             return Character.BYTES;
 192         }
 193         putCharBigEndianUnaligned(a, x);
 194         return Character.BYTES;
 195     }
 196 
 197     static int putShort(long a, short x) {
 198         if (unalignedAccess || isAddressAligned(a, Short.BYTES)) {
 199             putShort_(a, x);
 200             return Short.BYTES;
 201         }
 202         putShortBigEndianUnaligned(a, x);
 203         return Short.BYTES;
 204     }
 205 
 206     static int putInt(long a, int x) {
 207         if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
 208             putInt_(a, x);
 209             return Integer.BYTES;
 210         }
 211         putIntBigEndianUnaligned(a, x);
 212         return Integer.BYTES;
 213     }
 214 
 215     static int putLong(long a, long x) {
 216          if (unalignedAccess || isAddressAligned(a, Long.BYTES)) {
 217             putLong_(a, x);
 218             return Long.BYTES;
 219         }
 220         putLongBigEndianUnaligned(a, x);
 221         return Long.BYTES;
 222     }
 223 
 224     static int putFloat(long a, float x) {
 225         if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
 226             putFloat_(a, x);
 227             return Float.BYTES;
 228         }
 229         putFloatBigEndianUnaligned(a, x);
 230         return Float.BYTES;
 231     }
 232 
 233     static int putDouble(long a, double x) {
 234         if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
 235             putDouble_(a, x);
 236             return Double.BYTES;
 237         }
 238         putDoubleBigEndianUnaligned(a, x);
 239         return Double.BYTES;
 240     }
 241 }