1 /*
2 * Copyright (C) 2011 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 "dex_cache-inl.h"
18
19 #include "art_method-inl.h"
20 #include "class_linker.h"
21 #include "gc/accounting/card_table-inl.h"
22 #include "gc/heap.h"
23 #include "jit/profile_saver.h"
24 #include "linear_alloc.h"
25 #include "oat_file.h"
26 #include "object-inl.h"
27 #include "object.h"
28 #include "object_array-inl.h"
29 #include "reflective_value_visitor.h"
30 #include "runtime.h"
31 #include "runtime_globals.h"
32 #include "string.h"
33 #include "thread.h"
34 #include "write_barrier.h"
35
36 namespace art {
37 namespace mirror {
38
39 // Whether to allocate full dex cache arrays during startup. Currently disabled
40 // while debugging b/283632504.
41 static constexpr bool kEnableFullArraysAtStartup = false;
42
Initialize(const DexFile * dex_file,ObjPtr<ClassLoader> class_loader)43 void DexCache::Initialize(const DexFile* dex_file, ObjPtr<ClassLoader> class_loader) {
44 DCHECK(GetDexFile() == nullptr);
45 DCHECK(GetStrings() == nullptr);
46 DCHECK(GetResolvedTypes() == nullptr);
47 DCHECK(GetResolvedMethods() == nullptr);
48 DCHECK(GetResolvedFields() == nullptr);
49 DCHECK(GetResolvedMethodTypes() == nullptr);
50 DCHECK(GetResolvedCallSites() == nullptr);
51
52 ScopedAssertNoThreadSuspension sants(__FUNCTION__);
53
54 SetDexFile(dex_file);
55 SetClassLoader(class_loader);
56 }
57
VisitReflectiveTargets(ReflectiveValueVisitor * visitor)58 void DexCache::VisitReflectiveTargets(ReflectiveValueVisitor* visitor) {
59 bool wrote = false;
60 auto* fields = GetResolvedFields();
61 size_t num_fields = NumResolvedFields();
62 // Check both the data pointer and count since the array might be initialized
63 // concurrently on other thread, and we might observe just one of the values.
64 for (size_t i = 0; fields != nullptr && i < num_fields; i++) {
65 auto pair(fields->GetNativePair(i));
66 if (pair.index == NativeDexCachePair<ArtField>::InvalidIndexForSlot(i)) {
67 continue;
68 }
69 ArtField* new_val = visitor->VisitField(
70 pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedField, pair.index, this));
71 if (UNLIKELY(new_val != pair.object)) {
72 if (new_val == nullptr) {
73 pair = NativeDexCachePair<ArtField>(
74 nullptr, NativeDexCachePair<ArtField>::InvalidIndexForSlot(i));
75 } else {
76 pair.object = new_val;
77 }
78 fields->SetNativePair(i, pair);
79 wrote = true;
80 }
81 }
82 auto* methods = GetResolvedMethods();
83 size_t num_methods = NumResolvedMethods();
84 // Check both the data pointer and count since the array might be initialized
85 // concurrently on other thread, and we might observe just one of the values.
86 for (size_t i = 0; methods != nullptr && i < num_methods; i++) {
87 auto pair(methods->GetNativePair(i));
88 if (pair.index == NativeDexCachePair<ArtMethod>::InvalidIndexForSlot(i)) {
89 continue;
90 }
91 ArtMethod* new_val = visitor->VisitMethod(
92 pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, pair.index, this));
93 if (UNLIKELY(new_val != pair.object)) {
94 if (new_val == nullptr) {
95 pair = NativeDexCachePair<ArtMethod>(
96 nullptr, NativeDexCachePair<ArtMethod>::InvalidIndexForSlot(i));
97 } else {
98 pair.object = new_val;
99 }
100 methods->SetNativePair(i, pair);
101 wrote = true;
102 }
103 }
104
105 auto* fields_array = GetResolvedFieldsArray();
106 num_fields = NumResolvedFieldsArray();
107 for (size_t i = 0; fields_array != nullptr && i < num_fields; i++) {
108 ArtField* old_val = fields_array->Get(i);
109 if (old_val == nullptr) {
110 continue;
111 }
112 ArtField* new_val = visitor->VisitField(
113 old_val, DexCacheSourceInfo(kSourceDexCacheResolvedField, i, this));
114 if (new_val != old_val) {
115 fields_array->Set(i, new_val);
116 wrote = true;
117 }
118 }
119
120 auto* methods_array = GetResolvedMethodsArray();
121 num_methods = NumResolvedMethodsArray();
122 for (size_t i = 0; methods_array != nullptr && i < num_methods; i++) {
123 ArtMethod* old_val = methods_array->Get(i);
124 if (old_val == nullptr) {
125 continue;
126 }
127 ArtMethod* new_val = visitor->VisitMethod(
128 old_val, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, i, this));
129 if (new_val != old_val) {
130 methods_array->Set(i, new_val);
131 wrote = true;
132 }
133 }
134
135 if (wrote) {
136 WriteBarrier::ForEveryFieldWrite(this);
137 }
138 }
139
ResetNativeArrays()140 void DexCache::ResetNativeArrays() {
141 SetStrings(nullptr);
142 SetResolvedTypes(nullptr);
143 SetResolvedMethods(nullptr);
144 SetResolvedFields(nullptr);
145 SetResolvedMethodTypes(nullptr);
146 SetResolvedCallSites(nullptr);
147
148 SetStringsArray(nullptr);
149 SetResolvedTypesArray(nullptr);
150 SetResolvedMethodsArray(nullptr);
151 SetResolvedFieldsArray(nullptr);
152 SetResolvedMethodTypesArray(nullptr);
153 }
154
SetLocation(ObjPtr<mirror::String> location)155 void DexCache::SetLocation(ObjPtr<mirror::String> location) {
156 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
157 }
158
SetClassLoader(ObjPtr<ClassLoader> class_loader)159 void DexCache::SetClassLoader(ObjPtr<ClassLoader> class_loader) {
160 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_), class_loader);
161 }
162
GetClassLoader()163 ObjPtr<ClassLoader> DexCache::GetClassLoader() {
164 return GetFieldObject<ClassLoader>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_));
165 }
166
ShouldAllocateFullArrayAtStartup()167 bool DexCache::ShouldAllocateFullArrayAtStartup() {
168 if (!kEnableFullArraysAtStartup) {
169 return false;
170 }
171 Runtime* runtime = Runtime::Current();
172 if (runtime->IsAotCompiler()) {
173 // To save on memory in dex2oat, we don't allocate full arrays by default.
174 return false;
175 }
176
177 if (runtime->IsZygote()) {
178 // Zygote doesn't have a notion of startup.
179 return false;
180 }
181
182 if (runtime->GetStartupCompleted()) {
183 // We only allocate full arrays during app startup.
184 return false;
185 }
186
187 if (GetClassLoader() == nullptr) {
188 // Only allocate full array for app dex files (also note that for
189 // multi-image, the `GetCompilerFilter` call below does not work for
190 // non-primary oat files).
191 return false;
192 }
193
194 const OatDexFile* oat_dex_file = GetDexFile()->GetOatDexFile();
195 if (oat_dex_file != nullptr &&
196 CompilerFilter::IsAotCompilationEnabled(oat_dex_file->GetOatFile()->GetCompilerFilter())) {
197 // We only allocate full arrays for dex files where we do not have
198 // compilation.
199 return false;
200 }
201
202 return true;
203 }
204
UnlinkStartupCaches()205 void DexCache::UnlinkStartupCaches() {
206 if (GetDexFile() == nullptr) {
207 // Unused dex cache.
208 return;
209 }
210 UnlinkStringsArrayIfStartup();
211 UnlinkResolvedFieldsArrayIfStartup();
212 UnlinkResolvedMethodsArrayIfStartup();
213 UnlinkResolvedTypesArrayIfStartup();
214 UnlinkResolvedMethodTypesArrayIfStartup();
215 }
216
SetResolvedType(dex::TypeIndex type_idx,ObjPtr<Class> resolved)217 void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
218 DCHECK(resolved != nullptr);
219 DCHECK(resolved->IsResolved()) << resolved->GetStatus();
220 // TODO default transaction support.
221 // Use a release store for SetResolvedType. This is done to prevent other threads from seeing a
222 // class but not necessarily seeing the loaded members like the static fields array.
223 // See b/32075261.
224 SetResolvedTypesEntry(type_idx.index_, resolved.Ptr());
225 // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
226 WriteBarrier::ForEveryFieldWrite(this);
227
228 if (this == resolved->GetDexCache()) {
229 // If we're updating the dex cache of the class, optimistically update the cache for methods and
230 // fields if the caches are full arrays.
231 auto* resolved_methods = GetResolvedMethodsArray();
232 if (resolved_methods != nullptr) {
233 PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
234 // Because there could be duplicate method entries, we make sure we only
235 // update the cache with the first one found to be consistent with method
236 // resolution.
237 uint32_t previous_method_index = dex::kDexNoIndex;
238 for (ArtMethod& current_method : resolved->GetDeclaredMethods(pointer_size)) {
239 uint32_t new_index = current_method.GetDexMethodIndex();
240 if (new_index != previous_method_index) {
241 resolved_methods->Set(new_index, ¤t_method);
242 previous_method_index = new_index;
243 }
244 }
245 }
246 auto* resolved_fields = GetResolvedFieldsArray();
247 if (resolved_fields != nullptr) {
248 for (ArtField& current_field : resolved->GetSFields()) {
249 resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field);
250 }
251 for (ArtField& current_field : resolved->GetIFields()) {
252 resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field);
253 }
254 }
255 }
256 }
257
258 } // namespace mirror
259 } // namespace art
260