1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ART_RUNTIME_PRIMITIVE_H_
18 #define ART_RUNTIME_PRIMITIVE_H_
19
20 #include <sys/types.h>
21
22 #include "base/logging.h"
23 #include "base/macros.h"
24
25 namespace art {
26
27 static constexpr size_t kObjectReferenceSize = 4;
28
ComponentSizeShiftWidth(size_t component_size)29 constexpr size_t ComponentSizeShiftWidth(size_t component_size) {
30 return component_size == 1u ? 0u :
31 component_size == 2u ? 1u :
32 component_size == 4u ? 2u :
33 component_size == 8u ? 3u : 0u;
34 }
35
36 class Primitive {
37 public:
38 enum Type {
39 kPrimNot = 0,
40 kPrimBoolean,
41 kPrimByte,
42 kPrimChar,
43 kPrimShort,
44 kPrimInt,
45 kPrimLong,
46 kPrimFloat,
47 kPrimDouble,
48 kPrimVoid,
49 kPrimLast = kPrimVoid
50 };
51
GetType(char type)52 static Type GetType(char type) {
53 switch (type) {
54 case 'B':
55 return kPrimByte;
56 case 'C':
57 return kPrimChar;
58 case 'D':
59 return kPrimDouble;
60 case 'F':
61 return kPrimFloat;
62 case 'I':
63 return kPrimInt;
64 case 'J':
65 return kPrimLong;
66 case 'S':
67 return kPrimShort;
68 case 'Z':
69 return kPrimBoolean;
70 case 'V':
71 return kPrimVoid;
72 default:
73 return kPrimNot;
74 }
75 }
76
ComponentSizeShift(Type type)77 static size_t ComponentSizeShift(Type type) {
78 switch (type) {
79 case kPrimVoid:
80 case kPrimBoolean:
81 case kPrimByte: return 0;
82 case kPrimChar:
83 case kPrimShort: return 1;
84 case kPrimInt:
85 case kPrimFloat: return 2;
86 case kPrimLong:
87 case kPrimDouble: return 3;
88 case kPrimNot: return ComponentSizeShiftWidth(kObjectReferenceSize);
89 default:
90 LOG(FATAL) << "Invalid type " << static_cast<int>(type);
91 return 0;
92 }
93 }
94
ComponentSize(Type type)95 static size_t ComponentSize(Type type) {
96 switch (type) {
97 case kPrimVoid: return 0;
98 case kPrimBoolean:
99 case kPrimByte: return 1;
100 case kPrimChar:
101 case kPrimShort: return 2;
102 case kPrimInt:
103 case kPrimFloat: return 4;
104 case kPrimLong:
105 case kPrimDouble: return 8;
106 case kPrimNot: return kObjectReferenceSize;
107 default:
108 LOG(FATAL) << "Invalid type " << static_cast<int>(type);
109 return 0;
110 }
111 }
112
Descriptor(Type type)113 static const char* Descriptor(Type type) {
114 switch (type) {
115 case kPrimBoolean:
116 return "Z";
117 case kPrimByte:
118 return "B";
119 case kPrimChar:
120 return "C";
121 case kPrimShort:
122 return "S";
123 case kPrimInt:
124 return "I";
125 case kPrimFloat:
126 return "F";
127 case kPrimLong:
128 return "J";
129 case kPrimDouble:
130 return "D";
131 case kPrimVoid:
132 return "V";
133 default:
134 LOG(FATAL) << "Primitive char conversion on invalid type " << static_cast<int>(type);
135 return nullptr;
136 }
137 }
138
139 static const char* PrettyDescriptor(Type type);
140
141 // Returns the descriptor corresponding to the boxed type of |type|.
142 static const char* BoxedDescriptor(Type type);
143
IsFloatingPointType(Type type)144 static bool IsFloatingPointType(Type type) {
145 return type == kPrimFloat || type == kPrimDouble;
146 }
147
IsIntegralType(Type type)148 static bool IsIntegralType(Type type) {
149 // The Java language does not allow treating boolean as an integral type but
150 // our bit representation makes it safe.
151 switch (type) {
152 case kPrimBoolean:
153 case kPrimByte:
154 case kPrimChar:
155 case kPrimShort:
156 case kPrimInt:
157 case kPrimLong:
158 return true;
159 default:
160 return false;
161 }
162 }
163
164 // Return true if |type| is an numeric type.
IsNumericType(Type type)165 static constexpr bool IsNumericType(Type type) {
166 switch (type) {
167 case Primitive::Type::kPrimNot: return false;
168 case Primitive::Type::kPrimBoolean: return false;
169 case Primitive::Type::kPrimByte: return true;
170 case Primitive::Type::kPrimChar: return false;
171 case Primitive::Type::kPrimShort: return true;
172 case Primitive::Type::kPrimInt: return true;
173 case Primitive::Type::kPrimLong: return true;
174 case Primitive::Type::kPrimFloat: return true;
175 case Primitive::Type::kPrimDouble: return true;
176 case Primitive::Type::kPrimVoid: return false;
177 }
178 }
179
180 // Returns true if it is possible to widen type |from| to type |to|. Both |from| and
181 // |to| should be numeric primitive types.
IsWidenable(Type from,Type to)182 static bool IsWidenable(Type from, Type to) {
183 static_assert(Primitive::Type::kPrimByte < Primitive::Type::kPrimShort, "Bad ordering");
184 static_assert(Primitive::Type::kPrimShort < Primitive::Type::kPrimInt, "Bad ordering");
185 static_assert(Primitive::Type::kPrimInt < Primitive::Type::kPrimLong, "Bad ordering");
186 static_assert(Primitive::Type::kPrimLong < Primitive::Type::kPrimFloat, "Bad ordering");
187 static_assert(Primitive::Type::kPrimFloat < Primitive::Type::kPrimDouble, "Bad ordering");
188 // Widening is only applicable between numeric types, like byte
189 // and int. Non-numeric types, such as boolean, cannot be widened.
190 return IsNumericType(from) && IsNumericType(to) && from <= to;
191 }
192
IsIntOrLongType(Type type)193 static bool IsIntOrLongType(Type type) {
194 return type == kPrimInt || type == kPrimLong;
195 }
196
Is64BitType(Type type)197 static bool Is64BitType(Type type) {
198 return type == kPrimLong || type == kPrimDouble;
199 }
200
201 // Return the general kind of `type`, fusing integer-like types as kPrimInt.
PrimitiveKind(Type type)202 static Type PrimitiveKind(Type type) {
203 switch (type) {
204 case kPrimBoolean:
205 case kPrimByte:
206 case kPrimShort:
207 case kPrimChar:
208 case kPrimInt:
209 return kPrimInt;
210 default:
211 return type;
212 }
213 }
214
MinValueOfIntegralType(Type type)215 static int64_t MinValueOfIntegralType(Type type) {
216 switch (type) {
217 case kPrimBoolean:
218 return std::numeric_limits<bool>::min();
219 case kPrimByte:
220 return std::numeric_limits<int8_t>::min();
221 case kPrimChar:
222 return std::numeric_limits<uint16_t>::min();
223 case kPrimShort:
224 return std::numeric_limits<int16_t>::min();
225 case kPrimInt:
226 return std::numeric_limits<int32_t>::min();
227 case kPrimLong:
228 return std::numeric_limits<int64_t>::min();
229 default:
230 LOG(FATAL) << "non integral type";
231 }
232 return 0;
233 }
234
MaxValueOfIntegralType(Type type)235 static int64_t MaxValueOfIntegralType(Type type) {
236 switch (type) {
237 case kPrimBoolean:
238 return std::numeric_limits<bool>::max();
239 case kPrimByte:
240 return std::numeric_limits<int8_t>::max();
241 case kPrimChar:
242 return std::numeric_limits<uint16_t>::max();
243 case kPrimShort:
244 return std::numeric_limits<int16_t>::max();
245 case kPrimInt:
246 return std::numeric_limits<int32_t>::max();
247 case kPrimLong:
248 return std::numeric_limits<int64_t>::max();
249 default:
250 LOG(FATAL) << "non integral type";
251 }
252 return 0;
253 }
254
255 private:
256 DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
257 };
258
259 std::ostream& operator<<(std::ostream& os, const Primitive::Type& state);
260
261 } // namespace art
262
263 #endif // ART_RUNTIME_PRIMITIVE_H_
264