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