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