blob: ab1da1e2c3e50965f75c0d004abc237097feecf9 [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",
Ian Rogers2bcb4a42012-11-08 10:39:18 -080028 "boolean",
29 "byte",
30 "short",
31 "char",
32 "int",
33 "float",
34 "long (Low Half)",
35 "long (High Half)",
36 "double (Low Half)",
37 "double (High Half)",
38 "Precise 32-bit Constant",
39 "Imprecise 32-bit Constant",
40 "Precise 64-bit Constant (Low Half)",
41 "Precise 64-bit Constant (High Half)",
42 "Imprecise 64-bit Constant (Low Half)",
43 "Imprecise 64-bit Constant (High Half)",
Ian Rogers776ac1f2012-04-13 23:36:36 -070044 "Unresolved Reference",
45 "Uninitialized Reference",
46 "Uninitialized This Reference",
47 "Unresolved And Uninitialized Reference",
Ian Rogersad0b3a32012-04-16 14:50:24 -070048 "Unresolved And Uninitialized This Reference",
Ian Rogers529781d2012-07-23 17:24:29 -070049 "Unresolved Merged References",
50 "Unresolved Super Class",
Ian Rogers776ac1f2012-04-13 23:36:36 -070051 "Reference",
Ian Rogersb4903572012-10-11 11:52:56 -070052 "Precise Reference",
Ian Rogers776ac1f2012-04-13 23:36:36 -070053};
54
Ian Rogers529781d2012-07-23 17:24:29 -070055std::string RegType::Dump(const RegTypeCache* reg_types) const {
Ian Rogersb4903572012-10-11 11:52:56 -070056 DCHECK(type_ >= kRegTypeUndefined && type_ <= kRegTypePreciseReference);
57 DCHECK(arraysize(type_strings) == (kRegTypePreciseReference + 1));
Ian Rogers776ac1f2012-04-13 23:36:36 -070058 std::string result;
Ian Rogers529781d2012-07-23 17:24:29 -070059 if (IsUnresolvedMergedReference()) {
60 if (reg_types == NULL) {
61 std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
62 result += StringPrintf("UnresolvedMergedReferences(%d, %d)", refs.first, refs.second);
63 } else {
64 std::set<uint16_t> types = GetMergedTypes(reg_types);
65 result += "UnresolvedMergedReferences(";
66 typedef std::set<uint16_t>::const_iterator It; // TODO: C++0x auto
67 It it = types.begin();
68 result += reg_types->GetFromId(*it).Dump(reg_types);
69 for(++it; it != types.end(); ++it) {
70 result += ", ";
71 result += reg_types->GetFromId(*it).Dump(reg_types);
72 }
73 result += ")";
74 }
75 } else if (IsUnresolvedSuperClass()) {
76 uint16_t super_type_id = GetUnresolvedSuperClassChildId();
77 if (reg_types == NULL) {
78 result += StringPrintf("UnresolvedSuperClass(%d)", super_type_id);
79 } else {
80 result += "UnresolvedSuperClass(";
81 result += reg_types->GetFromId(super_type_id).Dump(reg_types);
82 result += ")";
83 }
84 } else if (IsConstant()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -070085 uint32_t val = ConstantValue();
86 if (val == 0) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -080087 CHECK(IsPreciseConstant());
88 result = "Zero/null";
Ian Rogers776ac1f2012-04-13 23:36:36 -070089 } else {
Ian Rogers2bcb4a42012-11-08 10:39:18 -080090 result = IsPreciseConstant() ? "Precise " : "Imprecise ";
Ian Rogers776ac1f2012-04-13 23:36:36 -070091 if (IsConstantShort()) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -080092 result += StringPrintf("Constant: %d", val);
Ian Rogers776ac1f2012-04-13 23:36:36 -070093 } else {
Ian Rogers2bcb4a42012-11-08 10:39:18 -080094 result += StringPrintf("Constant: 0x%x", val);
Ian Rogers776ac1f2012-04-13 23:36:36 -070095 }
96 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -080097 } else if (IsConstantLo()) {
98 int32_t val = ConstantValueLo();
99 result = IsPreciseConstantLo() ? "Precise " : "Imprecise ";
100 if (val >= std::numeric_limits<jshort>::min() &&
101 val <= std::numeric_limits<jshort>::max()) {
102 result += StringPrintf("Low-half Constant: %d", val);
103 } else {
104 result += StringPrintf("Low-half Constant: 0x%x", val);
105 }
106 } else if (IsConstantHi()) {
107 int32_t val = ConstantValueHi();
108 result = IsPreciseConstantHi() ? "Precise " : "Imprecise ";
109 if (val >= std::numeric_limits<jshort>::min() &&
110 val <= std::numeric_limits<jshort>::max()) {
111 result += StringPrintf("High-half Constant: %d", val);
112 } else {
113 result += StringPrintf("High-half Constant: 0x%x", val);
114 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700115 } else {
116 result = type_strings[type_];
117 if (IsReferenceTypes()) {
118 result += ": ";
119 if (IsUnresolvedTypes()) {
120 result += PrettyDescriptor(GetDescriptor());
121 } else {
122 result += PrettyDescriptor(GetClass());
123 }
124 }
125 }
126 return result;
127}
128
129const RegType& RegType::HighHalf(RegTypeCache* cache) const {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800130 DCHECK(IsLowHalf());
Ian Rogers776ac1f2012-04-13 23:36:36 -0700131 if (type_ == kRegTypeLongLo) {
132 return cache->FromType(kRegTypeLongHi);
133 } else if (type_ == kRegTypeDoubleLo) {
134 return cache->FromType(kRegTypeDoubleHi);
135 } else {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800136 DCHECK_EQ(type_, kRegTypeImpreciseConstLo);
137 return cache->FromType(kRegTypeImpreciseConstHi);
Ian Rogers776ac1f2012-04-13 23:36:36 -0700138 }
139}
140
Ian Rogers529781d2012-07-23 17:24:29 -0700141std::set<uint16_t> RegType::GetMergedTypes(const RegTypeCache* cache) const {
142 std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
143 const RegType& left = cache->GetFromId(refs.first);
144 const RegType& right = cache->GetFromId(refs.second);
145 std::set<uint16_t> types;
146 if (left.IsUnresolvedMergedReference()) {
147 types = left.GetMergedTypes(cache);
148 } else {
149 types.insert(refs.first);
150 }
151 if (right.IsUnresolvedMergedReference()) {
152 std::set<uint16_t> right_types = right.GetMergedTypes(cache);
153 types.insert(right_types.begin(), right_types.end());
154 } else {
155 types.insert(refs.second);
156 }
157#ifndef NDEBUG
158 typedef std::set<uint16_t>::const_iterator It; // TODO: C++0x auto
159 for(It it = types.begin(); it != types.end(); ++it) {
160 CHECK(!cache->GetFromId(*it).IsUnresolvedMergedReference());
161 }
162#endif
163 return types;
164}
165
Ian Rogersad0b3a32012-04-16 14:50:24 -0700166const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
167 if (!IsUnresolvedTypes()) {
168 Class* super_klass = GetClass()->GetSuperClass();
169 if (super_klass != NULL) {
Ian Rogersb4903572012-10-11 11:52:56 -0700170 return cache->FromClass(super_klass, IsPreciseReference());
Ian Rogers0d604842012-04-16 14:50:24 -0700171 } else {
Ian Rogersad0b3a32012-04-16 14:50:24 -0700172 return cache->Zero();
Ian Rogers776ac1f2012-04-13 23:36:36 -0700173 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700174 } else {
Ian Rogers529781d2012-07-23 17:24:29 -0700175 if (!IsUnresolvedMergedReference() && !IsUnresolvedSuperClass() &&
Elliott Hughes80537bb2013-01-04 16:37:26 -0800176 GetDescriptor()[0] == '[') {
Ian Rogers529781d2012-07-23 17:24:29 -0700177 // Super class of all arrays is Object.
Ian Rogersb4903572012-10-11 11:52:56 -0700178 return cache->JavaLangObject(true);
Ian Rogers529781d2012-07-23 17:24:29 -0700179 } else {
180 return cache->FromUnresolvedSuperClass(*this);
181 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700182 }
183}
184
185bool RegType::CanAccess(const RegType& other) const {
186 if (Equals(other)) {
187 return true; // Trivial accessibility.
188 } else {
189 bool this_unresolved = IsUnresolvedTypes();
190 bool other_unresolved = other.IsUnresolvedTypes();
191 if (!this_unresolved && !other_unresolved) {
192 return GetClass()->CanAccess(other.GetClass());
193 } else if (!other_unresolved) {
194 return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public.
195 } else {
196 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogerse1758fe2012-04-19 11:31:15 -0700197 }
Ian Rogersad0b3a32012-04-16 14:50:24 -0700198 }
199}
200
201bool RegType::CanAccessMember(Class* klass, uint32_t access_flags) const {
202 if (access_flags & kAccPublic) {
203 return true;
204 }
205 if (!IsUnresolvedTypes()) {
206 return GetClass()->CanAccessMember(klass, access_flags);
207 } else {
208 return false; // More complicated test not possible on unresolved types, be conservative.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700209 }
210}
211
212bool RegType::IsAssignableFrom(const RegType& src) const {
213 if (Equals(src)) {
214 return true;
215 } else {
216 switch (GetType()) {
217 case RegType::kRegTypeBoolean: return src.IsBooleanTypes();
218 case RegType::kRegTypeByte: return src.IsByteTypes();
219 case RegType::kRegTypeShort: return src.IsShortTypes();
220 case RegType::kRegTypeChar: return src.IsCharTypes();
221 case RegType::kRegTypeInteger: return src.IsIntegralTypes();
222 case RegType::kRegTypeFloat: return src.IsFloatTypes();
223 case RegType::kRegTypeLongLo: return src.IsLongTypes();
224 case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
225 default:
226 if (!IsReferenceTypes()) {
227 LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
228 }
229 if (src.IsZero()) {
230 return true; // all reference types can be assigned null
231 } else if (!src.IsReferenceTypes()) {
232 return false; // expect src to be a reference type
233 } else if (IsJavaLangObject()) {
234 return true; // all reference types can be assigned to Object
235 } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
236 return true; // We allow assignment to any interface, see comment in ClassJoin
237 } else if (IsJavaLangObjectArray()) {
238 return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
239 } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
240 GetClass()->IsAssignableFrom(src.GetClass())) {
241 // We're assignable from the Class point-of-view
242 return true;
243 } else {
Ian Rogers529781d2012-07-23 17:24:29 -0700244 // TODO: unresolved types are only assignable for null, Object and equality currently.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700245 return false;
246 }
247 }
248 }
249}
250
251static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
252 return a.IsConstant() ? b : a;
253}
254
255const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
256 DCHECK(!Equals(incoming_type)); // Trivial equality handled by caller
Ian Rogersad0b3a32012-04-16 14:50:24 -0700257 if (IsUndefined() && incoming_type.IsUndefined()) {
258 return *this; // Undefined MERGE Undefined => Undefined
Ian Rogers776ac1f2012-04-13 23:36:36 -0700259 } else if (IsConflict()) {
260 return *this; // Conflict MERGE * => Conflict
261 } else if (incoming_type.IsConflict()) {
262 return incoming_type; // * MERGE Conflict => Conflict
Ian Rogersad0b3a32012-04-16 14:50:24 -0700263 } else if (IsUndefined() || incoming_type.IsUndefined()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700264 return reg_types->Conflict(); // Unknown MERGE * => Conflict
265 } else if (IsConstant() && incoming_type.IsConstant()) {
266 int32_t val1 = ConstantValue();
267 int32_t val2 = incoming_type.ConstantValue();
268 if (val1 >= 0 && val2 >= 0) {
269 // +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
270 if (val1 >= val2) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800271 if (!IsPreciseConstant()) {
272 return *this;
273 } else {
274 return reg_types->FromCat1Const(val1, false);
275 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700276 } else {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800277 if (!incoming_type.IsPreciseConstant()) {
278 return incoming_type;
279 } else {
280 return reg_types->FromCat1Const(val2, false);
281 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700282 }
283 } else if (val1 < 0 && val2 < 0) {
284 // -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
285 if (val1 <= val2) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800286 if (!IsPreciseConstant()) {
287 return *this;
288 } else {
289 return reg_types->FromCat1Const(val1, false);
290 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700291 } else {
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800292 if (!incoming_type.IsPreciseConstant()) {
293 return incoming_type;
294 } else {
295 return reg_types->FromCat1Const(val2, false);
296 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700297 }
298 } else {
299 // Values are +ve and -ve, choose smallest signed type in which they both fit
300 if (IsConstantByte()) {
301 if (incoming_type.IsConstantByte()) {
302 return reg_types->ByteConstant();
303 } else if (incoming_type.IsConstantShort()) {
304 return reg_types->ShortConstant();
305 } else {
306 return reg_types->IntConstant();
307 }
308 } else if (IsConstantShort()) {
309 if (incoming_type.IsConstantShort()) {
310 return reg_types->ShortConstant();
311 } else {
312 return reg_types->IntConstant();
313 }
314 } else {
315 return reg_types->IntConstant();
316 }
317 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -0800318 } else if (IsConstantLo() && incoming_type.IsConstantLo()) {
319 int32_t val1 = ConstantValueLo();
320 int32_t val2 = incoming_type.ConstantValueLo();
321 return reg_types->FromCat2ConstLo(val1 | val2, false);
322 } else if (IsConstantHi() && incoming_type.IsConstantHi()) {
323 int32_t val1 = ConstantValueHi();
324 int32_t val2 = incoming_type.ConstantValueHi();
325 return reg_types->FromCat2ConstHi(val1 | val2, false);
Ian Rogers776ac1f2012-04-13 23:36:36 -0700326 } else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
327 if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
328 return reg_types->Boolean(); // boolean MERGE boolean => boolean
329 }
330 if (IsByteTypes() && incoming_type.IsByteTypes()) {
331 return reg_types->Byte(); // byte MERGE byte => byte
332 }
333 if (IsShortTypes() && incoming_type.IsShortTypes()) {
334 return reg_types->Short(); // short MERGE short => short
335 }
336 if (IsCharTypes() && incoming_type.IsCharTypes()) {
337 return reg_types->Char(); // char MERGE char => char
338 }
339 return reg_types->Integer(); // int MERGE * => int
340 } else if ((IsFloatTypes() && incoming_type.IsFloatTypes()) ||
341 (IsLongTypes() && incoming_type.IsLongTypes()) ||
342 (IsLongHighTypes() && incoming_type.IsLongHighTypes()) ||
343 (IsDoubleTypes() && incoming_type.IsDoubleTypes()) ||
344 (IsDoubleHighTypes() && incoming_type.IsDoubleHighTypes())) {
345 // check constant case was handled prior to entry
346 DCHECK(!IsConstant() || !incoming_type.IsConstant());
347 // float/long/double MERGE float/long/double_constant => float/long/double
348 return SelectNonConstant(*this, incoming_type);
349 } else if (IsReferenceTypes() && incoming_type.IsReferenceTypes()) {
350 if (IsZero() || incoming_type.IsZero()) {
351 return SelectNonConstant(*this, incoming_type); // 0 MERGE ref => ref
352 } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
Ian Rogersb4903572012-10-11 11:52:56 -0700353 return reg_types->JavaLangObject(false); // Object MERGE ref => Object
Ian Rogers529781d2012-07-23 17:24:29 -0700354 } else if (IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
355 // We know how to merge an unresolved type with itself, 0 or Object. In this case we
356 // have two sub-classes and don't know how to merge. Create a new string-based unresolved
357 // type that reflects our lack of knowledge and that allows the rest of the unresolved
358 // mechanics to continue.
359 return reg_types->FromUnresolvedMerge(*this, incoming_type);
360 } else if (IsUninitializedTypes() || incoming_type.IsUninitializedTypes()) {
361 // Something that is uninitialized hasn't had its constructor called. Mark any merge
362 // of this type with something that is initialized as conflicting. The cases of a merge
363 // with itself, 0 or Object are handled above.
Ian Rogers776ac1f2012-04-13 23:36:36 -0700364 return reg_types->Conflict();
365 } else { // Two reference types, compute Join
366 Class* c1 = GetClass();
367 Class* c2 = incoming_type.GetClass();
368 DCHECK(c1 != NULL && !c1->IsPrimitive());
369 DCHECK(c2 != NULL && !c2->IsPrimitive());
370 Class* join_class = ClassJoin(c1, c2);
Ian Rogersb4903572012-10-11 11:52:56 -0700371 if (c1 == join_class && !IsPreciseReference()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700372 return *this;
Ian Rogersb4903572012-10-11 11:52:56 -0700373 } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700374 return incoming_type;
375 } else {
Ian Rogersb4903572012-10-11 11:52:56 -0700376 return reg_types->FromClass(join_class, false);
Ian Rogers776ac1f2012-04-13 23:36:36 -0700377 }
378 }
379 } else {
380 return reg_types->Conflict(); // Unexpected types => Conflict
381 }
382}
383
Ian Rogersad0b3a32012-04-16 14:50:24 -0700384// See comment in reg_type.h
385Class* RegType::ClassJoin(Class* s, Class* t) {
386 DCHECK(!s->IsPrimitive()) << PrettyClass(s);
387 DCHECK(!t->IsPrimitive()) << PrettyClass(t);
388 if (s == t) {
389 return s;
390 } else if (s->IsAssignableFrom(t)) {
391 return s;
392 } else if (t->IsAssignableFrom(s)) {
393 return t;
394 } else if (s->IsArrayClass() && t->IsArrayClass()) {
395 Class* s_ct = s->GetComponentType();
396 Class* t_ct = t->GetComponentType();
397 if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) {
398 // Given the types aren't the same, if either array is of primitive types then the only
399 // common parent is java.lang.Object
400 Class* result = s->GetSuperClass(); // short-cut to java.lang.Object
401 DCHECK(result->IsObjectClass());
402 return result;
403 }
404 Class* common_elem = ClassJoin(s_ct, t_ct);
405 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogers365c1022012-06-22 15:05:28 -0700406 ClassLoader* class_loader = s->GetClassLoader();
Ian Rogersad0b3a32012-04-16 14:50:24 -0700407 std::string descriptor("[");
408 descriptor += ClassHelper(common_elem).GetDescriptor();
409 Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
410 DCHECK(array_class != NULL);
411 return array_class;
412 } else {
413 size_t s_depth = s->Depth();
414 size_t t_depth = t->Depth();
415 // Get s and t to the same depth in the hierarchy
416 if (s_depth > t_depth) {
417 while (s_depth > t_depth) {
418 s = s->GetSuperClass();
419 s_depth--;
420 }
421 } else {
422 while (t_depth > s_depth) {
423 t = t->GetSuperClass();
424 t_depth--;
425 }
426 }
427 // Go up the hierarchy until we get to the common parent
428 while (s != t) {
429 s = s->GetSuperClass();
430 t = t->GetSuperClass();
431 }
432 return s;
433 }
434}
435
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700436std::ostream& operator<<(std::ostream& os, const RegType& rhs)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700437 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700438 os << rhs.Dump();
439 return os;
440}
441
Elliott Hughesa21039c2012-06-21 12:09:25 -0700442} // namespace verifier
443} // namespace art