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 {
30 
31 // Helper function to do a null check after trying to resolve the field. Not for statics since obj
32 // does not exist there. There is a suspend check, object is a double pointer to update the value
33 // in the caller in case it moves.
34 template<FindFieldType type, bool kAccessCheck>
FindInstanceField(uint32_t field_idx,ArtMethod * referrer,Thread * self,size_t size,mirror::Object ** obj)35 ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
36                                                         ArtMethod* referrer,
37                                                         Thread* self,
38                                                         size_t size,
39                                                         mirror::Object** obj)
40     REQUIRES(!Roles::uninterruptible_)
41     REQUIRES_SHARED(Locks::mutator_lock_) {
42   StackHandleScope<1> hs(self);
43   HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
44   ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
45   if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
46     ThrowNullPointerExceptionForFieldAccess(field, (type & FindFieldFlags::ReadBit) != 0);
47     return nullptr;
48   }
49   return field;
50 }
51 
GetReferrer(Thread * self)52 static ArtMethod* GetReferrer(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
53   if (kIsDebugBuild) {
54     // stub_test doesn't call this code with a proper frame, so get the outer, and if
55     // it does not have compiled code return it.
56     ArtMethod* outer = GetCalleeSaveOuterMethod(self, CalleeSaveType::kSaveRefsOnly);
57     if (outer->GetEntryPointFromQuickCompiledCode() == nullptr) {
58       return outer;
59     }
60   }
61   return GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveRefsOnly).caller;
62 }
63 
64 // Macro used to define this set of functions:
65 //
66 //   art{Get,Set}<Kind>{Static,Instance}FromCode
67 //   art{Get,Set}<Kind>{Static,Instance}FromCompiledCode
68 //
69 #define ART_GET_FIELD_FROM_CODE(Kind, PrimitiveType, RetType, SetType,         \
70                                 PrimitiveOrObject, IsObject, Ptr)              \
71   extern "C" RetType artGet ## Kind ## StaticFromCode(uint32_t field_idx,      \
72                                                       ArtMethod* referrer,     \
73                                                       Thread* self)            \
74       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
75     ScopedQuickEntrypointChecks sqec(self);                                    \
76     ArtField* field = FindFieldFast(                                           \
77         field_idx, referrer, Static ## PrimitiveOrObject ## Read,              \
78         sizeof(PrimitiveType));                                                \
79     if (LIKELY(field != nullptr)) {                                            \
80       return field->Get ## Kind (field->GetDeclaringClass())Ptr;  /* NOLINT */ \
81     }                                                                          \
82     field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read, true>(      \
83         field_idx, referrer, self, sizeof(PrimitiveType));                     \
84     if (LIKELY(field != nullptr)) {                                            \
85       return field->Get ## Kind (field->GetDeclaringClass())Ptr;  /* NOLINT */ \
86     }                                                                          \
87     /* Will throw exception by checking with Thread::Current. */               \
88     return 0;                                                                  \
89   }                                                                            \
90                                                                                \
91   extern "C" RetType artGet ## Kind ## InstanceFromCode(uint32_t field_idx,    \
92                                                         mirror::Object* obj,   \
93                                                         ArtMethod* referrer,   \
94                                                         Thread* self)          \
95       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
96     ScopedQuickEntrypointChecks sqec(self);                                    \
97     ArtField* field = FindFieldFast(                                           \
98         field_idx, referrer, Instance ## PrimitiveOrObject ## Read,            \
99         sizeof(PrimitiveType));                                                \
100     if (LIKELY(field != nullptr) && obj != nullptr) {                          \
101       return field->Get ## Kind (obj)Ptr;  /* NOLINT */                        \
102     }                                                                          \
103     field = FindInstanceField<Instance ## PrimitiveOrObject ## Read, true>(    \
104         field_idx, referrer, self, sizeof(PrimitiveType), &obj);               \
105     if (LIKELY(field != nullptr)) {                                            \
106       return field->Get ## Kind (obj)Ptr;  /* NOLINT */                        \
107     }                                                                          \
108     /* Will throw exception by checking with Thread::Current. */               \
109     return 0;                                                                  \
110   }                                                                            \
111                                                                                \
112   extern "C" int artSet ## Kind ## StaticFromCode(uint32_t field_idx,          \
113                                                   SetType new_value,           \
114                                                   ArtMethod* referrer,         \
115                                                   Thread* self)                \
116       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
117     ScopedQuickEntrypointChecks sqec(self);                                    \
118     ArtField* field = FindFieldFast(                                           \
119         field_idx, referrer, Static ## PrimitiveOrObject ## Write,             \
120         sizeof(PrimitiveType));                                                \
121     if (UNLIKELY(field == nullptr)) {                                          \
122       if (IsObject) {                                                          \
123         StackHandleScope<1> hs(self);                                          \
124         HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(               \
125             reinterpret_cast<mirror::Object**>(&new_value)));                  \
126         field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>( \
127             field_idx, referrer, self, sizeof(PrimitiveType));                 \
128       } else {                                                                 \
129         field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>( \
130             field_idx, referrer, self, sizeof(PrimitiveType));                 \
131       }                                                                        \
132       if (UNLIKELY(field == nullptr)) {                                        \
133         return -1;                                                             \
134       }                                                                        \
135     }                                                                          \
136     if (!referrer->SkipAccessChecks() && IsObject && new_value != 0) {         \
137       StackArtFieldHandleScope<1> rhs(self);                                   \
138       ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(field));           \
139       if (field->ResolveType().IsNull()) {                                     \
140         self->AssertPendingException();                                        \
141         return -1;                                                             \
142       }                                                                        \
143       field = field_handle.Get();                                              \
144     }                                                                          \
145     field->Set ## Kind <false>(field->GetDeclaringClass(), new_value);         \
146     return 0;                                                                  \
147   }                                                                            \
148                                                                                \
149   extern "C" int artSet ## Kind ## InstanceFromCode(uint32_t field_idx,        \
150                                                     mirror::Object* obj,       \
151                                                     SetType new_value,         \
152                                                     ArtMethod* referrer,       \
153                                                     Thread* self)              \
154     REQUIRES_SHARED(Locks::mutator_lock_) {                                    \
155     ScopedQuickEntrypointChecks sqec(self);                                    \
156     ArtField* field = FindFieldFast(                                           \
157         field_idx, referrer, Instance ## PrimitiveOrObject ## Write,           \
158         sizeof(PrimitiveType));                                                \
159     if (UNLIKELY(field == nullptr || obj == nullptr)) {                        \
160       if (IsObject) {                                                          \
161         StackHandleScope<1> hs(self);                                          \
162         HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(               \
163             reinterpret_cast<mirror::Object**>(&new_value)));                  \
164         field =                                                                \
165             FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>(   \
166                 field_idx,                                                     \
167                 referrer,                                                      \
168                 self,                                                          \
169                 sizeof(PrimitiveType),                                         \
170                 &obj);                                                         \
171       } else {                                                                 \
172         field =                                                                \
173             FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>(   \
174                 field_idx,                                                     \
175                 referrer,                                                      \
176                 self,                                                          \
177                 sizeof(PrimitiveType),                                         \
178                 &obj);                                                         \
179       }                                                                        \
180       if (UNLIKELY(field == nullptr)) {                                        \
181         return -1;                                                             \
182       }                                                                        \
183     }                                                                          \
184     if (!referrer->SkipAccessChecks() && IsObject && new_value != 0) {         \
185       StackArtFieldHandleScope<1> rhs(self);                                   \
186       ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(field));           \
187       if (field->ResolveType().IsNull()) {                                     \
188         self->AssertPendingException();                                        \
189         return -1;                                                             \
190       }                                                                        \
191       field = field_handle.Get();                                              \
192     }                                                                          \
193     field->Set ## Kind<false>(obj, new_value);                                 \
194     return 0;                                                                  \
195   }                                                                            \
196                                                                                \
197   extern "C" RetType artGet ## Kind ## StaticFromCompiledCode(                 \
198       uint32_t field_idx,                                                      \
199       Thread* self)                                                            \
200       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
201     return artGet ## Kind ## StaticFromCode(                                   \
202         field_idx, GetReferrer(self), self);                                   \
203   }                                                                            \
204                                                                                \
205   extern "C" RetType artGet ## Kind ## InstanceFromCompiledCode(               \
206       uint32_t field_idx,                                                      \
207       mirror::Object* obj,                                                     \
208       Thread* self)                                                            \
209       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
210     return artGet ## Kind ## InstanceFromCode(                                 \
211         field_idx, obj, GetReferrer(self), self);                              \
212   }                                                                            \
213                                                                                \
214   extern "C" int artSet ## Kind ## StaticFromCompiledCode(                     \
215       uint32_t field_idx,                                                      \
216       SetType new_value,                                                       \
217       Thread* self)                                                            \
218       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
219     return artSet ## Kind ## StaticFromCode(                                   \
220         field_idx, new_value, GetReferrer(self), self);                        \
221   }                                                                            \
222                                                                                \
223   extern "C" int artSet ## Kind ## InstanceFromCompiledCode(                   \
224       uint32_t field_idx,                                                      \
225       mirror::Object* obj,                                                     \
226       SetType new_value,                                                       \
227       Thread* self)                                                            \
228       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
229     return artSet ## Kind ## InstanceFromCode(                                 \
230         field_idx, obj, new_value, GetReferrer(self), self);                   \
231   }
232 
233 // Define these functions:
234 //
235 //   artGetByteStaticFromCode
236 //   artGetByteInstanceFromCode
237 //   artSetByteStaticFromCode
238 //   artSetByteInstanceFromCode
239 //   artGetByteStaticFromCompiledCode
240 //   artGetByteInstanceFromCompiledCode
241 //   artSetByteStaticFromCompiledCode
242 //   artSetByteInstanceFromCompiledCode
243 //
244 ART_GET_FIELD_FROM_CODE(Byte, int8_t, ssize_t, uint32_t, Primitive, false, )
245 
246 // Define these functions:
247 //
248 //   artGetBooleanStaticFromCode
249 //   artGetBooleanInstanceFromCode
250 //   artSetBooleanStaticFromCode
251 //   artSetBooleanInstanceFromCode
252 //   artGetBooleanStaticFromCompiledCode
253 //   artGetBooleanInstanceFromCompiledCode
254 //   artSetBooleanStaticFromCompiledCode
255 //   artSetBooleanInstanceFromCompiledCode
256 //
257 ART_GET_FIELD_FROM_CODE(Boolean, int8_t, size_t, uint32_t, Primitive, false, )
258 
259 // Define these functions:
260 //
261 //   artGetShortStaticFromCode
262 //   artGetShortInstanceFromCode
263 //   artSetShortStaticFromCode
264 //   artSetShortInstanceFromCode
265 //   artGetShortStaticFromCompiledCode
266 //   artGetShortInstanceFromCompiledCode
267 //   artSetShortStaticFromCompiledCode
268 //   artSetShortInstanceFromCompiledCode
269 //
270 ART_GET_FIELD_FROM_CODE(Short, int16_t, ssize_t, uint16_t, Primitive, false, )
271 
272 // Define these functions:
273 //
274 //   artGetCharStaticFromCode
275 //   artGetCharInstanceFromCode
276 //   artSetCharStaticFromCode
277 //   artSetCharInstanceFromCode
278 //   artGetCharStaticFromCompiledCode
279 //   artGetCharInstanceFromCompiledCode
280 //   artSetCharStaticFromCompiledCode
281 //   artSetCharInstanceFromCompiledCode
282 //
283 ART_GET_FIELD_FROM_CODE(Char, int16_t, size_t, uint16_t, Primitive, false, )
284 
285 // Define these functions:
286 //
287 //   artGet32StaticFromCode
288 //   artGet32InstanceFromCode
289 //   artSet32StaticFromCode
290 //   artSet32InstanceFromCode
291 //   artGet32StaticFromCompiledCode
292 //   artGet32InstanceFromCompiledCode
293 //   artSet32StaticFromCompiledCode
294 //   artSet32InstanceFromCompiledCode
295 //
296 ART_GET_FIELD_FROM_CODE(32, int32_t, size_t, uint32_t, Primitive, false, )
297 
298 // Define these functions:
299 //
300 //   artGet64StaticFromCode
301 //   artGet64InstanceFromCode
302 //   artSet64StaticFromCode
303 //   artSet64InstanceFromCode
304 //   artGet64StaticFromCompiledCode
305 //   artGet64InstanceFromCompiledCode
306 //   artSet64StaticFromCompiledCode
307 //   artSet64InstanceFromCompiledCode
308 //
309 ART_GET_FIELD_FROM_CODE(64, int64_t, uint64_t, uint64_t, Primitive, false, )
310 
311 // Define these functions:
312 //
313 //   artGetObjStaticFromCode
314 //   artGetObjInstanceFromCode
315 //   artSetObjStaticFromCode
316 //   artSetObjInstanceFromCode
317 //   artGetObjStaticFromCompiledCode
318 //   artGetObjInstanceFromCompiledCode
319 //   artSetObjStaticFromCompiledCode
320 //   artSetObjInstanceFromCompiledCode
321 //
322 ART_GET_FIELD_FROM_CODE(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*,
323                         mirror::Object*, Object, true, .Ptr())
324 
325 #undef ART_GET_FIELD_FROM_CODE
326 
327 
328 // To cut on the number of entrypoints, we have shared entries for
329 // byte/boolean and char/short for setting an instance or static field. We just
330 // forward those to the unsigned variant.
artSet8StaticFromCompiledCode(uint32_t field_idx,uint32_t new_value,Thread * self)331 extern "C" int artSet8StaticFromCompiledCode(uint32_t field_idx,
332                                              uint32_t new_value,
333                                              Thread* self)
334     REQUIRES_SHARED(Locks::mutator_lock_) {
335   return artSetBooleanStaticFromCode(field_idx, new_value, GetReferrer(self), self);
336 }
337 
artSet16StaticFromCompiledCode(uint32_t field_idx,uint16_t new_value,Thread * self)338 extern "C" int artSet16StaticFromCompiledCode(uint32_t field_idx,
339                                               uint16_t new_value,
340                                               Thread* self)
341     REQUIRES_SHARED(Locks::mutator_lock_) {
342   return artSetCharStaticFromCode(field_idx, new_value, GetReferrer(self), self);
343 }
344 
artSet8InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,Thread * self)345 extern "C" int artSet8InstanceFromCompiledCode(uint32_t field_idx,
346                                                mirror::Object* obj,
347                                                uint8_t new_value,
348                                                Thread* self)
349     REQUIRES_SHARED(Locks::mutator_lock_) {
350   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
351 }
352 
artSet16InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,Thread * self)353 extern "C" int artSet16InstanceFromCompiledCode(uint32_t field_idx,
354                                                 mirror::Object* obj,
355                                                 uint16_t new_value,
356                                                 Thread* self)
357     REQUIRES_SHARED(Locks::mutator_lock_) {
358   return artSetCharInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
359 }
360 
artSet8StaticFromCode(uint32_t field_idx,uint32_t new_value,ArtMethod * referrer,Thread * self)361 extern "C" int artSet8StaticFromCode(uint32_t field_idx,
362                                      uint32_t new_value,
363                                      ArtMethod* referrer,
364                                      Thread* self)
365     REQUIRES_SHARED(Locks::mutator_lock_) {
366   return artSetBooleanStaticFromCode(field_idx, new_value, referrer, self);
367 }
368 
artSet16StaticFromCode(uint32_t field_idx,uint16_t new_value,ArtMethod * referrer,Thread * self)369 extern "C" int artSet16StaticFromCode(uint32_t field_idx,
370                                       uint16_t new_value,
371                                       ArtMethod* referrer,
372                                       Thread* self)
373     REQUIRES_SHARED(Locks::mutator_lock_) {
374   return artSetCharStaticFromCode(field_idx, new_value, referrer, self);
375 }
376 
artSet8InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,ArtMethod * referrer,Thread * self)377 extern "C" int artSet8InstanceFromCode(uint32_t field_idx,
378                                        mirror::Object* obj,
379                                        uint8_t new_value,
380                                        ArtMethod* referrer,
381                                        Thread* self)
382     REQUIRES_SHARED(Locks::mutator_lock_) {
383   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, referrer, self);
384 }
385 
artSet16InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,ArtMethod * referrer,Thread * self)386 extern "C" int artSet16InstanceFromCode(uint32_t field_idx,
387                                         mirror::Object* obj,
388                                         uint16_t new_value,
389                                         ArtMethod* referrer,
390                                         Thread* self)
391     REQUIRES_SHARED(Locks::mutator_lock_) {
392   return artSetCharInstanceFromCode(field_idx, obj, new_value, referrer, self);
393 }
394 
artReadBarrierMark(mirror::Object * obj)395 extern "C" mirror::Object* artReadBarrierMark(mirror::Object* obj) {
396   DCHECK(kEmitCompilerReadBarrier);
397   return ReadBarrier::Mark(obj);
398 }
399 
artReadBarrierSlow(mirror::Object * ref ATTRIBUTE_UNUSED,mirror::Object * obj,uint32_t offset)400 extern "C" mirror::Object* artReadBarrierSlow(mirror::Object* ref ATTRIBUTE_UNUSED,
401                                               mirror::Object* obj,
402                                               uint32_t offset) {
403   // Used only in connection with non-volatile loads.
404   DCHECK(kEmitCompilerReadBarrier);
405   uint8_t* raw_addr = reinterpret_cast<uint8_t*>(obj) + offset;
406   mirror::HeapReference<mirror::Object>* ref_addr =
407      reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_addr);
408   constexpr ReadBarrierOption kReadBarrierOption =
409       kUseReadBarrier ? kWithReadBarrier : kWithoutReadBarrier;
410   mirror::Object* result =
411       ReadBarrier::Barrier<mirror::Object, /* kIsVolatile= */ false, kReadBarrierOption>(
412         obj,
413         MemberOffset(offset),
414         ref_addr);
415   return result;
416 }
417 
artReadBarrierForRootSlow(GcRoot<mirror::Object> * root)418 extern "C" mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root) {
419   DCHECK(kEmitCompilerReadBarrier);
420   return root->Read();
421 }
422 
423 }  // namespace art
424