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