1 /*
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 <stdint.h>
18
19 #include "art_field-inl.h"
20 #include "art_method-inl.h"
21 #include "base/callee_save_type.h"
22 #include "callee_save_frame.h"
23 #include "dex/dex_file-inl.h"
24 #include "entrypoints/entrypoint_utils-inl.h"
25 #include "gc_root-inl.h"
26 #include "mirror/class-inl.h"
27 #include "mirror/object_reference.h"
28
29 namespace art HIDDEN {
30
31 // Fast path field resolution that can't initialize classes or throw exceptions.
FindFieldFast(uint32_t field_idx,ArtMethod * referrer,FindFieldType type,bool should_resolve_type=false)32 inline ArtField* FindFieldFast(uint32_t field_idx,
33 ArtMethod* referrer,
34 FindFieldType type,
35 bool should_resolve_type = false)
36 REQUIRES(!Roles::uninterruptible_)
37 REQUIRES_SHARED(Locks::mutator_lock_) {
38 ScopedAssertNoThreadSuspension ants(__FUNCTION__);
39 ArtField* resolved_field = referrer->GetDexCache()->GetResolvedField(field_idx);
40 if (UNLIKELY(resolved_field == nullptr)) {
41 return nullptr;
42 }
43 // Check for incompatible class change.
44 const bool is_set = (type & FindFieldFlags::WriteBit) != 0;
45 const bool is_static = (type & FindFieldFlags::StaticBit) != 0;
46 if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
47 // Incompatible class change.
48 return nullptr;
49 }
50 ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
51 if (is_static) {
52 // Check class is initialized else fail so that we can contend to initialize the class with
53 // other threads that may be racing to do this.
54 if (UNLIKELY(!fields_class->IsVisiblyInitialized())) {
55 return nullptr;
56 }
57 }
58 ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
59 if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
60 !referring_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) ||
61 (is_set && !resolved_field->CanBeChangedBy(referrer)))) {
62 // Illegal access.
63 return nullptr;
64 }
65 if (should_resolve_type && resolved_field->LookupResolvedType() == nullptr) {
66 return nullptr;
67 }
68 return resolved_field;
69 }
70
71 // Helper function to do a null check after trying to resolve the field. Not for statics since obj
72 // does not exist there. There is a suspend check, object is a double pointer to update the value
73 // in the caller in case it moves.
74 template<FindFieldType type>
FindInstanceField(uint32_t field_idx,ArtMethod * referrer,Thread * self,mirror::Object ** obj,bool should_resolve_type=false)75 ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
76 ArtMethod* referrer,
77 Thread* self,
78 mirror::Object** obj,
79 bool should_resolve_type = false)
80 REQUIRES(!Roles::uninterruptible_)
81 REQUIRES_SHARED(Locks::mutator_lock_) {
82 StackHandleScope<1> hs(self);
83 HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
84 ArtField* field = FindFieldFromCode<type>(field_idx, referrer, self, should_resolve_type);
85 if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
86 ThrowNullPointerExceptionForFieldAccess(field, referrer, (type & FindFieldFlags::ReadBit) != 0);
87 return nullptr;
88 }
89 return field;
90 }
91
GetReferrer(Thread * self)92 static ArtMethod* GetReferrer(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
93 if (kIsDebugBuild) {
94 // stub_test doesn't call this code with a proper frame, so get the outer, and if
95 // it does not have compiled code return it.
96 ArtMethod* outer = GetCalleeSaveOuterMethod(self, CalleeSaveType::kSaveRefsOnly);
97 if (outer->GetEntryPointFromQuickCompiledCode() == nullptr) {
98 return outer;
99 }
100 }
101 return GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveRefsOnly).caller;
102 }
103
104 // Macro used to define this set of functions:
105 //
106 // art{Get,Set}<Kind>{Static,Instance}FromCode
107 // art{Get,Set}<Kind>{Static,Instance}FromCompiledCode
108 //
109 #define ART_GET_FIELD_FROM_CODE(Kind, RetType, SetType, PrimitiveOrObject, \
110 IsObject, Ptr) \
111 extern "C" RetType artGet ## Kind ## StaticFromCode(uint32_t field_idx, \
112 ArtMethod* referrer, \
113 Thread* self) \
114 REQUIRES_SHARED(Locks::mutator_lock_) { \
115 ScopedQuickEntrypointChecks sqec(self); \
116 ArtField* field = FindFieldFast( \
117 field_idx, referrer, Static ## PrimitiveOrObject ## Read); \
118 if (LIKELY(field != nullptr)) { \
119 return field->Get ## Kind (field->GetDeclaringClass())Ptr; /* NOLINT */ \
120 } \
121 field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read>( \
122 field_idx, referrer, self); \
123 if (LIKELY(field != nullptr)) { \
124 return field->Get ## Kind (field->GetDeclaringClass())Ptr; /* NOLINT */ \
125 } \
126 /* Will throw exception by checking with Thread::Current. */ \
127 return 0; \
128 } \
129 \
130 extern "C" RetType artGet ## Kind ## InstanceFromCode(uint32_t field_idx, \
131 mirror::Object* obj, \
132 ArtMethod* referrer, \
133 Thread* self) \
134 REQUIRES_SHARED(Locks::mutator_lock_) { \
135 ScopedQuickEntrypointChecks sqec(self); \
136 ArtField* field = FindFieldFast( \
137 field_idx, referrer, Instance ## PrimitiveOrObject ## Read); \
138 if (LIKELY(field != nullptr) && obj != nullptr) { \
139 return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
140 } \
141 field = FindInstanceField<Instance ## PrimitiveOrObject ## Read>( \
142 field_idx, referrer, self, &obj); \
143 if (LIKELY(field != nullptr)) { \
144 return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
145 } \
146 /* Will throw exception by checking with Thread::Current. */ \
147 return 0; \
148 } \
149 \
150 extern "C" int artSet ## Kind ## StaticFromCode(uint32_t field_idx, \
151 SetType new_value, \
152 ArtMethod* referrer, \
153 Thread* self) \
154 REQUIRES_SHARED(Locks::mutator_lock_) { \
155 ScopedQuickEntrypointChecks sqec(self); \
156 bool should_resolve_type = (IsObject) && new_value != 0; \
157 ArtField* field = FindFieldFast( \
158 field_idx, \
159 referrer, \
160 Static ## PrimitiveOrObject ## Write, \
161 should_resolve_type); \
162 if (UNLIKELY(field == nullptr)) { \
163 if (IsObject) { \
164 StackHandleScope<1> hs(self); \
165 HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper( \
166 reinterpret_cast<mirror::Object**>(&new_value))); \
167 field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write>( \
168 field_idx, \
169 referrer, \
170 self, \
171 should_resolve_type); \
172 } else { \
173 field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write>( \
174 field_idx, referrer, self); \
175 } \
176 if (UNLIKELY(field == nullptr)) { \
177 return -1; \
178 } \
179 } \
180 field->Set ## Kind <false>(field->GetDeclaringClass(), new_value); \
181 return 0; \
182 } \
183 \
184 extern "C" int artSet ## Kind ## InstanceFromCode(uint32_t field_idx, \
185 mirror::Object* obj, \
186 SetType new_value, \
187 ArtMethod* referrer, \
188 Thread* self) \
189 REQUIRES_SHARED(Locks::mutator_lock_) { \
190 ScopedQuickEntrypointChecks sqec(self); \
191 bool should_resolve_type = (IsObject) && new_value != 0; \
192 ArtField* field = FindFieldFast( \
193 field_idx, \
194 referrer, \
195 Instance ## PrimitiveOrObject ## Write, \
196 should_resolve_type); \
197 if (UNLIKELY(field == nullptr || obj == nullptr)) { \
198 if (IsObject) { \
199 StackHandleScope<1> hs(self); \
200 HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper( \
201 reinterpret_cast<mirror::Object**>(&new_value))); \
202 field = FindInstanceField<Instance ## PrimitiveOrObject ## Write>( \
203 field_idx, \
204 referrer, \
205 self, \
206 &obj, \
207 should_resolve_type); \
208 } else { \
209 field = FindInstanceField<Instance ## PrimitiveOrObject ## Write>( \
210 field_idx, referrer, self, &obj); \
211 } \
212 if (UNLIKELY(field == nullptr)) { \
213 return -1; \
214 } \
215 } \
216 field->Set ## Kind<false>(obj, new_value); \
217 return 0; \
218 } \
219 \
220 extern "C" RetType artGet ## Kind ## StaticFromCompiledCode( \
221 uint32_t field_idx, \
222 Thread* self) \
223 REQUIRES_SHARED(Locks::mutator_lock_) { \
224 return artGet ## Kind ## StaticFromCode( \
225 field_idx, GetReferrer(self), self); \
226 } \
227 \
228 extern "C" RetType artGet ## Kind ## InstanceFromCompiledCode( \
229 uint32_t field_idx, \
230 mirror::Object* obj, \
231 Thread* self) \
232 REQUIRES_SHARED(Locks::mutator_lock_) { \
233 return artGet ## Kind ## InstanceFromCode( \
234 field_idx, obj, GetReferrer(self), self); \
235 } \
236 \
237 extern "C" int artSet ## Kind ## StaticFromCompiledCode( \
238 uint32_t field_idx, \
239 SetType new_value, \
240 Thread* self) \
241 REQUIRES_SHARED(Locks::mutator_lock_) { \
242 return artSet ## Kind ## StaticFromCode( \
243 field_idx, new_value, GetReferrer(self), self); \
244 } \
245 \
246 extern "C" int artSet ## Kind ## InstanceFromCompiledCode( \
247 uint32_t field_idx, \
248 mirror::Object* obj, \
249 SetType new_value, \
250 Thread* self) \
251 REQUIRES_SHARED(Locks::mutator_lock_) { \
252 return artSet ## Kind ## InstanceFromCode( \
253 field_idx, obj, new_value, GetReferrer(self), self); \
254 }
255
256 // Define these functions:
257 //
258 // artGetByteStaticFromCode
259 // artGetByteInstanceFromCode
260 // artSetByteStaticFromCode
261 // artSetByteInstanceFromCode
262 // artGetByteStaticFromCompiledCode
263 // artGetByteInstanceFromCompiledCode
264 // artSetByteStaticFromCompiledCode
265 // artSetByteInstanceFromCompiledCode
266 //
267 ART_GET_FIELD_FROM_CODE(Byte, ssize_t, uint32_t, Primitive, false, )
268
269 // Define these functions:
270 //
271 // artGetBooleanStaticFromCode
272 // artGetBooleanInstanceFromCode
273 // artSetBooleanStaticFromCode
274 // artSetBooleanInstanceFromCode
275 // artGetBooleanStaticFromCompiledCode
276 // artGetBooleanInstanceFromCompiledCode
277 // artSetBooleanStaticFromCompiledCode
278 // artSetBooleanInstanceFromCompiledCode
279 //
280 ART_GET_FIELD_FROM_CODE(Boolean, size_t, uint32_t, Primitive, false, )
281
282 // Define these functions:
283 //
284 // artGetShortStaticFromCode
285 // artGetShortInstanceFromCode
286 // artSetShortStaticFromCode
287 // artSetShortInstanceFromCode
288 // artGetShortStaticFromCompiledCode
289 // artGetShortInstanceFromCompiledCode
290 // artSetShortStaticFromCompiledCode
291 // artSetShortInstanceFromCompiledCode
292 //
293 ART_GET_FIELD_FROM_CODE(Short, ssize_t, uint16_t, Primitive, false, )
294
295 // Define these functions:
296 //
297 // artGetCharStaticFromCode
298 // artGetCharInstanceFromCode
299 // artSetCharStaticFromCode
300 // artSetCharInstanceFromCode
301 // artGetCharStaticFromCompiledCode
302 // artGetCharInstanceFromCompiledCode
303 // artSetCharStaticFromCompiledCode
304 // artSetCharInstanceFromCompiledCode
305 //
306 ART_GET_FIELD_FROM_CODE(Char, size_t, uint16_t, Primitive, false, )
307
308 // Define these functions:
309 //
310 // artGet32StaticFromCode
311 // artGet32InstanceFromCode
312 // artSet32StaticFromCode
313 // artSet32InstanceFromCode
314 // artGet32StaticFromCompiledCode
315 // artGet32InstanceFromCompiledCode
316 // artSet32StaticFromCompiledCode
317 // artSet32InstanceFromCompiledCode
318 //
319 #if defined(__riscv)
320 // On riscv64 we need to sign-extend `int` values to the full 64-bit register.
321 // `ArtField::Get32()` returns a `uint32_t`, so let the getters return the same,
322 // allowing the sign-extension specified by the RISC-V native calling convention:
323 // "[I]nteger scalars narrower than XLEN bits are widened according to the
324 // sign of their type up to 32 bits, then sign-extended to XLEN bits."
325 // This is OK for `float` as the compiled code shall transfer it using FMV.W.X,
326 // ignoring the upper 32 bits.
327 ART_GET_FIELD_FROM_CODE(32, uint32_t, uint32_t, Primitive, false, )
328 #else
329 ART_GET_FIELD_FROM_CODE(32, size_t, uint32_t, Primitive, false, )
330 #endif
331
332 // Define these functions:
333 //
334 // artGet64StaticFromCode
335 // artGet64InstanceFromCode
336 // artSet64StaticFromCode
337 // artSet64InstanceFromCode
338 // artGet64StaticFromCompiledCode
339 // artGet64InstanceFromCompiledCode
340 // artSet64StaticFromCompiledCode
341 // artSet64InstanceFromCompiledCode
342 //
343 ART_GET_FIELD_FROM_CODE(64, uint64_t, uint64_t, Primitive, false, )
344
345 // Define these functions:
346 //
347 // artGetObjStaticFromCode
348 // artGetObjInstanceFromCode
349 // artSetObjStaticFromCode
350 // artSetObjInstanceFromCode
351 // artGetObjStaticFromCompiledCode
352 // artGetObjInstanceFromCompiledCode
353 // artSetObjStaticFromCompiledCode
354 // artSetObjInstanceFromCompiledCode
355 //
356 ART_GET_FIELD_FROM_CODE(Obj, mirror::Object*, mirror::Object*, Object, true, .Ptr())
357
358 #undef ART_GET_FIELD_FROM_CODE
359
360
361 // To cut on the number of entrypoints, we have shared entries for
362 // byte/boolean and char/short for setting an instance or static field. We just
363 // forward those to the unsigned variant.
artSet8StaticFromCompiledCode(uint32_t field_idx,uint32_t new_value,Thread * self)364 extern "C" int artSet8StaticFromCompiledCode(uint32_t field_idx,
365 uint32_t new_value,
366 Thread* self)
367 REQUIRES_SHARED(Locks::mutator_lock_) {
368 return artSetBooleanStaticFromCode(field_idx, new_value, GetReferrer(self), self);
369 }
370
artSet16StaticFromCompiledCode(uint32_t field_idx,uint16_t new_value,Thread * self)371 extern "C" int artSet16StaticFromCompiledCode(uint32_t field_idx,
372 uint16_t new_value,
373 Thread* self)
374 REQUIRES_SHARED(Locks::mutator_lock_) {
375 return artSetCharStaticFromCode(field_idx, new_value, GetReferrer(self), self);
376 }
377
artSet8InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,Thread * self)378 extern "C" int artSet8InstanceFromCompiledCode(uint32_t field_idx,
379 mirror::Object* obj,
380 uint8_t new_value,
381 Thread* self)
382 REQUIRES_SHARED(Locks::mutator_lock_) {
383 return artSetBooleanInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
384 }
385
artSet16InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,Thread * self)386 extern "C" int artSet16InstanceFromCompiledCode(uint32_t field_idx,
387 mirror::Object* obj,
388 uint16_t new_value,
389 Thread* self)
390 REQUIRES_SHARED(Locks::mutator_lock_) {
391 return artSetCharInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
392 }
393
artSet8StaticFromCode(uint32_t field_idx,uint32_t new_value,ArtMethod * referrer,Thread * self)394 extern "C" int artSet8StaticFromCode(uint32_t field_idx,
395 uint32_t new_value,
396 ArtMethod* referrer,
397 Thread* self)
398 REQUIRES_SHARED(Locks::mutator_lock_) {
399 return artSetBooleanStaticFromCode(field_idx, new_value, referrer, self);
400 }
401
artSet16StaticFromCode(uint32_t field_idx,uint16_t new_value,ArtMethod * referrer,Thread * self)402 extern "C" int artSet16StaticFromCode(uint32_t field_idx,
403 uint16_t new_value,
404 ArtMethod* referrer,
405 Thread* self)
406 REQUIRES_SHARED(Locks::mutator_lock_) {
407 return artSetCharStaticFromCode(field_idx, new_value, referrer, self);
408 }
409
artSet8InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,ArtMethod * referrer,Thread * self)410 extern "C" int artSet8InstanceFromCode(uint32_t field_idx,
411 mirror::Object* obj,
412 uint8_t new_value,
413 ArtMethod* referrer,
414 Thread* self)
415 REQUIRES_SHARED(Locks::mutator_lock_) {
416 return artSetBooleanInstanceFromCode(field_idx, obj, new_value, referrer, self);
417 }
418
artSet16InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,ArtMethod * referrer,Thread * self)419 extern "C" int artSet16InstanceFromCode(uint32_t field_idx,
420 mirror::Object* obj,
421 uint16_t new_value,
422 ArtMethod* referrer,
423 Thread* self)
424 REQUIRES_SHARED(Locks::mutator_lock_) {
425 return artSetCharInstanceFromCode(field_idx, obj, new_value, referrer, self);
426 }
427
artReadBarrierMark(mirror::Object * obj)428 extern "C" mirror::Object* artReadBarrierMark(mirror::Object* obj) {
429 DCHECK(gUseReadBarrier);
430 return ReadBarrier::Mark(obj);
431 }
432
artReadBarrierSlow(mirror::Object * ref,mirror::Object * obj,uint32_t offset)433 extern "C" mirror::Object* artReadBarrierSlow([[maybe_unused]] mirror::Object* ref,
434 mirror::Object* obj,
435 uint32_t offset) {
436 // Used only in connection with non-volatile loads.
437 DCHECK(gUseReadBarrier);
438 uint8_t* raw_addr = reinterpret_cast<uint8_t*>(obj) + offset;
439 mirror::HeapReference<mirror::Object>* ref_addr =
440 reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_addr);
441 mirror::Object* result =
442 ReadBarrier::Barrier<mirror::Object, /* kIsVolatile= */ false, kWithReadBarrier>(
443 obj,
444 MemberOffset(offset),
445 ref_addr);
446 return result;
447 }
448
artReadBarrierForRootSlow(GcRoot<mirror::Object> * root)449 extern "C" mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root) {
450 DCHECK(gUseReadBarrier);
451 return root->Read();
452 }
453
454 } // namespace art
455