blob: e02fbf47d0d9f17f132e453d6d0f47bb0c9bbf11 [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 Rogers529781d2012-07-23 17:24:29 -070046 "Unresolved Merged References",
47 "Unresolved Super Class",
Ian Rogers776ac1f2012-04-13 23:36:36 -070048 "Reference",
Ian Rogersb4903572012-10-11 11:52:56 -070049 "Precise Reference",
Ian Rogers776ac1f2012-04-13 23:36:36 -070050};
51
Ian Rogers529781d2012-07-23 17:24:29 -070052std::string RegType::Dump(const RegTypeCache* reg_types) const {
Ian Rogersb4903572012-10-11 11:52:56 -070053 DCHECK(type_ >= kRegTypeUndefined && type_ <= kRegTypePreciseReference);
54 DCHECK(arraysize(type_strings) == (kRegTypePreciseReference + 1));
Ian Rogers776ac1f2012-04-13 23:36:36 -070055 std::string result;
Ian Rogers529781d2012-07-23 17:24:29 -070056 if (IsUnresolvedMergedReference()) {
57 if (reg_types == NULL) {
58 std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
59 result += StringPrintf("UnresolvedMergedReferences(%d, %d)", refs.first, refs.second);
60 } else {
61 std::set<uint16_t> types = GetMergedTypes(reg_types);
62 result += "UnresolvedMergedReferences(";
63 typedef std::set<uint16_t>::const_iterator It; // TODO: C++0x auto
64 It it = types.begin();
65 result += reg_types->GetFromId(*it).Dump(reg_types);
66 for(++it; it != types.end(); ++it) {
67 result += ", ";
68 result += reg_types->GetFromId(*it).Dump(reg_types);
69 }
70 result += ")";
71 }
72 } else if (IsUnresolvedSuperClass()) {
73 uint16_t super_type_id = GetUnresolvedSuperClassChildId();
74 if (reg_types == NULL) {
75 result += StringPrintf("UnresolvedSuperClass(%d)", super_type_id);
76 } else {
77 result += "UnresolvedSuperClass(";
78 result += reg_types->GetFromId(super_type_id).Dump(reg_types);
79 result += ")";
80 }
81 } else if (IsConstant()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -070082 uint32_t val = ConstantValue();
83 if (val == 0) {
84 result = "Zero";
85 } else {
86 if (IsConstantShort()) {
87 result = StringPrintf("32-bit Constant: %d", val);
88 } else {
89 result = StringPrintf("32-bit Constant: 0x%x", val);
90 }
91 }
92 } else {
93 result = type_strings[type_];
94 if (IsReferenceTypes()) {
95 result += ": ";
96 if (IsUnresolvedTypes()) {
97 result += PrettyDescriptor(GetDescriptor());
98 } else {
99 result += PrettyDescriptor(GetClass());
100 }
101 }
102 }
103 return result;
104}
105
106const RegType& RegType::HighHalf(RegTypeCache* cache) const {
107 CHECK(IsLowHalf());
108 if (type_ == kRegTypeLongLo) {
109 return cache->FromType(kRegTypeLongHi);
110 } else if (type_ == kRegTypeDoubleLo) {
111 return cache->FromType(kRegTypeDoubleHi);
112 } else {
113 return cache->FromType(kRegTypeConstHi);
114 }
115}
116
Ian Rogers529781d2012-07-23 17:24:29 -0700117std::set<uint16_t> RegType::GetMergedTypes(const RegTypeCache* cache) const {
118 std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
119 const RegType& left = cache->GetFromId(refs.first);
120 const RegType& right = cache->GetFromId(refs.second);
121 std::set<uint16_t> types;
122 if (left.IsUnresolvedMergedReference()) {
123 types = left.GetMergedTypes(cache);
124 } else {
125 types.insert(refs.first);
126 }
127 if (right.IsUnresolvedMergedReference()) {
128 std::set<uint16_t> right_types = right.GetMergedTypes(cache);
129 types.insert(right_types.begin(), right_types.end());
130 } else {
131 types.insert(refs.second);
132 }
133#ifndef NDEBUG
134 typedef std::set<uint16_t>::const_iterator It; // TODO: C++0x auto
135 for(It it = types.begin(); it != types.end(); ++it) {
136 CHECK(!cache->GetFromId(*it).IsUnresolvedMergedReference());
137 }
138#endif
139 return types;
140}
141
Ian Rogersad0b3a32012-04-16 14:50:24 -0700142const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
143 if (!IsUnresolvedTypes()) {
144 Class* super_klass = GetClass()->GetSuperClass();
145 if (super_klass != NULL) {
Ian Rogersb4903572012-10-11 11:52:56 -0700146 return cache->FromClass(super_klass, IsPreciseReference());
Ian Rogers0d604842012-04-16 14:50:24 -0700147 } else {
Ian Rogersad0b3a32012-04-16 14:50:24 -0700148 return cache->Zero();
Ian Rogers776ac1f2012-04-13 23:36:36 -0700149 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700150 } else {
Ian Rogers529781d2012-07-23 17:24:29 -0700151 if (!IsUnresolvedMergedReference() && !IsUnresolvedSuperClass() &&
152 GetDescriptor()->CharAt(0) == '[') {
153 // Super class of all arrays is Object.
Ian Rogersb4903572012-10-11 11:52:56 -0700154 return cache->JavaLangObject(true);
Ian Rogers529781d2012-07-23 17:24:29 -0700155 } else {
156 return cache->FromUnresolvedSuperClass(*this);
157 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700158 }
159}
160
161bool RegType::CanAccess(const RegType& other) const {
162 if (Equals(other)) {
163 return true; // Trivial accessibility.
164 } else {
165 bool this_unresolved = IsUnresolvedTypes();
166 bool other_unresolved = other.IsUnresolvedTypes();
167 if (!this_unresolved && !other_unresolved) {
168 return GetClass()->CanAccess(other.GetClass());
169 } else if (!other_unresolved) {
170 return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public.
171 } else {
172 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogerse1758fe2012-04-19 11:31:15 -0700173 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700174 }
175}
176
177bool RegType::CanAccessMember(Class* klass, uint32_t access_flags) const {
178 if (access_flags & kAccPublic) {
179 return true;
180 }
181 if (!IsUnresolvedTypes()) {
182 return GetClass()->CanAccessMember(klass, access_flags);
183 } else {
184 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700185 }
186}
187
188bool RegType::IsAssignableFrom(const RegType& src) const {
189 if (Equals(src)) {
190 return true;
191 } else {
192 switch (GetType()) {
193 case RegType::kRegTypeBoolean: return src.IsBooleanTypes();
194 case RegType::kRegTypeByte: return src.IsByteTypes();
195 case RegType::kRegTypeShort: return src.IsShortTypes();
196 case RegType::kRegTypeChar: return src.IsCharTypes();
197 case RegType::kRegTypeInteger: return src.IsIntegralTypes();
198 case RegType::kRegTypeFloat: return src.IsFloatTypes();
199 case RegType::kRegTypeLongLo: return src.IsLongTypes();
200 case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
201 default:
202 if (!IsReferenceTypes()) {
203 LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
204 }
205 if (src.IsZero()) {
206 return true; // all reference types can be assigned null
207 } else if (!src.IsReferenceTypes()) {
208 return false; // expect src to be a reference type
209 } else if (IsJavaLangObject()) {
210 return true; // all reference types can be assigned to Object
211 } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
212 return true; // We allow assignment to any interface, see comment in ClassJoin
213 } else if (IsJavaLangObjectArray()) {
214 return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
215 } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
216 GetClass()->IsAssignableFrom(src.GetClass())) {
217 // We're assignable from the Class point-of-view
218 return true;
219 } else {
Ian Rogers529781d2012-07-23 17:24:29 -0700220 // TODO: unresolved types are only assignable for null, Object and equality currently.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700221 return false;
222 }
223 }
224 }
225}
226
227static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
228 return a.IsConstant() ? b : a;
229}
230
231const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
232 DCHECK(!Equals(incoming_type)); // Trivial equality handled by caller
Ian Rogersad0b3a32012-04-16 14:50:24 -0700233 if (IsUndefined() && incoming_type.IsUndefined()) {
234 return *this; // Undefined MERGE Undefined => Undefined
Ian Rogers776ac1f2012-04-13 23:36:36 -0700235 } else if (IsConflict()) {
236 return *this; // Conflict MERGE * => Conflict
237 } else if (incoming_type.IsConflict()) {
238 return incoming_type; // * MERGE Conflict => Conflict
Ian Rogersad0b3a32012-04-16 14:50:24 -0700239 } else if (IsUndefined() || incoming_type.IsUndefined()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700240 return reg_types->Conflict(); // Unknown MERGE * => Conflict
241 } else if (IsConstant() && incoming_type.IsConstant()) {
242 int32_t val1 = ConstantValue();
243 int32_t val2 = incoming_type.ConstantValue();
244 if (val1 >= 0 && val2 >= 0) {
245 // +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
246 if (val1 >= val2) {
247 return *this;
248 } else {
249 return incoming_type;
250 }
251 } else if (val1 < 0 && val2 < 0) {
252 // -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
253 if (val1 <= val2) {
254 return *this;
255 } else {
256 return incoming_type;
257 }
258 } else {
259 // Values are +ve and -ve, choose smallest signed type in which they both fit
260 if (IsConstantByte()) {
261 if (incoming_type.IsConstantByte()) {
262 return reg_types->ByteConstant();
263 } else if (incoming_type.IsConstantShort()) {
264 return reg_types->ShortConstant();
265 } else {
266 return reg_types->IntConstant();
267 }
268 } else if (IsConstantShort()) {
269 if (incoming_type.IsConstantShort()) {
270 return reg_types->ShortConstant();
271 } else {
272 return reg_types->IntConstant();
273 }
274 } else {
275 return reg_types->IntConstant();
276 }
277 }
278 } else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
279 if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
280 return reg_types->Boolean(); // boolean MERGE boolean => boolean
281 }
282 if (IsByteTypes() && incoming_type.IsByteTypes()) {
283 return reg_types->Byte(); // byte MERGE byte => byte
284 }
285 if (IsShortTypes() && incoming_type.IsShortTypes()) {
286 return reg_types->Short(); // short MERGE short => short
287 }
288 if (IsCharTypes() && incoming_type.IsCharTypes()) {
289 return reg_types->Char(); // char MERGE char => char
290 }
291 return reg_types->Integer(); // int MERGE * => int
292 } else if ((IsFloatTypes() && incoming_type.IsFloatTypes()) ||
293 (IsLongTypes() && incoming_type.IsLongTypes()) ||
294 (IsLongHighTypes() && incoming_type.IsLongHighTypes()) ||
295 (IsDoubleTypes() && incoming_type.IsDoubleTypes()) ||
296 (IsDoubleHighTypes() && incoming_type.IsDoubleHighTypes())) {
297 // check constant case was handled prior to entry
298 DCHECK(!IsConstant() || !incoming_type.IsConstant());
299 // float/long/double MERGE float/long/double_constant => float/long/double
300 return SelectNonConstant(*this, incoming_type);
301 } else if (IsReferenceTypes() && incoming_type.IsReferenceTypes()) {
302 if (IsZero() || incoming_type.IsZero()) {
303 return SelectNonConstant(*this, incoming_type); // 0 MERGE ref => ref
304 } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
Ian Rogersb4903572012-10-11 11:52:56 -0700305 return reg_types->JavaLangObject(false); // Object MERGE ref => Object
Ian Rogers529781d2012-07-23 17:24:29 -0700306 } else if (IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
307 // We know how to merge an unresolved type with itself, 0 or Object. In this case we
308 // have two sub-classes and don't know how to merge. Create a new string-based unresolved
309 // type that reflects our lack of knowledge and that allows the rest of the unresolved
310 // mechanics to continue.
311 return reg_types->FromUnresolvedMerge(*this, incoming_type);
312 } else if (IsUninitializedTypes() || incoming_type.IsUninitializedTypes()) {
313 // Something that is uninitialized hasn't had its constructor called. Mark any merge
314 // of this type with something that is initialized as conflicting. The cases of a merge
315 // with itself, 0 or Object are handled above.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700316 return reg_types->Conflict();
317 } else { // Two reference types, compute Join
318 Class* c1 = GetClass();
319 Class* c2 = incoming_type.GetClass();
320 DCHECK(c1 != NULL && !c1->IsPrimitive());
321 DCHECK(c2 != NULL && !c2->IsPrimitive());
322 Class* join_class = ClassJoin(c1, c2);
Ian Rogersb4903572012-10-11 11:52:56 -0700323 if (c1 == join_class && !IsPreciseReference()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700324 return *this;
Ian Rogersb4903572012-10-11 11:52:56 -0700325 } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700326 return incoming_type;
327 } else {
Ian Rogersb4903572012-10-11 11:52:56 -0700328 return reg_types->FromClass(join_class, false);
Ian Rogers776ac1f2012-04-13 23:36:36 -0700329 }
330 }
331 } else {
332 return reg_types->Conflict(); // Unexpected types => Conflict
333 }
334}
335
Ian Rogersad0b3a32012-04-16 14:50:24 -0700336// See comment in reg_type.h
337Class* RegType::ClassJoin(Class* s, Class* t) {
338 DCHECK(!s->IsPrimitive()) << PrettyClass(s);
339 DCHECK(!t->IsPrimitive()) << PrettyClass(t);
340 if (s == t) {
341 return s;
342 } else if (s->IsAssignableFrom(t)) {
343 return s;
344 } else if (t->IsAssignableFrom(s)) {
345 return t;
346 } else if (s->IsArrayClass() && t->IsArrayClass()) {
347 Class* s_ct = s->GetComponentType();
348 Class* t_ct = t->GetComponentType();
349 if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) {
350 // Given the types aren't the same, if either array is of primitive types then the only
351 // common parent is java.lang.Object
352 Class* result = s->GetSuperClass(); // short-cut to java.lang.Object
353 DCHECK(result->IsObjectClass());
354 return result;
355 }
356 Class* common_elem = ClassJoin(s_ct, t_ct);
357 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogers365c1022012-06-22 15:05:28 -0700358 ClassLoader* class_loader = s->GetClassLoader();
Ian Rogersad0b3a32012-04-16 14:50:24 -0700359 std::string descriptor("[");
360 descriptor += ClassHelper(common_elem).GetDescriptor();
361 Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
362 DCHECK(array_class != NULL);
363 return array_class;
364 } else {
365 size_t s_depth = s->Depth();
366 size_t t_depth = t->Depth();
367 // Get s and t to the same depth in the hierarchy
368 if (s_depth > t_depth) {
369 while (s_depth > t_depth) {
370 s = s->GetSuperClass();
371 s_depth--;
372 }
373 } else {
374 while (t_depth > s_depth) {
375 t = t->GetSuperClass();
376 t_depth--;
377 }
378 }
379 // Go up the hierarchy until we get to the common parent
380 while (s != t) {
381 s = s->GetSuperClass();
382 t = t->GetSuperClass();
383 }
384 return s;
385 }
386}
387
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700388std::ostream& operator<<(std::ostream& os, const RegType& rhs)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700389 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700390 os << rhs.Dump();
391 return os;
392}
393
Elliott Hughesa21039c2012-06-21 12:09:25 -0700394} // namespace verifier
395} // namespace art