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_PRIMITIVECONVERSIONS_HPP
26#define SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_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
36class PrimitiveConversions : public AllStatic {
37public:
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
57private:
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.
92template<typename T, typename U>
93inline T PrimitiveConversions::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.
106template<typename T, typename U>
107struct PrimitiveConversions::Cast<T, U, false> VALUE_OBJ_CLASS_SPEC {
108  STATIC_ASSERT(sizeof(T) == sizeof(U));
109};
110
111// Conversion between integral types.
112template<typename T, typename U>
113struct PrimitiveConversions::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.
122template<typename T, typename U>
123struct PrimitiveConversions::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.
134template<typename T, typename U>
135struct PrimitiveConversions::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.
146template<typename T, typename U>
147struct PrimitiveConversions::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.
156template<typename T, typename U>
157struct PrimitiveConversions::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
165template<typename T, typename U>
166inline T PrimitiveConversions::cast(U x) {
167  return Cast<T, U>()(x);
168}
169
170#endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP
171