1 /*
   2  * Copyright (c) 2017, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  26 #define SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "metaprogramming/enableIf.hpp"
  30 #include "metaprogramming/integralConstant.hpp"
  31 #include "metaprogramming/isFloatingPoint.hpp"
  32 #include "metaprogramming/isIntegral.hpp"
  33 #include "metaprogramming/isRegisteredEnum.hpp"
  34 #include "utilities/debug.hpp"
  35 
  36 class IntegerTypes : public AllStatic {
  37 public:
  38   // Return a value of type T with the same representation as x.
  39   //
  40   // T and U must be of the same size.
  41   //
  42   // At least one of T or U must be an integral type.  The other must
  43   // be an integral, floating point, or pointer type.
  44   template<typename T, typename U> static T cast(U x);
  45 
  46   // Support thin wrappers over primitive types.
  47   // If derived from TrueType, provides representational conversion
  48   // from T to some other type.  When true, must provide
  49   // - Value: typedef for T.
  50   // - Decayed: typedef for decayed type.
  51   // - static Decayed decay(T x): return value of type Decayed with
  52   //   the same representation as x.
  53   // - static T recover(Decayed x): return a value of type T with the
  54   //   same representation as x.
  55   template<typename T> struct Translate : public FalseType {};
  56 
  57 private:
  58 
  59   template<typename T,
  60            typename U,
  61            bool same_size = sizeof(T) == sizeof(U),
  62            typename Enable = void>
  63   struct Cast;
  64 
  65   template<typename T, typename U> static T cast_using_union(U x);
  66 };
  67 
  68 // Return an object of type T with the same value representation as x.
  69 //
  70 // T and U must be of the same size.  It is expected that one of T and
  71 // U is an integral type, and the other is an integral type, a
  72 // (registered) enum type, or a floating point type
  73 //
  74 // This implementation uses the "union trick", which seems to be the
  75 // best of a bad set of options.  Though technically undefined
  76 // behavior, it is widely and well supported, producing good code.  In
  77 // some cases, such as gcc, that support is explicitly documented.
  78 //
  79 // Using memcpy is the correct method, but some compilers produce
  80 // wretched code for that method, even at maximal optimization levels.
  81 //
  82 // Using static_cast is only possible for integral and enum types, not
  83 // for floating point types.  And for integral and enum conversions,
  84 // static_cast has unspecified or implementation-defined behavior for
  85 // some cases.  C++11 <type_traits> can be used to avoid most or all
  86 // of those unspecified or implementation-defined issues, though that
  87 // may require multi-step conversions.
  88 //
  89 // Using reinterpret_cast of references has undefined behavior for
  90 // many cases, and there is much less empirical basis for its use, as
  91 // compared to the union trick.
  92 template<typename T, typename U>
  93 inline T IntegerTypes::cast_using_union(U x) {
  94   STATIC_ASSERT(sizeof(T) == sizeof(U));
  95   union { T t; U u; };
  96   u = x;
  97   return t;
  98 }
  99 
 100 //////////////////////////////////////////////////////////////////////////////
 101 // cast<T>(x)
 102 //
 103 // Cast<T, U, same_size, Enable>
 104 
 105 // Give an informative error if the sizes differ.
 106 template<typename T, typename U>
 107 struct IntegerTypes::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC {
 108   STATIC_ASSERT(sizeof(T) == sizeof(U));
 109 };
 110 
 111 // Conversion between integral types.
 112 template<typename T, typename U>
 113 struct IntegerTypes::Cast<
 114   T, U, true,
 115   typename EnableIf<IsIntegral<T>::value && IsIntegral<U>::value>::type>
 116   VALUE_OBJ_CLASS_SPEC
 117 {
 118   T operator()(U x) const { return cast_using_union<T>(x); }
 119 };
 120 
 121 // Convert an enum or floating point value to an integer value.
 122 template<typename T, typename U>
 123 struct IntegerTypes::Cast<
 124   T, U, true,
 125   typename EnableIf<IsIntegral<T>::value &&
 126                     (IsRegisteredEnum<U>::value ||
 127                      IsFloatingPoint<U>::value)>::type>
 128   VALUE_OBJ_CLASS_SPEC
 129 {
 130   T operator()(U x) const { return cast_using_union<T>(x); }
 131 };
 132 
 133 // Convert an integer to an enum or floating point value.
 134 template<typename T, typename U>
 135 struct IntegerTypes::Cast<
 136   T, U, true,
 137   typename EnableIf<IsIntegral<U>::value &&
 138                     (IsRegisteredEnum<T>::value ||
 139                      IsFloatingPoint<T>::value)>::type>
 140   VALUE_OBJ_CLASS_SPEC
 141 {
 142   T operator()(U x) const { return cast_using_union<T>(x); }
 143 };
 144 
 145 // Convert a pointer to an integral value.
 146 template<typename T, typename U>
 147 struct IntegerTypes::Cast<
 148   T, U*, true,
 149   typename EnableIf<IsIntegral<T>::value>::type>
 150   VALUE_OBJ_CLASS_SPEC
 151 {
 152   T operator()(U* x) const { return reinterpret_cast<T>(x); }
 153 };
 154 
 155 // Convert an integral value to a pointer.
 156 template<typename T, typename U>
 157 struct IntegerTypes::Cast<
 158   T*, U, true,
 159   typename EnableIf<IsIntegral<U>::value>::type>
 160   VALUE_OBJ_CLASS_SPEC
 161 {
 162   T* operator()(U x) const { return reinterpret_cast<T*>(x); }
 163 };
 164 
 165 template<typename T, typename U>
 166 inline T IntegerTypes::cast(U x) {
 167   return Cast<T, U>()(x);
 168 }
 169 
 170 #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP