1 /*
2 * Copyright (C) 2012 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_VERIFIER_REG_TYPE_INL_H_
18 #define ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_
19
20 #include "reg_type.h"
21
22 #include "base/arena_allocator.h"
23 #include "base/casts.h"
24 #include "method_verifier.h"
25 #include "mirror/class.h"
26 #include "verifier_deps.h"
27
28 namespace art HIDDEN {
29 namespace verifier {
30
GetClass()31 inline ObjPtr<mirror::Class> RegType::GetClass() const {
32 DCHECK(IsReference()) << Dump();
33 return down_cast<const ReferenceType&>(*this).GetClassImpl();
34 }
35
GetClassHandle()36 inline Handle<mirror::Class> RegType::GetClassHandle() const {
37 DCHECK(IsReference()) << Dump();
38 return down_cast<const ReferenceType&>(*this).GetClassHandleImpl();
39 }
40
41 namespace detail {
42
43 class RegTypeAssignabilityImpl final : RegType {
44 public:
RegTypeAssignabilityImpl(RegType::Kind kind)45 explicit constexpr RegTypeAssignabilityImpl(RegType::Kind kind)
46 : RegType("", /* unused cache id */ 0, kind) {}
47
48 static constexpr Assignability AssignabilityFrom(RegType::Kind lhs_kind, RegType::Kind rhs_kind);
49 };
50
AssignabilityFrom(RegType::Kind lhs_kind,RegType::Kind rhs_kind)51 constexpr RegType::Assignability RegTypeAssignabilityImpl::AssignabilityFrom(
52 RegType::Kind lhs_kind, RegType::Kind rhs_kind) {
53 RegTypeAssignabilityImpl lhs(lhs_kind);
54 RegTypeAssignabilityImpl rhs(rhs_kind);
55 auto maybe_narrowing_conversion = [&rhs]() constexpr {
56 return rhs.IsIntegralTypes() ? Assignability::kNarrowingConversion
57 : Assignability::kNotAssignable;
58 };
59 if (lhs.IsBoolean()) {
60 return rhs.IsBooleanTypes() ? Assignability::kAssignable : maybe_narrowing_conversion();
61 } else if (lhs.IsByte()) {
62 return rhs.IsByteTypes() ? Assignability::kAssignable : maybe_narrowing_conversion();
63 } else if (lhs.IsShort()) {
64 return rhs.IsShortTypes() ? Assignability::kAssignable : maybe_narrowing_conversion();
65 } else if (lhs.IsChar()) {
66 return rhs.IsCharTypes() ? Assignability::kAssignable : maybe_narrowing_conversion();
67 } else if (lhs.IsInteger()) {
68 return rhs.IsIntegralTypes() ? Assignability::kAssignable : Assignability::kNotAssignable;
69 } else if (lhs.IsFloat()) {
70 return rhs.IsFloatTypes() ? Assignability::kAssignable : Assignability::kNotAssignable;
71 } else if (lhs.IsLongLo()) {
72 return rhs.IsLongTypes() ? Assignability::kAssignable : Assignability::kNotAssignable;
73 } else if (lhs.IsDoubleLo()) {
74 return rhs.IsDoubleTypes() ? Assignability::kAssignable : Assignability::kNotAssignable;
75 } else if (lhs.IsConflict()) {
76 // TODO: The `MethodVerifier` is doing a `lhs` category check for `return{,-wide,-object}`
77 // before the assignability check, so a `Conflict` (`void`) is not a valid `lhs`. We could
78 // speed up the verification by removing the category check and relying on the assignability
79 // check. Then we would need to return `NotAssignable` here as the result would be used
80 // if a value is returned from a `void` method.
81 return Assignability::kInvalid;
82 } else if (lhs.IsUninitializedTypes() || lhs.IsUnresolvedMergedReference()) {
83 // These reference kinds are not valid `lhs`.
84 return Assignability::kInvalid;
85 } else if (lhs.IsNonZeroReferenceTypes()) {
86 if (rhs.IsZeroOrNull()) {
87 return Assignability::kAssignable; // All reference types can be assigned null.
88 } else if (!rhs.IsNonZeroReferenceTypes()) {
89 return Assignability::kNotAssignable; // Expect rhs to be a reference type.
90 } else if (rhs.IsUninitializedTypes()) {
91 // References of uninitialized types can be copied but not assigned.
92 return Assignability::kNotAssignable;
93 } else if (lhs.IsJavaLangObject()) {
94 return Assignability::kAssignable; // All reference types can be assigned to Object.
95 } else {
96 // Use `Reference` to tell the caller to process a reference assignability check.
97 // This check requires more information than the kinds available here.
98 return Assignability::kReference;
99 }
100 } else {
101 DCHECK(lhs.IsUndefined() || lhs.IsHighHalf() || lhs.IsConstantTypes());
102 return Assignability::kInvalid;
103 }
104 }
105
106 } // namespace detail
107
AssignabilityFrom(Kind lhs,Kind rhs)108 inline RegType::Assignability RegType::AssignabilityFrom(Kind lhs, Kind rhs) {
109 static constexpr size_t kNumKinds = NumberOfKinds();
110 using AssignabilityTable = std::array<std::array<Assignability, kNumKinds>, kNumKinds>;
111 static constexpr AssignabilityTable kAssignabilityTable = []() constexpr {
112 AssignabilityTable result;
113 for (size_t lhs = 0u; lhs != kNumKinds; ++lhs) {
114 for (size_t rhs = 0u; rhs != kNumKinds; ++rhs) {
115 result[lhs][rhs] = detail::RegTypeAssignabilityImpl::AssignabilityFrom(
116 enum_cast<RegType::Kind>(lhs), enum_cast<RegType::Kind>(rhs));
117 }
118 }
119 return result;
120 }();
121
122 return kAssignabilityTable[lhs][rhs];
123 }
124
new(size_t size,ArenaAllocator * allocator)125 inline void* RegType::operator new(size_t size, ArenaAllocator* allocator) {
126 return allocator->Alloc(size, kArenaAllocMisc);
127 }
128
129 } // namespace verifier
130 } // namespace art
131
132 #endif // ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_
133