blob: 217084ff55910de0c272d21e3bcd6b5d4291aa21 [file] [log] [blame]
Ian Rogers776ac1f2012-04-13 23:36:36 -07001/*
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#include "reg_type.h"
18
19#include "object_utils.h"
20#include "reg_type_cache.h"
21
22namespace art {
23namespace verifier {
24
25static const char* type_strings[] = {
Ian Rogersad0b3a32012-04-16 14:50:24 -070026 "Undefined",
Ian Rogers776ac1f2012-04-13 23:36:36 -070027 "Conflict",
28 "Boolean",
29 "Byte",
30 "Short",
31 "Char",
32 "Integer",
33 "Float",
34 "Long (Low Half)",
35 "Long (High Half)",
36 "Double (Low Half)",
37 "Double (High Half)",
38 "64-bit Constant (Low Half)",
39 "64-bit Constant (High Half)",
40 "32-bit Constant",
41 "Unresolved Reference",
42 "Uninitialized Reference",
43 "Uninitialized This Reference",
44 "Unresolved And Uninitialized Reference",
Ian Rogersad0b3a32012-04-16 14:50:24 -070045 "Unresolved And Uninitialized This Reference",
Ian Rogers776ac1f2012-04-13 23:36:36 -070046 "Reference",
47};
48
49std::string RegType::Dump() const {
Ian Rogersad0b3a32012-04-16 14:50:24 -070050 DCHECK(type_ >= kRegTypeUndefined && type_ <= kRegTypeReference);
Ian Rogers776ac1f2012-04-13 23:36:36 -070051 std::string result;
52 if (IsConstant()) {
53 uint32_t val = ConstantValue();
54 if (val == 0) {
55 result = "Zero";
56 } else {
57 if (IsConstantShort()) {
58 result = StringPrintf("32-bit Constant: %d", val);
59 } else {
60 result = StringPrintf("32-bit Constant: 0x%x", val);
61 }
62 }
63 } else {
64 result = type_strings[type_];
65 if (IsReferenceTypes()) {
66 result += ": ";
67 if (IsUnresolvedTypes()) {
68 result += PrettyDescriptor(GetDescriptor());
69 } else {
70 result += PrettyDescriptor(GetClass());
71 }
72 }
73 }
74 return result;
75}
76
77const RegType& RegType::HighHalf(RegTypeCache* cache) const {
78 CHECK(IsLowHalf());
79 if (type_ == kRegTypeLongLo) {
80 return cache->FromType(kRegTypeLongHi);
81 } else if (type_ == kRegTypeDoubleLo) {
82 return cache->FromType(kRegTypeDoubleHi);
83 } else {
84 return cache->FromType(kRegTypeConstHi);
85 }
86}
87
Ian Rogersad0b3a32012-04-16 14:50:24 -070088const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
89 if (!IsUnresolvedTypes()) {
90 Class* super_klass = GetClass()->GetSuperClass();
91 if (super_klass != NULL) {
92 return cache->FromClass(super_klass);
Ian Rogers0d604842012-04-16 14:50:24 -070093 } else {
Ian Rogersad0b3a32012-04-16 14:50:24 -070094 return cache->Zero();
Ian Rogers776ac1f2012-04-13 23:36:36 -070095 }
Ian Rogersad0b3a32012-04-16 14:50:24 -070096 } else {
97 // TODO: handle unresolved type cases better?
98 return cache->Conflict();
99 }
100}
101
102bool RegType::CanAccess(const RegType& other) const {
103 if (Equals(other)) {
104 return true; // Trivial accessibility.
105 } else {
106 bool this_unresolved = IsUnresolvedTypes();
107 bool other_unresolved = other.IsUnresolvedTypes();
108 if (!this_unresolved && !other_unresolved) {
109 return GetClass()->CanAccess(other.GetClass());
110 } else if (!other_unresolved) {
111 return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public.
112 } else {
113 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogerse1758fe2012-04-19 11:31:15 -0700114 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700115 }
116}
117
118bool RegType::CanAccessMember(Class* klass, uint32_t access_flags) const {
119 if (access_flags & kAccPublic) {
120 return true;
121 }
122 if (!IsUnresolvedTypes()) {
123 return GetClass()->CanAccessMember(klass, access_flags);
124 } else {
125 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700126 }
127}
128
129bool RegType::IsAssignableFrom(const RegType& src) const {
130 if (Equals(src)) {
131 return true;
132 } else {
133 switch (GetType()) {
134 case RegType::kRegTypeBoolean: return src.IsBooleanTypes();
135 case RegType::kRegTypeByte: return src.IsByteTypes();
136 case RegType::kRegTypeShort: return src.IsShortTypes();
137 case RegType::kRegTypeChar: return src.IsCharTypes();
138 case RegType::kRegTypeInteger: return src.IsIntegralTypes();
139 case RegType::kRegTypeFloat: return src.IsFloatTypes();
140 case RegType::kRegTypeLongLo: return src.IsLongTypes();
141 case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
142 default:
143 if (!IsReferenceTypes()) {
144 LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
145 }
146 if (src.IsZero()) {
147 return true; // all reference types can be assigned null
148 } else if (!src.IsReferenceTypes()) {
149 return false; // expect src to be a reference type
150 } else if (IsJavaLangObject()) {
151 return true; // all reference types can be assigned to Object
152 } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
153 return true; // We allow assignment to any interface, see comment in ClassJoin
154 } else if (IsJavaLangObjectArray()) {
155 return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
156 } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
157 GetClass()->IsAssignableFrom(src.GetClass())) {
158 // We're assignable from the Class point-of-view
159 return true;
Ian Rogersad0b3a32012-04-16 14:50:24 -0700160 } else if (IsUnresolvedTypes() && src.IsUnresolvedTypes() &&
161 GetDescriptor() == src.GetDescriptor()) {
162 // Two unresolved types (maybe one is uninitialized), we're clearly assignable if the
163 // descriptor is the same.
164 return true;
Ian Rogers776ac1f2012-04-13 23:36:36 -0700165 } else {
166 return false;
167 }
168 }
169 }
170}
171
172static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
173 return a.IsConstant() ? b : a;
174}
175
176const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
177 DCHECK(!Equals(incoming_type)); // Trivial equality handled by caller
Ian Rogersad0b3a32012-04-16 14:50:24 -0700178 if (IsUndefined() && incoming_type.IsUndefined()) {
179 return *this; // Undefined MERGE Undefined => Undefined
Ian Rogers776ac1f2012-04-13 23:36:36 -0700180 } else if (IsConflict()) {
181 return *this; // Conflict MERGE * => Conflict
182 } else if (incoming_type.IsConflict()) {
183 return incoming_type; // * MERGE Conflict => Conflict
Ian Rogersad0b3a32012-04-16 14:50:24 -0700184 } else if (IsUndefined() || incoming_type.IsUndefined()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700185 return reg_types->Conflict(); // Unknown MERGE * => Conflict
186 } else if (IsConstant() && incoming_type.IsConstant()) {
187 int32_t val1 = ConstantValue();
188 int32_t val2 = incoming_type.ConstantValue();
189 if (val1 >= 0 && val2 >= 0) {
190 // +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
191 if (val1 >= val2) {
192 return *this;
193 } else {
194 return incoming_type;
195 }
196 } else if (val1 < 0 && val2 < 0) {
197 // -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
198 if (val1 <= val2) {
199 return *this;
200 } else {
201 return incoming_type;
202 }
203 } else {
204 // Values are +ve and -ve, choose smallest signed type in which they both fit
205 if (IsConstantByte()) {
206 if (incoming_type.IsConstantByte()) {
207 return reg_types->ByteConstant();
208 } else if (incoming_type.IsConstantShort()) {
209 return reg_types->ShortConstant();
210 } else {
211 return reg_types->IntConstant();
212 }
213 } else if (IsConstantShort()) {
214 if (incoming_type.IsConstantShort()) {
215 return reg_types->ShortConstant();
216 } else {
217 return reg_types->IntConstant();
218 }
219 } else {
220 return reg_types->IntConstant();
221 }
222 }
223 } else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
224 if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
225 return reg_types->Boolean(); // boolean MERGE boolean => boolean
226 }
227 if (IsByteTypes() && incoming_type.IsByteTypes()) {
228 return reg_types->Byte(); // byte MERGE byte => byte
229 }
230 if (IsShortTypes() && incoming_type.IsShortTypes()) {
231 return reg_types->Short(); // short MERGE short => short
232 }
233 if (IsCharTypes() && incoming_type.IsCharTypes()) {
234 return reg_types->Char(); // char MERGE char => char
235 }
236 return reg_types->Integer(); // int MERGE * => int
237 } else if ((IsFloatTypes() && incoming_type.IsFloatTypes()) ||
238 (IsLongTypes() && incoming_type.IsLongTypes()) ||
239 (IsLongHighTypes() && incoming_type.IsLongHighTypes()) ||
240 (IsDoubleTypes() && incoming_type.IsDoubleTypes()) ||
241 (IsDoubleHighTypes() && incoming_type.IsDoubleHighTypes())) {
242 // check constant case was handled prior to entry
243 DCHECK(!IsConstant() || !incoming_type.IsConstant());
244 // float/long/double MERGE float/long/double_constant => float/long/double
245 return SelectNonConstant(*this, incoming_type);
246 } else if (IsReferenceTypes() && incoming_type.IsReferenceTypes()) {
247 if (IsZero() || incoming_type.IsZero()) {
248 return SelectNonConstant(*this, incoming_type); // 0 MERGE ref => ref
249 } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
250 return reg_types->JavaLangObject(); // Object MERGE ref => Object
251 } else if (IsUninitializedTypes() || incoming_type.IsUninitializedTypes() ||
252 IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
253 // Can only merge an unresolved or uninitialized type with itself, 0 or Object, we've already
254 // checked these so => Conflict
255 return reg_types->Conflict();
256 } else { // Two reference types, compute Join
257 Class* c1 = GetClass();
258 Class* c2 = incoming_type.GetClass();
259 DCHECK(c1 != NULL && !c1->IsPrimitive());
260 DCHECK(c2 != NULL && !c2->IsPrimitive());
261 Class* join_class = ClassJoin(c1, c2);
262 if (c1 == join_class) {
263 return *this;
264 } else if (c2 == join_class) {
265 return incoming_type;
266 } else {
267 return reg_types->FromClass(join_class);
268 }
269 }
270 } else {
271 return reg_types->Conflict(); // Unexpected types => Conflict
272 }
273}
274
Ian Rogersad0b3a32012-04-16 14:50:24 -0700275// See comment in reg_type.h
276Class* RegType::ClassJoin(Class* s, Class* t) {
277 DCHECK(!s->IsPrimitive()) << PrettyClass(s);
278 DCHECK(!t->IsPrimitive()) << PrettyClass(t);
279 if (s == t) {
280 return s;
281 } else if (s->IsAssignableFrom(t)) {
282 return s;
283 } else if (t->IsAssignableFrom(s)) {
284 return t;
285 } else if (s->IsArrayClass() && t->IsArrayClass()) {
286 Class* s_ct = s->GetComponentType();
287 Class* t_ct = t->GetComponentType();
288 if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) {
289 // Given the types aren't the same, if either array is of primitive types then the only
290 // common parent is java.lang.Object
291 Class* result = s->GetSuperClass(); // short-cut to java.lang.Object
292 DCHECK(result->IsObjectClass());
293 return result;
294 }
295 Class* common_elem = ClassJoin(s_ct, t_ct);
296 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
297 const ClassLoader* class_loader = s->GetClassLoader();
298 std::string descriptor("[");
299 descriptor += ClassHelper(common_elem).GetDescriptor();
300 Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
301 DCHECK(array_class != NULL);
302 return array_class;
303 } else {
304 size_t s_depth = s->Depth();
305 size_t t_depth = t->Depth();
306 // Get s and t to the same depth in the hierarchy
307 if (s_depth > t_depth) {
308 while (s_depth > t_depth) {
309 s = s->GetSuperClass();
310 s_depth--;
311 }
312 } else {
313 while (t_depth > s_depth) {
314 t = t->GetSuperClass();
315 t_depth--;
316 }
317 }
318 // Go up the hierarchy until we get to the common parent
319 while (s != t) {
320 s = s->GetSuperClass();
321 t = t->GetSuperClass();
322 }
323 return s;
324 }
325}
326
Ian Rogers776ac1f2012-04-13 23:36:36 -0700327std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
328 os << rhs.Dump();
329 return os;
330}
331
Elliott Hughesa21039c2012-06-21 12:09:25 -0700332} // namespace verifier
333} // namespace art