blob: f72ad6ab13ec6f8f9b91a69bf37a6fd6293f86aa [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 Rogerse1758fe2012-04-19 11:31:15 -070026 "Unknown",
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",
45 "Reference",
46};
47
48std::string RegType::Dump() const {
Ian Rogerse1758fe2012-04-19 11:31:15 -070049 DCHECK(type_ >= kRegTypeUnknown && type_ <= kRegTypeReference);
Ian Rogers776ac1f2012-04-13 23:36:36 -070050 std::string result;
51 if (IsConstant()) {
52 uint32_t val = ConstantValue();
53 if (val == 0) {
54 result = "Zero";
55 } else {
56 if (IsConstantShort()) {
57 result = StringPrintf("32-bit Constant: %d", val);
58 } else {
59 result = StringPrintf("32-bit Constant: 0x%x", val);
60 }
61 }
62 } else {
63 result = type_strings[type_];
64 if (IsReferenceTypes()) {
65 result += ": ";
66 if (IsUnresolvedTypes()) {
67 result += PrettyDescriptor(GetDescriptor());
68 } else {
69 result += PrettyDescriptor(GetClass());
70 }
71 }
72 }
73 return result;
74}
75
76const RegType& RegType::HighHalf(RegTypeCache* cache) const {
77 CHECK(IsLowHalf());
78 if (type_ == kRegTypeLongLo) {
79 return cache->FromType(kRegTypeLongHi);
80 } else if (type_ == kRegTypeDoubleLo) {
81 return cache->FromType(kRegTypeDoubleHi);
82 } else {
83 return cache->FromType(kRegTypeConstHi);
84 }
85}
86
Ian Rogerse1758fe2012-04-19 11:31:15 -070087/*
88 * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
89 * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
90 * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
91 * is the deepest (lowest upper bound) parent of S and T).
92 *
93 * This operation applies for regular classes and arrays, however, for interface types there needn't
94 * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
95 * introducing sets of types, however, the only operation permissible on an interface is
96 * invoke-interface. In the tradition of Java verifiers we defer the verification of interface
97 * types until an invoke-interface call on the interface typed reference at runtime and allow
98 * the perversion of any Object being assignable to an interface type (note, however, that we don't
99 * allow assignment of Object or Interface to any concrete subclass of Object and are therefore type
100 * safe; further the Join on a Object cannot result in a sub-class by definition).
101 */
102Class* RegType::ClassJoin(Class* s, Class* t) {
103 DCHECK(!s->IsPrimitive()) << PrettyClass(s);
104 DCHECK(!t->IsPrimitive()) << PrettyClass(t);
105 if (s == t) {
106 return s;
107 } else if (s->IsAssignableFrom(t)) {
108 return s;
109 } else if (t->IsAssignableFrom(s)) {
110 return t;
111 } else if (s->IsArrayClass() && t->IsArrayClass()) {
112 Class* s_ct = s->GetComponentType();
113 Class* t_ct = t->GetComponentType();
114 if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) {
115 // Given the types aren't the same, if either array is of primitive types then the only
116 // common parent is java.lang.Object
117 Class* result = s->GetSuperClass(); // short-cut to java.lang.Object
118 DCHECK(result->IsObjectClass());
119 return result;
Ian Rogers776ac1f2012-04-13 23:36:36 -0700120 }
Ian Rogerse1758fe2012-04-19 11:31:15 -0700121 Class* common_elem = ClassJoin(s_ct, t_ct);
122 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
123 const ClassLoader* class_loader = s->GetClassLoader();
124 std::string descriptor("[");
125 descriptor += ClassHelper(common_elem).GetDescriptor();
126 Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
127 DCHECK(array_class != NULL);
128 return array_class;
Ian Rogers0d604842012-04-16 14:50:24 -0700129 } else {
Ian Rogerse1758fe2012-04-19 11:31:15 -0700130 size_t s_depth = s->Depth();
131 size_t t_depth = t->Depth();
132 // Get s and t to the same depth in the hierarchy
133 if (s_depth > t_depth) {
134 while (s_depth > t_depth) {
135 s = s->GetSuperClass();
136 s_depth--;
137 }
Ian Rogers0d604842012-04-16 14:50:24 -0700138 } else {
Ian Rogerse1758fe2012-04-19 11:31:15 -0700139 while (t_depth > s_depth) {
140 t = t->GetSuperClass();
141 t_depth--;
142 }
Ian Rogers776ac1f2012-04-13 23:36:36 -0700143 }
Ian Rogerse1758fe2012-04-19 11:31:15 -0700144 // Go up the hierarchy until we get to the common parent
145 while (s != t) {
146 s = s->GetSuperClass();
147 t = t->GetSuperClass();
148 }
149 return s;
Ian Rogers776ac1f2012-04-13 23:36:36 -0700150 }
151}
152
153bool RegType::IsAssignableFrom(const RegType& src) const {
154 if (Equals(src)) {
155 return true;
156 } else {
157 switch (GetType()) {
158 case RegType::kRegTypeBoolean: return src.IsBooleanTypes();
159 case RegType::kRegTypeByte: return src.IsByteTypes();
160 case RegType::kRegTypeShort: return src.IsShortTypes();
161 case RegType::kRegTypeChar: return src.IsCharTypes();
162 case RegType::kRegTypeInteger: return src.IsIntegralTypes();
163 case RegType::kRegTypeFloat: return src.IsFloatTypes();
164 case RegType::kRegTypeLongLo: return src.IsLongTypes();
165 case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
166 default:
167 if (!IsReferenceTypes()) {
168 LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
169 }
170 if (src.IsZero()) {
171 return true; // all reference types can be assigned null
172 } else if (!src.IsReferenceTypes()) {
173 return false; // expect src to be a reference type
174 } else if (IsJavaLangObject()) {
175 return true; // all reference types can be assigned to Object
176 } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
177 return true; // We allow assignment to any interface, see comment in ClassJoin
178 } else if (IsJavaLangObjectArray()) {
179 return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
180 } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
181 GetClass()->IsAssignableFrom(src.GetClass())) {
182 // We're assignable from the Class point-of-view
183 return true;
184 } else {
185 return false;
186 }
187 }
188 }
189}
190
191static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
192 return a.IsConstant() ? b : a;
193}
194
195const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
196 DCHECK(!Equals(incoming_type)); // Trivial equality handled by caller
Ian Rogerse1758fe2012-04-19 11:31:15 -0700197 if (IsUnknown() && incoming_type.IsUnknown()) {
198 return *this; // Unknown MERGE Unknown => Unknown
Ian Rogers776ac1f2012-04-13 23:36:36 -0700199 } else if (IsConflict()) {
200 return *this; // Conflict MERGE * => Conflict
201 } else if (incoming_type.IsConflict()) {
202 return incoming_type; // * MERGE Conflict => Conflict
Ian Rogerse1758fe2012-04-19 11:31:15 -0700203 } else if (IsUnknown() || incoming_type.IsUnknown()) {
Ian Rogers776ac1f2012-04-13 23:36:36 -0700204 return reg_types->Conflict(); // Unknown MERGE * => Conflict
205 } else if (IsConstant() && incoming_type.IsConstant()) {
206 int32_t val1 = ConstantValue();
207 int32_t val2 = incoming_type.ConstantValue();
208 if (val1 >= 0 && val2 >= 0) {
209 // +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
210 if (val1 >= val2) {
211 return *this;
212 } else {
213 return incoming_type;
214 }
215 } else if (val1 < 0 && val2 < 0) {
216 // -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
217 if (val1 <= val2) {
218 return *this;
219 } else {
220 return incoming_type;
221 }
222 } else {
223 // Values are +ve and -ve, choose smallest signed type in which they both fit
224 if (IsConstantByte()) {
225 if (incoming_type.IsConstantByte()) {
226 return reg_types->ByteConstant();
227 } else if (incoming_type.IsConstantShort()) {
228 return reg_types->ShortConstant();
229 } else {
230 return reg_types->IntConstant();
231 }
232 } else if (IsConstantShort()) {
233 if (incoming_type.IsConstantShort()) {
234 return reg_types->ShortConstant();
235 } else {
236 return reg_types->IntConstant();
237 }
238 } else {
239 return reg_types->IntConstant();
240 }
241 }
242 } else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
243 if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
244 return reg_types->Boolean(); // boolean MERGE boolean => boolean
245 }
246 if (IsByteTypes() && incoming_type.IsByteTypes()) {
247 return reg_types->Byte(); // byte MERGE byte => byte
248 }
249 if (IsShortTypes() && incoming_type.IsShortTypes()) {
250 return reg_types->Short(); // short MERGE short => short
251 }
252 if (IsCharTypes() && incoming_type.IsCharTypes()) {
253 return reg_types->Char(); // char MERGE char => char
254 }
255 return reg_types->Integer(); // int MERGE * => int
256 } else if ((IsFloatTypes() && incoming_type.IsFloatTypes()) ||
257 (IsLongTypes() && incoming_type.IsLongTypes()) ||
258 (IsLongHighTypes() && incoming_type.IsLongHighTypes()) ||
259 (IsDoubleTypes() && incoming_type.IsDoubleTypes()) ||
260 (IsDoubleHighTypes() && incoming_type.IsDoubleHighTypes())) {
261 // check constant case was handled prior to entry
262 DCHECK(!IsConstant() || !incoming_type.IsConstant());
263 // float/long/double MERGE float/long/double_constant => float/long/double
264 return SelectNonConstant(*this, incoming_type);
265 } else if (IsReferenceTypes() && incoming_type.IsReferenceTypes()) {
266 if (IsZero() || incoming_type.IsZero()) {
267 return SelectNonConstant(*this, incoming_type); // 0 MERGE ref => ref
268 } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
269 return reg_types->JavaLangObject(); // Object MERGE ref => Object
270 } else if (IsUninitializedTypes() || incoming_type.IsUninitializedTypes() ||
271 IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
272 // Can only merge an unresolved or uninitialized type with itself, 0 or Object, we've already
273 // checked these so => Conflict
274 return reg_types->Conflict();
275 } else { // Two reference types, compute Join
276 Class* c1 = GetClass();
277 Class* c2 = incoming_type.GetClass();
278 DCHECK(c1 != NULL && !c1->IsPrimitive());
279 DCHECK(c2 != NULL && !c2->IsPrimitive());
280 Class* join_class = ClassJoin(c1, c2);
281 if (c1 == join_class) {
282 return *this;
283 } else if (c2 == join_class) {
284 return incoming_type;
285 } else {
286 return reg_types->FromClass(join_class);
287 }
288 }
289 } else {
290 return reg_types->Conflict(); // Unexpected types => Conflict
291 }
292}
293
Ian Rogers776ac1f2012-04-13 23:36:36 -0700294std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
295 os << rhs.Dump();
296 return os;
297}
298
299} // verifier
300} // art