blob: 4953483ffee372d178c9f195dd54a6ccf222f4eb [file] [log] [blame]
David Brazdilca3c8c32016-09-06 14:04:48 +01001/*
2 * Copyright (C) 2016 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 "verifier_deps.h"
18
19#include "compiler_callbacks.h"
20#include "mirror/class-inl.h"
21#include "runtime.h"
22
23namespace art {
24namespace verifier {
25
26VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) {
27 MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
28 for (const DexFile* dex_file : dex_files) {
29 DCHECK(GetDexFileDeps(*dex_file) == nullptr);
30 std::unique_ptr<DexFileDeps> deps(new DexFileDeps());
31 dex_deps_.emplace(dex_file, std::move(deps));
32 }
33}
34
35VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
36 auto it = dex_deps_.find(&dex_file);
37 return (it == dex_deps_.end()) ? nullptr : it->second.get();
38}
39
40template <typename T>
41uint16_t VerifierDeps::GetAccessFlags(T* element) {
42 static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
43 if (element == nullptr) {
44 return VerifierDeps::kUnresolvedMarker;
45 } else {
46 uint16_t access_flags = Low16Bits(element->GetAccessFlags());
47 CHECK_NE(access_flags, VerifierDeps::kUnresolvedMarker);
48 return access_flags;
49 }
50}
51
52template <typename T>
53uint32_t VerifierDeps::GetDeclaringClassStringId(const DexFile& dex_file, T* element) {
54 static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
55 if (element == nullptr) {
56 return VerifierDeps::kUnresolvedMarker;
57 } else {
58 std::string temp;
59 uint32_t string_id = GetIdFromString(
60 dex_file, element->GetDeclaringClass()->GetDescriptor(&temp));
61 return string_id;
62 }
63}
64
65uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
66 const DexFile::StringId* string_id = dex_file.FindStringId(str.c_str());
67 if (string_id != nullptr) {
68 // String is in the DEX file. Return its ID.
69 return dex_file.GetIndexForStringId(*string_id);
70 }
71
72 // String is not in the DEX file. Assign a new ID to it which is higher than
73 // the number of strings in the DEX file.
74
75 DexFileDeps* deps = GetDexFileDeps(dex_file);
76 DCHECK(deps != nullptr);
77
78 uint32_t num_ids_in_dex = dex_file.NumStringIds();
79 uint32_t num_extra_ids = deps->strings_.size();
80
81 for (size_t i = 0; i < num_extra_ids; ++i) {
82 if (deps->strings_[i] == str) {
83 return num_ids_in_dex + i;
84 }
85 }
86
87 deps->strings_.push_back(str);
88
89 uint32_t new_id = num_ids_in_dex + num_extra_ids;
90 CHECK_GE(new_id, num_ids_in_dex); // check for overflows
91 DCHECK_EQ(str, GetStringFromId(dex_file, new_id));
92
93 return new_id;
94}
95
96std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) {
97 uint32_t num_ids_in_dex = dex_file.NumStringIds();
98 if (string_id < num_ids_in_dex) {
99 return std::string(dex_file.StringDataByIdx(string_id));
100 } else {
101 DexFileDeps* deps = GetDexFileDeps(dex_file);
102 DCHECK(deps != nullptr);
103 string_id -= num_ids_in_dex;
104 CHECK_LT(string_id, deps->strings_.size());
105 return deps->strings_[string_id];
106 }
107}
108
109bool VerifierDeps::IsInClassPath(mirror::Class* klass) {
110 DCHECK(klass != nullptr);
111
112 mirror::DexCache* dex_cache = klass->GetDexCache();
113 if (dex_cache == nullptr) {
114 // This is a synthesized class, in this case always an array. They are not
115 // defined in the compiled DEX files and therefore are part of the classpath.
116 // We could avoid recording dependencies on arrays with component types in
117 // the compiled DEX files but we choose to record them anyway so as to
118 // record the access flags VM sets for array classes.
119 DCHECK(klass->IsArrayClass()) << PrettyDescriptor(klass);
120 return true;
121 }
122
123 const DexFile* dex_file = dex_cache->GetDexFile();
124 DCHECK(dex_file != nullptr);
125
126 // Test if the `dex_deps_` contains an entry for `dex_file`. If not, the dex
127 // file was not registered as being compiled and we assume `klass` is in the
128 // classpath.
129 return (GetDexFileDeps(*dex_file) == nullptr);
130}
131
132void VerifierDeps::AddClassResolution(const DexFile& dex_file,
133 uint16_t type_idx,
134 mirror::Class* klass) {
135 DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
136 if (dex_deps == nullptr) {
137 // This invocation is from verification of a dex file which is not being compiled.
138 return;
139 }
140
141 if (klass != nullptr && !IsInClassPath(klass)) {
142 // Class resolved into one of the DEX files which are being compiled.
143 // This is not a classpath dependency.
144 return;
145 }
146
147 MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
148 dex_deps->classes_.emplace(ClassResolution(type_idx, GetAccessFlags(klass)));
149}
150
151void VerifierDeps::AddFieldResolution(const DexFile& dex_file,
152 uint32_t field_idx,
153 ArtField* field) {
154 DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
155 if (dex_deps == nullptr) {
156 // This invocation is from verification of a dex file which is not being compiled.
157 return;
158 }
159
160 if (field != nullptr && !IsInClassPath(field->GetDeclaringClass())) {
161 // Field resolved into one of the DEX files which are being compiled.
162 // This is not a classpath dependency.
163 return;
164 }
165
166 MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
167 dex_deps->fields_.emplace(FieldResolution(
168 field_idx, GetAccessFlags(field), GetDeclaringClassStringId(dex_file, field)));
169}
170
171void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
172 uint32_t method_idx,
173 MethodResolutionKind resolution_kind,
174 ArtMethod* method) {
175 DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
176 if (dex_deps == nullptr) {
177 // This invocation is from verification of a dex file which is not being compiled.
178 return;
179 }
180
181 if (method != nullptr && !IsInClassPath(method->GetDeclaringClass())) {
182 // Method resolved into one of the DEX files which are being compiled.
183 // This is not a classpath dependency.
184 return;
185 }
186
187 MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
188 MethodResolution method_tuple(method_idx,
189 GetAccessFlags(method),
190 GetDeclaringClassStringId(dex_file, method));
191 if (resolution_kind == kDirectMethodResolution) {
192 dex_deps->direct_methods_.emplace(method_tuple);
193 } else if (resolution_kind == kVirtualMethodResolution) {
194 dex_deps->virtual_methods_.emplace(method_tuple);
195 } else {
196 DCHECK_EQ(resolution_kind, kInterfaceMethodResolution);
197 dex_deps->interface_methods_.emplace(method_tuple);
198 }
199}
200
201void VerifierDeps::AddAssignability(const DexFile& dex_file,
202 mirror::Class* destination,
203 mirror::Class* source,
204 bool is_strict,
205 bool is_assignable) {
206 // Test that the method is only called on reference types.
207 // Note that concurrent verification of `destination` and `source` may have
208 // set their status to erroneous. However, the tests performed below rely
209 // merely on no issues with linking (valid access flags, superclass and
210 // implemented interfaces). If the class at any point reached the IsResolved
211 // status, the requirement holds. This is guaranteed by RegTypeCache::ResolveClass.
212 DCHECK(destination != nullptr && !destination->IsPrimitive());
213 DCHECK(source != nullptr && !source->IsPrimitive());
214
215 if (destination == source ||
216 destination->IsObjectClass() ||
217 (!is_strict && destination->IsInterface())) {
218 // Cases when `destination` is trivially assignable from `source`.
219 DCHECK(is_assignable);
220 return;
221 }
222
223 DCHECK_EQ(is_assignable, destination->IsAssignableFrom(source));
224
225 if (destination->IsArrayClass() && source->IsArrayClass()) {
226 // Both types are arrays. Break down to component types and add recursively.
227 // This helps filter out destinations from compiled DEX files (see below)
228 // and deduplicate entries with the same canonical component type.
229 mirror::Class* destination_component = destination->GetComponentType();
230 mirror::Class* source_component = source->GetComponentType();
231
232 // Only perform the optimization if both types are resolved which guarantees
233 // that they linked successfully, as required at the top of this method.
234 if (destination_component->IsResolved() && source_component->IsResolved()) {
235 AddAssignability(dex_file,
236 destination_component,
237 source_component,
238 /* is_strict */ true,
239 is_assignable);
240 return;
241 }
242 }
243
244 DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
245 if (dex_deps == nullptr) {
246 // This invocation is from verification of a DEX file which is not being compiled.
247 return;
248 }
249
250 if (!IsInClassPath(destination) && !IsInClassPath(source)) {
251 // Both `destination` and `source` are defined in the compiled DEX files.
252 // No need to record a dependency.
253 return;
254 }
255
256 MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
257
258 // Get string IDs for both descriptors and store in the appropriate set.
259
260 std::string temp1, temp2;
261 std::string destination_desc(destination->GetDescriptor(&temp1));
262 std::string source_desc(source->GetDescriptor(&temp2));
263 uint32_t destination_id = GetIdFromString(dex_file, destination_desc);
264 uint32_t source_id = GetIdFromString(dex_file, source_desc);
265
266 if (is_assignable) {
267 dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
268 } else {
269 dex_deps->unassignable_types_.emplace(TypeAssignability(destination_id, source_id));
270 }
271}
272
273static inline VerifierDeps* GetVerifierDepsSingleton() {
274 CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
275 if (callbacks == nullptr) {
276 return nullptr;
277 }
278 return callbacks->GetVerifierDeps();
279}
280
281void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
282 uint16_t type_idx,
283 mirror::Class* klass) {
284 VerifierDeps* singleton = GetVerifierDepsSingleton();
285 if (singleton != nullptr) {
286 singleton->AddClassResolution(dex_file, type_idx, klass);
287 }
288}
289
290void VerifierDeps::MaybeRecordFieldResolution(const DexFile& dex_file,
291 uint32_t field_idx,
292 ArtField* field) {
293 VerifierDeps* singleton = GetVerifierDepsSingleton();
294 if (singleton != nullptr) {
295 singleton->AddFieldResolution(dex_file, field_idx, field);
296 }
297}
298
299void VerifierDeps::MaybeRecordMethodResolution(const DexFile& dex_file,
300 uint32_t method_idx,
301 MethodResolutionKind resolution_kind,
302 ArtMethod* method) {
303 VerifierDeps* singleton = GetVerifierDepsSingleton();
304 if (singleton != nullptr) {
305 singleton->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
306 }
307}
308
309void VerifierDeps::MaybeRecordAssignability(const DexFile& dex_file,
310 mirror::Class* destination,
311 mirror::Class* source,
312 bool is_strict,
313 bool is_assignable) {
314 VerifierDeps* singleton = GetVerifierDepsSingleton();
315 if (singleton != nullptr) {
316 singleton->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
317 }
318}
319
320} // namespace verifier
321} // namespace art