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 "utilities/debug.hpp"
  30 #include "metaprogramming/enableIf.hpp"
  31 #include "metaprogramming/integralConstant.hpp"
  32 #include "metaprogramming/isFloatingPoint.hpp"
  33 #include "metaprogramming/isPointer.hpp"
  34 #include "metaprogramming/isRegisteredEnum.hpp"
  35 #include "metaprogramming/isIntegral.hpp"
  36 
  37 class IntegerTypes : public AllStatic {
  38 public:
  39   // Return a value of type T with the same representation as x.
  40   //
  41   // T and U must be of the same size.
  42   //
  43   // At least one of T or U must be an integral type.  The other must
  44   // be an integral, floating point, or pointer type.
  45   template<typename T, typename U> static T cast(U x);
  46 
  47   // Support thin wrappers over primitive types.
  48   // If derived from TrueType, provides representational conversion
  49   // from T to some other type.  When true, must provide
  50   // - Value: typedef for T.
  51   // - Decayed: typedef for decayed type.
  52   // - static Decayed decay(T x): return value of type Decayed with
  53   //   the same representation as x.
  54   // - static T recover(Decayed x): return a value of type T with the
  55   //   same representation as x.
  56   template<typename T> struct Translate : public FalseType {};
  57 
  58   // Value categories.  For internal use, but needs to be public.
  59   enum Category {
  60     INTEGRAL,
  61     ENUM,
  62     FLOAT,
  63     POINTER
  64   };
  65 
  66 private:
  67 
  68   template<typename T, typename Enable = void> struct GetCategory;
  69 
  70   template<typename T,
  71            typename U,
  72            bool same_size = sizeof(T) == sizeof(U),
  73            Category to_category = GetCategory<T>::value,
  74            Category from_category = GetCategory<U>::value>
  75   struct Cast;
  76 
  77   template<typename T, typename U> static T cast_integral(U x);
  78   template<typename T, typename U> static T cast_floating_point(U x);
  79 };
  80 
  81 #define DEFINE_GET_CATEGORY(Predicate, Value)                           \
  82   template<typename T>                                                  \
  83   struct IntegerTypes::GetCategory<                                     \
  84     T,                                                                  \
  85     typename EnableIf<Predicate<T>::value>::type>                       \
  86     : IntegralConstant<IntegerTypes::Category, IntegerTypes::Value>     \
  87   {};
  88 
  89 DEFINE_GET_CATEGORY(IsIntegral, INTEGRAL)
  90 DEFINE_GET_CATEGORY(IsRegisteredEnum, ENUM)
  91 DEFINE_GET_CATEGORY(IsFloatingPoint, FLOAT)
  92 DEFINE_GET_CATEGORY(IsPointer, POINTER)
  93 
  94 #undef DEFINE_GET_CATEGORY
  95 
  96 // Convert between different integral types of the same size.
  97 // See C++03 3.10/15 for discussion of reinterpret_cast to a reference
  98 // as a means for converting integral types while keeping the representation.
  99 template<typename T, typename U>
 100 inline T IntegerTypes::cast_integral(U x) {
 101   STATIC_ASSERT(sizeof(T) == sizeof(U));
 102   return reinterpret_cast<T&>(x);
 103 }
 104 
 105 // Convert between an integral type and a floating point type of the
 106 // same size.  The only truly correct way to do this is with memcpy.
 107 // Both the union trick and type punning via casts are undefined
 108 // behavior. gcc generates exactly the same code for all three methods,
 109 // except where the UB of type punning causes it to go off into the weeds.
 110 // (gcc explicitly supports the union trick.)  Other compilers may vary.
 111 // In particular, not all compilers do a good job with the memcpy.
 112 template<typename T, typename U>
 113 inline T IntegerTypes::cast_floating_point(U x) {
 114   STATIC_ASSERT(sizeof(T) == sizeof(U));
 115   T result;
 116   memcpy(&result, &x, sizeof(x));
 117   return result;
 118 }
 119 
 120 //////////////////////////////////////////////////////////////////////////////
 121 // cast<T>(x)
 122 //
 123 // Cast<T, U, same_size, to_category, from_category>
 124 
 125 // Give an informative error if the sizes differ.
 126 template<typename T, typename U,
 127          IntegerTypes::Category to_category,
 128          IntegerTypes::Category from_category>
 129 struct IntegerTypes::Cast<T, U, false, to_category, from_category>
 130   VALUE_OBJ_CLASS_SPEC
 131 {
 132   STATIC_ASSERT(sizeof(T) == sizeof(U));
 133 };
 134 
 135 #define DEFINE_INTEGER_TYPES_CAST(To, From, Convert)    \
 136   template<typename T, typename U>                      \
 137   struct IntegerTypes::Cast<T, U, true,                 \
 138                             IntegerTypes::To,           \
 139                             IntegerTypes::From>         \
 140     VALUE_OBJ_CLASS_SPEC                                \
 141   {                                                     \
 142     T operator()(U x) const { return Convert<T>(x); }   \
 143   };
 144 
 145 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, INTEGRAL, cast_integral)
 146 DEFINE_INTEGER_TYPES_CAST(ENUM,     INTEGRAL, cast_integral)
 147 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, ENUM,     cast_integral)
 148 DEFINE_INTEGER_TYPES_CAST(FLOAT,    INTEGRAL, cast_floating_point)
 149 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, FLOAT,    cast_floating_point)
 150 DEFINE_INTEGER_TYPES_CAST(POINTER,  INTEGRAL, reinterpret_cast)
 151 DEFINE_INTEGER_TYPES_CAST(INTEGRAL, POINTER,  reinterpret_cast)
 152 
 153 #undef DEFINE_INTEGER_TYPES_CAST
 154 
 155 template<typename T, typename U>
 156 inline T IntegerTypes::cast(U x) {
 157   return Cast<T, U>()(x);
 158 }
 159 
 160 #endif // SHARE_VM_METAPROGRAMMING_INTEGERTYPES_HPP