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[] = {
26 "Unknown",
27 "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 {
49 DCHECK(type_ >= kRegTypeUnknown && type_ <= kRegTypeReference);
50 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
87/*
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;
120 }
121 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;
129 } else {
130 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 }
138 } else {
139 while (t_depth > s_depth) {
140 t = t->GetSuperClass();
141 t_depth--;
142 }
143 }
144 // 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;
150 }
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
197 if (IsUnknown() && incoming_type.IsUnknown()) {
198 return *this; // Unknown MERGE Unknown => Unknown
199 } else if (IsConflict()) {
200 return *this; // Conflict MERGE * => Conflict
201 } else if (incoming_type.IsConflict()) {
202 return incoming_type; // * MERGE Conflict => Conflict
203 } else if (IsUnknown() || incoming_type.IsUnknown()) {
204 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
294std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
295 os << rhs.Dump();
296 return os;
297}
298
299} // verifier
300} // art