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_LIBDEXFILE_DEX_PRIMITIVE_H_
18 #define ART_LIBDEXFILE_DEX_PRIMITIVE_H_
19 
20 #include <sys/types.h>
21 
22 #include <android-base/logging.h>
23 
24 #include "base/macros.h"
25 
26 namespace art {
27 
28 static constexpr size_t kObjectReferenceSize = 4;
29 
ComponentSizeShiftWidth(size_t component_size)30 constexpr size_t ComponentSizeShiftWidth(size_t component_size) {
31   return component_size == 1u ? 0u :
32       component_size == 2u ? 1u :
33           component_size == 4u ? 2u :
34               component_size == 8u ? 3u : 0u;
35 }
36 
37 class Primitive {
38  public:
39   enum Type {
40     kPrimNot = 0,
41     kPrimBoolean,
42     kPrimByte,
43     kPrimChar,
44     kPrimShort,
45     kPrimInt,
46     kPrimLong,
47     kPrimFloat,
48     kPrimDouble,
49     kPrimVoid,
50     kPrimLast = kPrimVoid
51   };
52 
GetType(char type)53   static constexpr Type GetType(char type) {
54     switch (type) {
55       case 'B':
56         return kPrimByte;
57       case 'C':
58         return kPrimChar;
59       case 'D':
60         return kPrimDouble;
61       case 'F':
62         return kPrimFloat;
63       case 'I':
64         return kPrimInt;
65       case 'J':
66         return kPrimLong;
67       case 'S':
68         return kPrimShort;
69       case 'Z':
70         return kPrimBoolean;
71       case 'V':
72         return kPrimVoid;
73       default:
74         return kPrimNot;
75     }
76   }
77 
ComponentSizeShift(Type type)78   static constexpr size_t ComponentSizeShift(Type type) {
79     switch (type) {
80       case kPrimVoid:
81       case kPrimBoolean:
82       case kPrimByte:    return 0;
83       case kPrimChar:
84       case kPrimShort:   return 1;
85       case kPrimInt:
86       case kPrimFloat:   return 2;
87       case kPrimLong:
88       case kPrimDouble:  return 3;
89       case kPrimNot:     return ComponentSizeShiftWidth(kObjectReferenceSize);
90     }
91     LOG(FATAL) << "Invalid type " << static_cast<int>(type);
92     UNREACHABLE();
93   }
94 
ComponentSize(Type type)95   static constexpr 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     }
108     LOG(FATAL) << "Invalid type " << static_cast<int>(type);
109     UNREACHABLE();
110   }
111 
Descriptor(Type type)112   static const char* Descriptor(Type type) {
113     switch (type) {
114       case kPrimBoolean:
115         return "Z";
116       case kPrimByte:
117         return "B";
118       case kPrimChar:
119         return "C";
120       case kPrimShort:
121         return "S";
122       case kPrimInt:
123         return "I";
124       case kPrimFloat:
125         return "F";
126       case kPrimLong:
127         return "J";
128       case kPrimDouble:
129         return "D";
130       case kPrimVoid:
131         return "V";
132       default:
133         LOG(FATAL) << "Primitive char conversion on invalid type " << static_cast<int>(type);
134         return nullptr;
135     }
136   }
137 
138   static const char* PrettyDescriptor(Type type);
139 
140   // Returns the descriptor corresponding to the boxed type of |type|.
141   static const char* BoxedDescriptor(Type type);
142 
143   // Returns true if |type| is an numeric type.
IsNumericType(Type type)144   static constexpr bool IsNumericType(Type type) {
145     switch (type) {
146       case Primitive::Type::kPrimNot: return false;
147       case Primitive::Type::kPrimBoolean: return false;
148       case Primitive::Type::kPrimByte: return true;
149       case Primitive::Type::kPrimChar: return true;
150       case Primitive::Type::kPrimShort: return true;
151       case Primitive::Type::kPrimInt: return true;
152       case Primitive::Type::kPrimLong: return true;
153       case Primitive::Type::kPrimFloat: return true;
154       case Primitive::Type::kPrimDouble: return true;
155       case Primitive::Type::kPrimVoid: return false;
156     }
157     LOG(FATAL) << "Invalid type " << static_cast<int>(type);
158     UNREACHABLE();
159   }
160 
161   // Return trues if |type| is a signed numeric type.
IsSignedNumericType(Type type)162   static constexpr bool IsSignedNumericType(Type type) {
163     switch (type) {
164       case Primitive::Type::kPrimNot: return false;
165       case Primitive::Type::kPrimBoolean: return false;
166       case Primitive::Type::kPrimByte: return true;
167       case Primitive::Type::kPrimChar: return false;
168       case Primitive::Type::kPrimShort: return true;
169       case Primitive::Type::kPrimInt: return true;
170       case Primitive::Type::kPrimLong: return true;
171       case Primitive::Type::kPrimFloat: return true;
172       case Primitive::Type::kPrimDouble: return true;
173       case Primitive::Type::kPrimVoid: return false;
174     }
175     LOG(FATAL) << "Invalid type " << static_cast<int>(type);
176     UNREACHABLE();
177   }
178 
179   // Returns the number of bits required to hold the largest
180   // positive number that can be represented by |type|.
BitsRequiredForLargestValue(Type type)181   static constexpr size_t BitsRequiredForLargestValue(Type type) {
182     switch (type) {
183       case Primitive::Type::kPrimNot: return 0u;
184       case Primitive::Type::kPrimBoolean: return 1u;
185       case Primitive::Type::kPrimByte: return 7u;
186       case Primitive::Type::kPrimChar: return 16u;
187       case Primitive::Type::kPrimShort: return 15u;
188       case Primitive::Type::kPrimInt: return 31u;
189       case Primitive::Type::kPrimLong: return 63u;
190       case Primitive::Type::kPrimFloat: return 128u;
191       case Primitive::Type::kPrimDouble: return 1024u;
192       case Primitive::Type::kPrimVoid: return 0u;
193     }
194   }
195 
196   // Returns true if it is possible to widen type |from| to type |to|. Both |from| and
197   // |to| should be numeric primitive types.
IsWidenable(Type from,Type to)198   static bool IsWidenable(Type from, Type to) {
199     if (!IsNumericType(from) || !IsNumericType(to)) {
200       // Widening is only applicable between numeric types.
201       return false;
202     }
203     if (IsSignedNumericType(from) && !IsSignedNumericType(to)) {
204       // Nowhere to store the sign bit in |to|.
205       return false;
206     }
207     if (BitsRequiredForLargestValue(from) > BitsRequiredForLargestValue(to)) {
208       // The from,to pair corresponds to a narrowing.
209       return false;
210     }
211     return true;
212   }
213 
Is64BitType(Type type)214   static bool Is64BitType(Type type) {
215     return type == kPrimLong || type == kPrimDouble;
216   }
217 
218  private:
219   DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
220 };
221 
222 std::ostream& operator<<(std::ostream& os, Primitive::Type state);
223 
224 }  // namespace art
225 
226 #endif  // ART_LIBDEXFILE_DEX_PRIMITIVE_H_
227