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 "linear_alloc.h"
24 #include "oat_file.h"
25 #include "object-inl.h"
26 #include "object.h"
27 #include "object_array-inl.h"
28 #include "reflective_value_visitor.h"
29 #include "runtime.h"
30 #include "runtime_globals.h"
31 #include "string.h"
32 #include "thread.h"
33 #include "utils/dex_cache_arrays_layout-inl.h"
34 #include "write_barrier.h"
35
36 namespace art {
37 namespace mirror {
38
InitializeDexCache(Thread * self,ObjPtr<mirror::DexCache> dex_cache,ObjPtr<mirror::String> location,const DexFile * dex_file,LinearAlloc * linear_alloc,PointerSize image_pointer_size)39 void DexCache::InitializeDexCache(Thread* self,
40 ObjPtr<mirror::DexCache> dex_cache,
41 ObjPtr<mirror::String> location,
42 const DexFile* dex_file,
43 LinearAlloc* linear_alloc,
44 PointerSize image_pointer_size) {
45 DCHECK(dex_file != nullptr);
46 ScopedAssertNoThreadSuspension sants(__FUNCTION__);
47 DexCacheArraysLayout layout(image_pointer_size, dex_file);
48 uint8_t* raw_arrays = nullptr;
49
50 if (dex_file->NumStringIds() != 0u ||
51 dex_file->NumTypeIds() != 0u ||
52 dex_file->NumMethodIds() != 0u ||
53 dex_file->NumFieldIds() != 0u) {
54 static_assert(ArenaAllocator::kAlignment == 8, "Expecting arena alignment of 8.");
55 DCHECK(layout.Alignment() == 8u || layout.Alignment() == 16u);
56 // Zero-initialized.
57 raw_arrays = (layout.Alignment() == 16u)
58 ? reinterpret_cast<uint8_t*>(linear_alloc->AllocAlign16(self, layout.Size()))
59 : reinterpret_cast<uint8_t*>(linear_alloc->Alloc(self, layout.Size()));
60 }
61
62 StringDexCacheType* strings = (dex_file->NumStringIds() == 0u) ? nullptr :
63 reinterpret_cast<StringDexCacheType*>(raw_arrays + layout.StringsOffset());
64 TypeDexCacheType* types = (dex_file->NumTypeIds() == 0u) ? nullptr :
65 reinterpret_cast<TypeDexCacheType*>(raw_arrays + layout.TypesOffset());
66 MethodDexCacheType* methods = (dex_file->NumMethodIds() == 0u) ? nullptr :
67 reinterpret_cast<MethodDexCacheType*>(raw_arrays + layout.MethodsOffset());
68 FieldDexCacheType* fields = (dex_file->NumFieldIds() == 0u) ? nullptr :
69 reinterpret_cast<FieldDexCacheType*>(raw_arrays + layout.FieldsOffset());
70
71 size_t num_strings = kDexCacheStringCacheSize;
72 if (dex_file->NumStringIds() < num_strings) {
73 num_strings = dex_file->NumStringIds();
74 }
75 size_t num_types = kDexCacheTypeCacheSize;
76 if (dex_file->NumTypeIds() < num_types) {
77 num_types = dex_file->NumTypeIds();
78 }
79 size_t num_fields = kDexCacheFieldCacheSize;
80 if (dex_file->NumFieldIds() < num_fields) {
81 num_fields = dex_file->NumFieldIds();
82 }
83 size_t num_methods = kDexCacheMethodCacheSize;
84 if (dex_file->NumMethodIds() < num_methods) {
85 num_methods = dex_file->NumMethodIds();
86 }
87
88 // Note that we allocate the method type dex caches regardless of this flag,
89 // and we make sure here that they're not used by the runtime. This is in the
90 // interest of simplicity and to avoid extensive compiler and layout class changes.
91 //
92 // If this needs to be mitigated in a production system running this code,
93 // DexCache::kDexCacheMethodTypeCacheSize can be set to zero.
94 MethodTypeDexCacheType* method_types = nullptr;
95 size_t num_method_types = 0;
96
97 if (dex_file->NumProtoIds() < kDexCacheMethodTypeCacheSize) {
98 num_method_types = dex_file->NumProtoIds();
99 } else {
100 num_method_types = kDexCacheMethodTypeCacheSize;
101 }
102
103 if (num_method_types > 0) {
104 method_types = reinterpret_cast<MethodTypeDexCacheType*>(
105 raw_arrays + layout.MethodTypesOffset());
106 }
107
108 GcRoot<mirror::CallSite>* call_sites = (dex_file->NumCallSiteIds() == 0)
109 ? nullptr
110 : reinterpret_cast<GcRoot<CallSite>*>(raw_arrays + layout.CallSitesOffset());
111
112 DCHECK_ALIGNED(raw_arrays, alignof(StringDexCacheType)) <<
113 "Expected raw_arrays to align to StringDexCacheType.";
114 DCHECK_ALIGNED(layout.StringsOffset(), alignof(StringDexCacheType)) <<
115 "Expected StringsOffset() to align to StringDexCacheType.";
116 DCHECK_ALIGNED(strings, alignof(StringDexCacheType)) <<
117 "Expected strings to align to StringDexCacheType.";
118 static_assert(alignof(StringDexCacheType) == 8u,
119 "Expected StringDexCacheType to have align of 8.");
120 if (kIsDebugBuild) {
121 // Consistency check to make sure all the dex cache arrays are empty. b/28992179
122 for (size_t i = 0; i < num_strings; ++i) {
123 CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u);
124 CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull());
125 }
126 for (size_t i = 0; i < num_types; ++i) {
127 CHECK_EQ(types[i].load(std::memory_order_relaxed).index, 0u);
128 CHECK(types[i].load(std::memory_order_relaxed).object.IsNull());
129 }
130 for (size_t i = 0; i < num_methods; ++i) {
131 CHECK_EQ(GetNativePairPtrSize(methods, i, image_pointer_size).index, 0u);
132 CHECK(GetNativePairPtrSize(methods, i, image_pointer_size).object == nullptr);
133 }
134 for (size_t i = 0; i < num_fields; ++i) {
135 CHECK_EQ(GetNativePairPtrSize(fields, i, image_pointer_size).index, 0u);
136 CHECK(GetNativePairPtrSize(fields, i, image_pointer_size).object == nullptr);
137 }
138 for (size_t i = 0; i < num_method_types; ++i) {
139 CHECK_EQ(method_types[i].load(std::memory_order_relaxed).index, 0u);
140 CHECK(method_types[i].load(std::memory_order_relaxed).object.IsNull());
141 }
142 for (size_t i = 0; i < dex_file->NumCallSiteIds(); ++i) {
143 CHECK(call_sites[i].IsNull());
144 }
145 }
146 if (strings != nullptr) {
147 mirror::StringDexCachePair::Initialize(strings);
148 }
149 if (types != nullptr) {
150 mirror::TypeDexCachePair::Initialize(types);
151 }
152 if (fields != nullptr) {
153 mirror::FieldDexCachePair::Initialize(fields, image_pointer_size);
154 }
155 if (methods != nullptr) {
156 mirror::MethodDexCachePair::Initialize(methods, image_pointer_size);
157 }
158 if (method_types != nullptr) {
159 mirror::MethodTypeDexCachePair::Initialize(method_types);
160 }
161 dex_cache->Init(dex_file,
162 location,
163 strings,
164 num_strings,
165 types,
166 num_types,
167 methods,
168 num_methods,
169 fields,
170 num_fields,
171 method_types,
172 num_method_types,
173 call_sites,
174 dex_file->NumCallSiteIds());
175 }
176
VisitReflectiveTargets(ReflectiveValueVisitor * visitor)177 void DexCache::VisitReflectiveTargets(ReflectiveValueVisitor* visitor) {
178 bool wrote = false;
179 for (size_t i = 0; i < NumResolvedFields(); i++) {
180 auto pair(GetNativePairPtrSize(GetResolvedFields(), i, kRuntimePointerSize));
181 if (pair.index == FieldDexCachePair::InvalidIndexForSlot(i)) {
182 continue;
183 }
184 ArtField* new_val = visitor->VisitField(
185 pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedField, pair.index, this));
186 if (UNLIKELY(new_val != pair.object)) {
187 if (new_val == nullptr) {
188 pair = FieldDexCachePair(nullptr, FieldDexCachePair::InvalidIndexForSlot(i));
189 } else {
190 pair.object = new_val;
191 }
192 SetNativePairPtrSize(GetResolvedFields(), i, pair, kRuntimePointerSize);
193 wrote = true;
194 }
195 }
196 for (size_t i = 0; i < NumResolvedMethods(); i++) {
197 auto pair(GetNativePairPtrSize(GetResolvedMethods(), i, kRuntimePointerSize));
198 if (pair.index == MethodDexCachePair::InvalidIndexForSlot(i)) {
199 continue;
200 }
201 ArtMethod* new_val = visitor->VisitMethod(
202 pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, pair.index, this));
203 if (UNLIKELY(new_val != pair.object)) {
204 if (new_val == nullptr) {
205 pair = MethodDexCachePair(nullptr, MethodDexCachePair::InvalidIndexForSlot(i));
206 } else {
207 pair.object = new_val;
208 }
209 SetNativePairPtrSize(GetResolvedMethods(), i, pair, kRuntimePointerSize);
210 wrote = true;
211 }
212 }
213 if (wrote) {
214 WriteBarrier::ForEveryFieldWrite(this);
215 }
216 }
217
AddPreResolvedStringsArray()218 bool DexCache::AddPreResolvedStringsArray() {
219 DCHECK_EQ(NumPreResolvedStrings(), 0u);
220 Thread* const self = Thread::Current();
221 LinearAlloc* linear_alloc = Runtime::Current()->GetLinearAlloc();
222 const size_t num_strings = GetDexFile()->NumStringIds();
223 if (num_strings != 0) {
224 GcRoot<mirror::String>* strings =
225 linear_alloc->AllocArray<GcRoot<mirror::String>>(self, num_strings);
226 if (strings == nullptr) {
227 // Failed to allocate pre-resolved string array (probably due to address fragmentation), bail.
228 return false;
229 }
230 SetField32<false>(NumPreResolvedStringsOffset(), num_strings);
231
232 CHECK(strings != nullptr);
233 SetPreResolvedStrings(strings);
234 for (size_t i = 0; i < GetDexFile()->NumStringIds(); ++i) {
235 CHECK(GetPreResolvedStrings()[i].Read() == nullptr);
236 }
237 }
238 return true;
239 }
240
Init(const DexFile * dex_file,ObjPtr<String> location,StringDexCacheType * strings,uint32_t num_strings,TypeDexCacheType * resolved_types,uint32_t num_resolved_types,MethodDexCacheType * resolved_methods,uint32_t num_resolved_methods,FieldDexCacheType * resolved_fields,uint32_t num_resolved_fields,MethodTypeDexCacheType * resolved_method_types,uint32_t num_resolved_method_types,GcRoot<CallSite> * resolved_call_sites,uint32_t num_resolved_call_sites)241 void DexCache::Init(const DexFile* dex_file,
242 ObjPtr<String> location,
243 StringDexCacheType* strings,
244 uint32_t num_strings,
245 TypeDexCacheType* resolved_types,
246 uint32_t num_resolved_types,
247 MethodDexCacheType* resolved_methods,
248 uint32_t num_resolved_methods,
249 FieldDexCacheType* resolved_fields,
250 uint32_t num_resolved_fields,
251 MethodTypeDexCacheType* resolved_method_types,
252 uint32_t num_resolved_method_types,
253 GcRoot<CallSite>* resolved_call_sites,
254 uint32_t num_resolved_call_sites) {
255 CHECK(dex_file != nullptr);
256 CHECK(location != nullptr);
257 CHECK_EQ(num_strings != 0u, strings != nullptr);
258 CHECK_EQ(num_resolved_types != 0u, resolved_types != nullptr);
259 CHECK_EQ(num_resolved_methods != 0u, resolved_methods != nullptr);
260 CHECK_EQ(num_resolved_fields != 0u, resolved_fields != nullptr);
261 CHECK_EQ(num_resolved_method_types != 0u, resolved_method_types != nullptr);
262 CHECK_EQ(num_resolved_call_sites != 0u, resolved_call_sites != nullptr);
263
264 SetDexFile(dex_file);
265 SetLocation(location);
266 SetStrings(strings);
267 SetResolvedTypes(resolved_types);
268 SetResolvedMethods(resolved_methods);
269 SetResolvedFields(resolved_fields);
270 SetResolvedMethodTypes(resolved_method_types);
271 SetResolvedCallSites(resolved_call_sites);
272 SetField32<false>(NumStringsOffset(), num_strings);
273 SetField32<false>(NumResolvedTypesOffset(), num_resolved_types);
274 SetField32<false>(NumResolvedMethodsOffset(), num_resolved_methods);
275 SetField32<false>(NumResolvedFieldsOffset(), num_resolved_fields);
276 SetField32<false>(NumResolvedMethodTypesOffset(), num_resolved_method_types);
277 SetField32<false>(NumResolvedCallSitesOffset(), num_resolved_call_sites);
278 }
279
SetLocation(ObjPtr<mirror::String> location)280 void DexCache::SetLocation(ObjPtr<mirror::String> location) {
281 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
282 }
283
SetClassLoader(ObjPtr<ClassLoader> class_loader)284 void DexCache::SetClassLoader(ObjPtr<ClassLoader> class_loader) {
285 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_), class_loader);
286 }
287
288 #if !defined(__aarch64__) && !defined(__x86_64__)
289 static pthread_mutex_t dex_cache_slow_atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
290
AtomicLoadRelaxed16B(std::atomic<ConversionPair64> * target)291 DexCache::ConversionPair64 DexCache::AtomicLoadRelaxed16B(std::atomic<ConversionPair64>* target) {
292 pthread_mutex_lock(&dex_cache_slow_atomic_mutex);
293 DexCache::ConversionPair64 value = *reinterpret_cast<ConversionPair64*>(target);
294 pthread_mutex_unlock(&dex_cache_slow_atomic_mutex);
295 return value;
296 }
297
AtomicStoreRelease16B(std::atomic<ConversionPair64> * target,ConversionPair64 value)298 void DexCache::AtomicStoreRelease16B(std::atomic<ConversionPair64>* target,
299 ConversionPair64 value) {
300 pthread_mutex_lock(&dex_cache_slow_atomic_mutex);
301 *reinterpret_cast<ConversionPair64*>(target) = value;
302 pthread_mutex_unlock(&dex_cache_slow_atomic_mutex);
303 }
304 #endif
305
306 } // namespace mirror
307 } // namespace art
308