1 /*
2  * Copyright (C) 2015 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 #ifndef ART_RUNTIME_LAMBDA_SHORTY_FIELD_TYPE_H_
17 #define ART_RUNTIME_LAMBDA_SHORTY_FIELD_TYPE_H_
18 
19 #include "base/logging.h"
20 #include "base/macros.h"
21 #include "base/value_object.h"
22 #include "globals.h"
23 #include "runtime/primitive.h"
24 
25 #include <ostream>
26 
27 namespace art {
28 
29 namespace mirror {
30 class Object;  // forward declaration
31 }  // namespace mirror
32 
33 namespace lambda {
34 
35 struct Closure;  // forward declaration
36 
37 // TODO: Refactor together with primitive.h
38 
39 // The short form of a field type descriptor. Corresponds to ShortyFieldType in dex specification.
40 // Only types usable by a field (and locals) are allowed (i.e. no void type).
41 // Note that arrays and objects are treated both as 'L'.
42 //
43 // This is effectively a 'char' enum-like zero-cost type-safe wrapper with extra helper functions.
44 struct ShortyFieldType : ValueObject {
45   // Use as if this was an enum class, e.g. 'ShortyFieldType::kBoolean'.
46   enum : char {
47     // Primitives (Narrow):
48     kBoolean = 'Z',
49     kByte = 'B',
50     kChar = 'C',
51     kShort = 'S',
52     kInt = 'I',
53     kFloat = 'F',
54     // Primitives (Wide):
55     kLong = 'J',
56     kDouble = 'D',
57     // Managed types:
58     kObject = 'L',  // This can also be an array (which is otherwise '[' in a non-shorty).
59     kLambda = '\\',
60   };  // NOTE: This is an anonymous enum so we can get exhaustive switch checking from the compiler.
61 
62   // Implicitly construct from the enum above. Value must be one of the enum list members above.
63   // Always safe to use, does not do any DCHECKs.
ShortyFieldTypeShortyFieldType64   inline constexpr ShortyFieldType(decltype(kByte) c) : value_(c) {
65   }
66 
67   // Default constructor. The initial value is undefined. Initialize before calling methods.
68   // This is very unsafe but exists as a convenience to having undefined values.
ShortyFieldTypeShortyFieldType69   explicit ShortyFieldType() : value_(StaticCastValue(0)) {
70   }
71 
72   // Explicitly construct from a char. Value must be one of the enum list members above.
73   // Conversion is potentially unsafe, so DCHECKing is performed.
ShortyFieldTypeShortyFieldType74   explicit inline ShortyFieldType(char c) : value_(StaticCastValue(c)) {
75     if (kIsDebugBuild) {
76       // Verify at debug-time that our conversion is safe.
77       ShortyFieldType ignored;
78       DCHECK(MaybeCreate(c, &ignored)) << "unknown shorty field type '" << c << "'";
79     }
80   }
81 
82   // Attempts to parse the character in 'shorty_field_type' into its strongly typed version.
83   // Returns false if the character was out of range of the grammar.
MaybeCreateShortyFieldType84   static bool MaybeCreate(char shorty_field_type, ShortyFieldType* out) {
85     DCHECK(out != nullptr);
86     switch (shorty_field_type) {
87       case kBoolean:
88       case kByte:
89       case kChar:
90       case kShort:
91       case kInt:
92       case kFloat:
93       case kLong:
94       case kDouble:
95       case kObject:
96       case kLambda:
97         *out = ShortyFieldType(static_cast<decltype(kByte)>(shorty_field_type));
98         return true;
99       default:
100         break;
101     }
102 
103     return false;
104   }
105 
106   // Convert the first type in a field type descriptor string into a shorty.
107   // Arrays are converted into objects.
108   // Does not work for 'void' types (as they are illegal in a field type descriptor).
CreateFromFieldTypeDescriptorShortyFieldType109   static ShortyFieldType CreateFromFieldTypeDescriptor(const char* field_type_descriptor) {
110     DCHECK(field_type_descriptor != nullptr);
111     char c = *field_type_descriptor;
112     if (UNLIKELY(c == kArray)) {  // Arrays are treated as object references.
113       c = kObject;
114     }
115     return ShortyFieldType{c};  // NOLINT [readability/braces] [4]
116   }
117 
118   // Parse the first type in the field type descriptor string into a shorty.
119   // See CreateFromFieldTypeDescriptor for more details.
120   //
121   // Returns the pointer offset into the middle of the field_type_descriptor
122   // that would either point to the next shorty type, or to null if there are
123   // no more types.
124   //
125   // DCHECKs that each of the nested types is a valid shorty field type. This
126   // means the type descriptor must be already valid.
ParseFromFieldTypeDescriptorShortyFieldType127   static const char* ParseFromFieldTypeDescriptor(const char* field_type_descriptor,
128                                                   ShortyFieldType* out_type) {
129     DCHECK(field_type_descriptor != nullptr);
130 
131     if (UNLIKELY(field_type_descriptor[0] == '\0')) {
132       // Handle empty strings by immediately returning null.
133       return nullptr;
134     }
135 
136     // All non-empty strings must be a valid list of field type descriptors, otherwise
137     // the DCHECKs will kick in and the program will crash.
138     const char shorter_type = *field_type_descriptor;
139 
140     ShortyFieldType safe_type;
141     bool type_set = MaybeCreate(shorter_type, &safe_type);
142 
143     // Lambda that keeps skipping characters until it sees ';'.
144     // Stops one character -after- the ';'.
145     auto skip_until_semicolon = [&field_type_descriptor]() {
146       while (*field_type_descriptor != ';' && *field_type_descriptor != '\0') {
147         ++field_type_descriptor;
148       }
149       DCHECK_NE(*field_type_descriptor, '\0')
150           << " type descriptor terminated too early: " << field_type_descriptor;
151       ++field_type_descriptor;  // Skip the ';'
152     };
153 
154     ++field_type_descriptor;
155     switch (shorter_type) {
156       case kObject:
157         skip_until_semicolon();
158 
159         DCHECK(type_set);
160         DCHECK(safe_type == kObject);
161         break;
162       case kArray:
163         // Strip out all of the leading [[[[[s, we don't care if it's a multi-dimensional array.
164         while (*field_type_descriptor == '[' && *field_type_descriptor != '\0') {
165           ++field_type_descriptor;
166         }
167         DCHECK_NE(*field_type_descriptor, '\0')
168             << " type descriptor terminated too early: " << field_type_descriptor;
169         // Either a primitive, object, or closure left. No more arrays.
170         {
171           // Now skip all the characters that form the array's interior-most element type
172           // (which itself is guaranteed not to be an array).
173           ShortyFieldType array_interior_type;
174           type_set = MaybeCreate(*field_type_descriptor, &array_interior_type);
175           DCHECK(type_set) << " invalid remaining type descriptor " << field_type_descriptor;
176 
177           // Handle array-of-objects case like [[[[[LObject; and array-of-closures like [[[[[\Foo;
178           if (*field_type_descriptor == kObject || *field_type_descriptor == kLambda) {
179             skip_until_semicolon();
180           } else {
181             // Handle primitives which are exactly one character we can skip.
182             DCHECK(array_interior_type.IsPrimitive());
183             ++field_type_descriptor;
184           }
185         }
186 
187         safe_type = kObject;
188         type_set = true;
189         break;
190       case kLambda:
191         skip_until_semicolon();
192 
193         DCHECK(safe_type == kLambda);
194         DCHECK(type_set);
195         break;
196       default:
197         DCHECK_NE(kVoid, shorter_type) << "cannot make a ShortyFieldType from a void type";
198         break;
199     }
200 
201     DCHECK(type_set) << "invalid shorty type descriptor " << shorter_type;
202 
203     *out_type = safe_type;
204     return type_set ? field_type_descriptor : nullptr;
205   }
206 
207   // Explicitly convert to a char.
208   inline explicit operator char() const {
209     return value_;
210   }
211 
212   // Is this a primitive?
IsPrimitiveShortyFieldType213   inline bool IsPrimitive() const {
214     return IsPrimitiveNarrow() || IsPrimitiveWide();
215   }
216 
217   // Is this a narrow primitive (i.e. can fit into 1 virtual register)?
IsPrimitiveNarrowShortyFieldType218   inline bool IsPrimitiveNarrow() const {
219     switch (value_) {
220       case kBoolean:
221       case kByte:
222       case kChar:
223       case kShort:
224       case kInt:
225       case kFloat:
226         return true;
227       default:
228         return false;
229     }
230   }
231 
232   // Is this a wide primitive (i.e. needs exactly 2 virtual registers)?
IsPrimitiveWideShortyFieldType233   inline bool IsPrimitiveWide() const {
234     switch (value_) {
235       case kLong:
236       case kDouble:
237         return true;
238       default:
239         return false;
240     }
241   }
242 
243   // Is this an object reference (which can also be an array)?
IsObjectShortyFieldType244   inline bool IsObject() const {
245     return value_ == kObject;
246   }
247 
248   // Is this a lambda?
IsLambdaShortyFieldType249   inline bool IsLambda() const {
250     return value_ == kLambda;
251   }
252 
253   // Is the size of this (to store inline as a field) always known at compile-time?
IsStaticSizeShortyFieldType254   inline bool IsStaticSize() const {
255     return !IsLambda();
256   }
257 
258   // Get the compile-time size (to be able to store it inline as a field or on stack).
259   // Dynamically-sized values such as lambdas return the guaranteed lower bound.
GetStaticSizeShortyFieldType260   inline size_t GetStaticSize() const {
261     switch (value_) {
262       case kBoolean:
263         return sizeof(bool);
264       case kByte:
265         return sizeof(uint8_t);
266       case kChar:
267         return sizeof(int16_t);
268       case kShort:
269         return sizeof(uint16_t);
270       case kInt:
271         return sizeof(int32_t);
272       case kLong:
273         return sizeof(int64_t);
274       case kFloat:
275         return sizeof(float);
276       case kDouble:
277         return sizeof(double);
278       case kObject:
279         return kObjectReferenceSize;
280       case kLambda:
281         return sizeof(void*);  // Large enough to store the ArtLambdaMethod
282       default:
283         DCHECK(false) << "unknown shorty field type '" << static_cast<char>(value_) << "'";
284         UNREACHABLE();
285     }
286   }
287 
288   // Implicitly convert to the anonymous nested inner type. Used for exhaustive switch detection.
decltypeShortyFieldType289   inline operator decltype(kByte)() const {
290     return value_;
291   }
292 
293   // Returns a read-only static string representing the enum name, useful for printing/debug only.
ToStringShortyFieldType294   inline const char* ToString() const {
295     switch (value_) {
296       case kBoolean:
297         return "kBoolean";
298       case kByte:
299         return "kByte";
300       case kChar:
301         return "kChar";
302       case kShort:
303         return "kShort";
304       case kInt:
305         return "kInt";
306       case kLong:
307         return "kLong";
308       case kFloat:
309         return "kFloat";
310       case kDouble:
311         return "kDouble";
312       case kObject:
313         return "kObject";
314       case kLambda:
315         return "kLambda";
316       default:
317         // Undefined behavior if we get this far. Pray the compiler gods are merciful.
318         return "<undefined>";
319     }
320   }
321 
322  private:
323   static constexpr const char kArray = '[';
324   static constexpr const char kVoid  = 'V';
325 
326   // Helper to statically cast anything into our nested anonymous enum type.
327   template <typename T>
decltypeShortyFieldType328   inline static decltype(kByte) StaticCastValue(const T& anything) {
329     return static_cast<decltype(value_)>(anything);
330   }
331 
332   // The only field in this struct.
333   decltype(kByte) value_;
334 };
335 
336 
337   // Print to an output stream.
338 inline std::ostream& operator<<(std::ostream& ostream, ShortyFieldType shorty) {
339   return ostream << shorty.ToString();
340 }
341 
342 static_assert(sizeof(ShortyFieldType) == sizeof(char),
343               "ShortyFieldType must be lightweight just like a char");
344 
345 // Compile-time trait information regarding the ShortyFieldType.
346 // Used by static_asserts to verify that the templates are correctly used at compile-time.
347 //
348 // For example,
349 //     ShortyFieldTypeTraits::IsPrimitiveNarrowType<int64_t>() == true
350 //     ShortyFieldTypeTraits::IsObjectType<mirror::Object*>() == true
351 struct ShortyFieldTypeTraits {
352   // A type guaranteed to be large enough to holds any of the shorty field types.
353   using MaxType = uint64_t;
354 
355   // Type traits: Returns true if 'T' is a valid type that can be represented by a shorty field type.
356   template <typename T>
IsTypeShortyFieldTypeTraits357   static inline constexpr bool IsType() {
358     return IsPrimitiveType<T>() || IsObjectType<T>() || IsLambdaType<T>();
359   }
360 
361   // Returns true if 'T' is a primitive type (i.e. a built-in without nested references).
362   template <typename T>
IsPrimitiveTypeShortyFieldTypeTraits363   static inline constexpr bool IsPrimitiveType() {
364     return IsPrimitiveNarrowType<T>() || IsPrimitiveWideType<T>();
365   }
366 
367   // Returns true if 'T' is a primitive type that is narrow (i.e. can be stored into 1 vreg).
368   template <typename T>
IsPrimitiveNarrowTypeShortyFieldTypeTraits369   static inline constexpr bool IsPrimitiveNarrowType() {
370     return IsPrimitiveNarrowTypeImpl(static_cast<T* const>(nullptr));
371   }
372 
373   // Returns true if 'T' is a primitive type that is wide (i.e. needs 2 vregs for storage).
374   template <typename T>
IsPrimitiveWideTypeShortyFieldTypeTraits375   static inline constexpr bool IsPrimitiveWideType() {
376     return IsPrimitiveWideTypeImpl(static_cast<T* const>(nullptr));
377   }
378 
379   // Returns true if 'T' is an object (i.e. it is a managed GC reference).
380   // Note: This is equivalent to std::base_of<mirror::Object*, T>::value
381   template <typename T>
IsObjectTypeShortyFieldTypeTraits382   static inline constexpr bool IsObjectType() {
383     return IsObjectTypeImpl(static_cast<T* const>(nullptr));
384   }
385 
386   // Returns true if 'T' is a lambda (i.e. it is a closure with unknown static data);
387   template <typename T>
IsLambdaTypeShortyFieldTypeTraits388   static inline constexpr bool IsLambdaType() {
389     return IsLambdaTypeImpl(static_cast<T* const>(nullptr));
390   }
391 
392  private:
393 #define IS_VALID_TYPE_SPECIALIZATION(type, name) \
394   static inline constexpr bool Is ## name ## TypeImpl(type* const  = 0) { \
395     return true; \
396   } \
397   \
398   static_assert(sizeof(MaxType) >= sizeof(type), "MaxType too small")
399 
400   IS_VALID_TYPE_SPECIALIZATION(bool, PrimitiveNarrow);
401   IS_VALID_TYPE_SPECIALIZATION(int8_t, PrimitiveNarrow);
402   IS_VALID_TYPE_SPECIALIZATION(uint8_t, PrimitiveNarrow);  // Not strictly true, but close enough.
403   IS_VALID_TYPE_SPECIALIZATION(int16_t, PrimitiveNarrow);
404   IS_VALID_TYPE_SPECIALIZATION(uint16_t, PrimitiveNarrow);  // Chars are unsigned.
405   IS_VALID_TYPE_SPECIALIZATION(int32_t, PrimitiveNarrow);
406   IS_VALID_TYPE_SPECIALIZATION(uint32_t, PrimitiveNarrow);  // Not strictly true, but close enough.
407   IS_VALID_TYPE_SPECIALIZATION(float, PrimitiveNarrow);
408   IS_VALID_TYPE_SPECIALIZATION(int64_t, PrimitiveWide);
409   IS_VALID_TYPE_SPECIALIZATION(uint64_t, PrimitiveWide);  // Not strictly true, but close enough.
410   IS_VALID_TYPE_SPECIALIZATION(double, PrimitiveWide);
411   IS_VALID_TYPE_SPECIALIZATION(mirror::Object*, Object);
412   IS_VALID_TYPE_SPECIALIZATION(Closure*, Lambda);
413 #undef IS_VALID_TYPE_SPECIALIZATION
414 
415 #define IS_VALID_TYPE_SPECIALIZATION_IMPL(name) \
416   template <typename T> \
417   static inline constexpr bool Is ## name ## TypeImpl(T* const = 0) { \
418     return false; \
419   }
420 
421   IS_VALID_TYPE_SPECIALIZATION_IMPL(PrimitiveNarrow);
422   IS_VALID_TYPE_SPECIALIZATION_IMPL(PrimitiveWide);
423   IS_VALID_TYPE_SPECIALIZATION_IMPL(Object);
424   IS_VALID_TYPE_SPECIALIZATION_IMPL(Lambda);
425 
426 #undef IS_VALID_TYPE_SPECIALIZATION_IMPL
427 };
428 
429 // Maps the ShortyFieldType enum into it's C++ type equivalent, into the "type" typedef.
430 // For example:
431 //     ShortyFieldTypeSelectType<ShortyFieldType::kBoolean>::type => bool
432 //     ShortyFieldTypeSelectType<ShortyFieldType::kLong>::type => int64_t
433 //
434 // Invalid enums will not have the type defined.
435 template <decltype(ShortyFieldType::kByte) Shorty>
436 struct ShortyFieldTypeSelectType {
437 };
438 
439 // Maps the C++ type into it's ShortyFieldType enum equivalent, into the "value" constexpr.
440 // For example:
441 //     ShortyFieldTypeSelectEnum<bool>::value => ShortyFieldType::kBoolean
442 //     ShortyFieldTypeSelectEnum<int64_t>::value => ShortyFieldType::kLong
443 //
444 // Signed-ness must match for a valid select, e.g. uint64_t will not map to kLong, but int64_t will.
445 // Invalid types will not have the value defined (see e.g. ShortyFieldTypeTraits::IsType<T>())
446 template <typename T>
447 struct ShortyFieldTypeSelectEnum {
448 };
449 
450 #define SHORTY_FIELD_TYPE_SELECT_IMPL(cpp_type, enum_element)      \
451 template <> \
452 struct ShortyFieldTypeSelectType<ShortyFieldType::enum_element> { \
453   using type = cpp_type; \
454 }; \
455 \
456 template <> \
457 struct ShortyFieldTypeSelectEnum<cpp_type> { \
458   static constexpr const auto value = ShortyFieldType::enum_element; \
459 }; \
460 
461 SHORTY_FIELD_TYPE_SELECT_IMPL(bool, kBoolean);
462 SHORTY_FIELD_TYPE_SELECT_IMPL(int8_t, kByte);
463 SHORTY_FIELD_TYPE_SELECT_IMPL(int16_t, kShort);
464 SHORTY_FIELD_TYPE_SELECT_IMPL(uint16_t, kChar);
465 SHORTY_FIELD_TYPE_SELECT_IMPL(int32_t, kInt);
466 SHORTY_FIELD_TYPE_SELECT_IMPL(float, kFloat);
467 SHORTY_FIELD_TYPE_SELECT_IMPL(int64_t, kLong);
468 SHORTY_FIELD_TYPE_SELECT_IMPL(double, kDouble);
469 SHORTY_FIELD_TYPE_SELECT_IMPL(mirror::Object*, kObject);
470 SHORTY_FIELD_TYPE_SELECT_IMPL(Closure*, kLambda);
471 
472 }  // namespace lambda
473 }  // namespace art
474 
475 #endif  // ART_RUNTIME_LAMBDA_SHORTY_FIELD_TYPE_H_
476