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