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 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 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 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 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 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. 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. 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|. 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. 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 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