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 "callee_save_frame.h"
22 #include "dex_file-inl.h"
23 #include "entrypoints/entrypoint_utils-inl.h"
24 #include "gc_root-inl.h"
25 #include "mirror/class-inl.h"
26 #include "mirror/object_reference.h"
27 
28 namespace art {
29 
FindFieldTypeIsRead(FindFieldType type)30 inline constexpr bool FindFieldTypeIsRead(FindFieldType type) {
31   return type == InstanceObjectRead ||
32          type == InstancePrimitiveRead ||
33          type == StaticObjectRead ||
34          type == StaticPrimitiveRead;
35 }
36 
37 // Helper function to do a null check after trying to resolve the field. Not for statics since obj
38 // does not exist there. There is a suspend check, object is a double pointer to update the value
39 // in the caller in case it moves.
40 template<FindFieldType type, bool kAccessCheck>
FindInstanceField(uint32_t field_idx,ArtMethod * referrer,Thread * self,size_t size,mirror::Object ** obj)41 ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
42                                                         ArtMethod* referrer,
43                                                         Thread* self,
44                                                         size_t size,
45                                                         mirror::Object** obj)
46     REQUIRES(!Roles::uninterruptible_)
47     REQUIRES_SHARED(Locks::mutator_lock_) {
48   StackHandleScope<1> hs(self);
49   HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
50   ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
51   if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
52     ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/FindFieldTypeIsRead(type));
53     return nullptr;
54   }
55   return field;
56 }
57 
GetReferrer(Thread * self)58 static ArtMethod* GetReferrer(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
59   if (kIsDebugBuild) {
60     // stub_test doesn't call this code with a proper frame, so get the outer, and if
61     // it does not have compiled code return it.
62     ArtMethod* outer = GetCalleeSaveOuterMethod(self, Runtime::kSaveRefsOnly);
63     if (outer->GetEntryPointFromQuickCompiledCode() == nullptr) {
64       return outer;
65     }
66   }
67   return GetCalleeSaveMethodCallerAndOuterMethod(self, Runtime::kSaveRefsOnly).caller;
68 }
69 
70 #define ART_GET_FIELD_FROM_CODE(Kind, PrimitiveType, RetType, SetType,         \
71                                 PrimitiveOrObject, IsObject, Ptr)              \
72   extern "C" RetType artGet ## Kind ## StaticFromCode(uint32_t field_idx,      \
73                                                       ArtMethod* referrer,     \
74                                                       Thread* self)            \
75       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
76     ScopedQuickEntrypointChecks sqec(self);                                    \
77     ArtField* field = FindFieldFast(                                           \
78         field_idx, referrer, Static ## PrimitiveOrObject ## Read,              \
79         sizeof(PrimitiveType));                                                \
80     if (LIKELY(field != nullptr)) {                                            \
81       return field->Get ## Kind (field->GetDeclaringClass())Ptr;               \
82     }                                                                          \
83     field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read, true>(      \
84         field_idx, referrer, self, sizeof(PrimitiveType));                     \
85     if (LIKELY(field != nullptr)) {                                            \
86       return field->Get ## Kind (field->GetDeclaringClass())Ptr;               \
87     }                                                                          \
88     /* Will throw exception by checking with Thread::Current. */               \
89     return 0;                                                                  \
90   }                                                                            \
91                                                                                \
92   extern "C" RetType artGet ## Kind ## InstanceFromCode(uint32_t field_idx,    \
93                                                         mirror::Object* obj,   \
94                                                         ArtMethod* referrer,   \
95                                                         Thread* self)          \
96       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
97     ScopedQuickEntrypointChecks sqec(self);                                    \
98     ArtField* field = FindFieldFast(                                           \
99         field_idx, referrer, Instance ## PrimitiveOrObject ## Read,            \
100         sizeof(PrimitiveType));                                                \
101     if (LIKELY(field != nullptr) && obj != nullptr) {                          \
102       return field->Get ## Kind (obj)Ptr;                                      \
103     }                                                                          \
104     field = FindInstanceField<Instance ## PrimitiveOrObject ## Read, true>(    \
105         field_idx, referrer, self, sizeof(PrimitiveType), &obj);               \
106     if (LIKELY(field != nullptr)) {                                            \
107       return field->Get ## Kind (obj)Ptr;                                      \
108     }                                                                          \
109     /* Will throw exception by checking with Thread::Current. */               \
110     return 0;                                                                  \
111   }                                                                            \
112                                                                                \
113   extern "C" int artSet ## Kind ## StaticFromCode(uint32_t field_idx,          \
114                                                   SetType new_value,           \
115                                                   ArtMethod* referrer,         \
116                                                   Thread* self)                \
117       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
118     ScopedQuickEntrypointChecks sqec(self);                                    \
119     ArtField* field = FindFieldFast(                                           \
120         field_idx, referrer, Static ## PrimitiveOrObject ## Write,             \
121         sizeof(PrimitiveType));                                                \
122     if (LIKELY(field != nullptr)) {                                            \
123       field->Set ## Kind <false>(field->GetDeclaringClass(), new_value);       \
124       return 0;                                                                \
125     }                                                                          \
126     if (IsObject) {                                                            \
127       StackHandleScope<1> hs(self);                                            \
128       HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(                 \
129           reinterpret_cast<mirror::Object**>(&new_value)));                    \
130       field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>(   \
131           field_idx, referrer, self, sizeof(PrimitiveType));                   \
132     } else {                                                                   \
133       field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>(   \
134           field_idx, referrer, self, sizeof(PrimitiveType));                   \
135     }                                                                          \
136     if (LIKELY(field != nullptr)) {                                            \
137       field->Set ## Kind <false>(field->GetDeclaringClass(), new_value);       \
138       return 0;                                                                \
139     }                                                                          \
140     return -1;                                                                 \
141   }                                                                            \
142                                                                                \
143   extern "C" int artSet ## Kind ## InstanceFromCode(uint32_t field_idx,        \
144                                                     mirror::Object* obj,       \
145                                                     SetType new_value,         \
146                                                     ArtMethod* referrer,       \
147                                                     Thread* self)              \
148     REQUIRES_SHARED(Locks::mutator_lock_) {                                    \
149     ScopedQuickEntrypointChecks sqec(self);                                    \
150     ArtField* field = FindFieldFast(                                           \
151         field_idx, referrer, Instance ## PrimitiveOrObject ## Write,           \
152         sizeof(PrimitiveType));                                                \
153     if (LIKELY(field != nullptr && obj != nullptr)) {                          \
154       field->Set ## Kind <false>(obj, new_value);                              \
155       return 0;                                                                \
156     }                                                                          \
157     if (IsObject) {                                                            \
158       StackHandleScope<1> hs(self);                                            \
159       HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(                 \
160           reinterpret_cast<mirror::Object**>(&new_value)));                    \
161       field = FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
162           field_idx,                                                           \
163           referrer,                                                            \
164           self,                                                                \
165           sizeof(PrimitiveType),                                               \
166           &obj);                                                               \
167     } else {                                                                   \
168       field = FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
169           field_idx,                                                           \
170           referrer,                                                            \
171           self,                                                                \
172           sizeof(PrimitiveType),                                               \
173           &obj);                                                               \
174     }                                                                          \
175     if (LIKELY(field != nullptr)) {                                            \
176       field->Set ## Kind<false>(obj, new_value);                               \
177       return 0;                                                                \
178     }                                                                          \
179     return -1;                                                                 \
180   }                                                                            \
181                                                                                \
182   extern "C" RetType artGet ## Kind ## StaticFromCompiledCode(                 \
183       uint32_t field_idx,                                                      \
184       Thread* self)                                                            \
185       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
186     return artGet ## Kind ## StaticFromCode(                                   \
187         field_idx, GetReferrer(self), self);                                   \
188   }                                                                            \
189                                                                                \
190   extern "C" RetType artGet ## Kind ## InstanceFromCompiledCode(               \
191       uint32_t field_idx,                                                      \
192       mirror::Object* obj,                                                     \
193       Thread* self)                                                            \
194       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
195     return artGet ## Kind ## InstanceFromCode(                                 \
196         field_idx, obj, GetReferrer(self), self);                              \
197   }                                                                            \
198                                                                                \
199   extern "C" int artSet ## Kind ## StaticFromCompiledCode(                     \
200       uint32_t field_idx,                                                      \
201       SetType new_value,                                                       \
202       Thread* self)                                                            \
203       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
204     return artSet ## Kind ## StaticFromCode(                                   \
205         field_idx, new_value, GetReferrer(self), self);                        \
206   }                                                                            \
207                                                                                \
208   extern "C" int artSet ## Kind ## InstanceFromCompiledCode(                   \
209       uint32_t field_idx,                                                      \
210       mirror::Object* obj,                                                     \
211       SetType new_value,                                                       \
212       Thread* self)                                                            \
213       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
214     return artSet ## Kind ## InstanceFromCode(                                 \
215         field_idx, obj, new_value, GetReferrer(self), self);                   \
216   }
217 
218 ART_GET_FIELD_FROM_CODE(Byte, int8_t, ssize_t, uint32_t, Primitive, false, )
219 ART_GET_FIELD_FROM_CODE(Boolean, int8_t, size_t, uint32_t, Primitive, false, )
220 ART_GET_FIELD_FROM_CODE(Short, int16_t, ssize_t, uint16_t, Primitive, false, )
221 ART_GET_FIELD_FROM_CODE(Char, int16_t, size_t, uint16_t, Primitive, false, )
222 ART_GET_FIELD_FROM_CODE(32, int32_t, size_t, uint32_t, Primitive, false, )
223 ART_GET_FIELD_FROM_CODE(64, int64_t, uint64_t, uint64_t, Primitive, false, )
224 ART_GET_FIELD_FROM_CODE(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*,
225                         mirror::Object*, Object, true, .Ptr())
226 
227 
228 // To cut on the number of entrypoints, we have shared entries for
229 // byte/boolean and char/short for setting an instance or static field. We just
230 // forward those to the unsigned variant.
artSet8StaticFromCompiledCode(uint32_t field_idx,uint32_t new_value,Thread * self)231 extern "C" int artSet8StaticFromCompiledCode(uint32_t field_idx,
232                                              uint32_t new_value,
233                                              Thread* self)
234     REQUIRES_SHARED(Locks::mutator_lock_) {
235   return artSetBooleanStaticFromCode(field_idx, new_value, GetReferrer(self), self);
236 }
237 
artSet16StaticFromCompiledCode(uint32_t field_idx,uint16_t new_value,Thread * self)238 extern "C" int artSet16StaticFromCompiledCode(uint32_t field_idx,
239                                               uint16_t new_value,
240                                               Thread* self)
241     REQUIRES_SHARED(Locks::mutator_lock_) {
242   return artSetCharStaticFromCode(field_idx, new_value, GetReferrer(self), self);
243 }
244 
artSet8InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,Thread * self)245 extern "C" int artSet8InstanceFromCompiledCode(uint32_t field_idx,
246                                                mirror::Object* obj,
247                                                uint8_t new_value,
248                                                Thread* self)
249     REQUIRES_SHARED(Locks::mutator_lock_) {
250   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
251 }
252 
artSet16InstanceFromCompiledCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,Thread * self)253 extern "C" int artSet16InstanceFromCompiledCode(uint32_t field_idx,
254                                                 mirror::Object* obj,
255                                                 uint16_t new_value,
256                                                 Thread* self)
257     REQUIRES_SHARED(Locks::mutator_lock_) {
258   return artSetCharInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
259 }
260 
artSet8StaticFromCode(uint32_t field_idx,uint32_t new_value,ArtMethod * referrer,Thread * self)261 extern "C" int artSet8StaticFromCode(uint32_t field_idx,
262                                      uint32_t new_value,
263                                      ArtMethod* referrer,
264                                      Thread* self)
265     REQUIRES_SHARED(Locks::mutator_lock_) {
266   return artSetBooleanStaticFromCode(field_idx, new_value, referrer, self);
267 }
268 
artSet16StaticFromCode(uint32_t field_idx,uint16_t new_value,ArtMethod * referrer,Thread * self)269 extern "C" int artSet16StaticFromCode(uint32_t field_idx,
270                                       uint16_t new_value,
271                                       ArtMethod* referrer,
272                                       Thread* self)
273     REQUIRES_SHARED(Locks::mutator_lock_) {
274   return artSetCharStaticFromCode(field_idx, new_value, referrer, self);
275 }
276 
artSet8InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint8_t new_value,ArtMethod * referrer,Thread * self)277 extern "C" int artSet8InstanceFromCode(uint32_t field_idx,
278                                        mirror::Object* obj,
279                                        uint8_t new_value,
280                                        ArtMethod* referrer,
281                                        Thread* self)
282     REQUIRES_SHARED(Locks::mutator_lock_) {
283   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, referrer, self);
284 }
285 
artSet16InstanceFromCode(uint32_t field_idx,mirror::Object * obj,uint16_t new_value,ArtMethod * referrer,Thread * self)286 extern "C" int artSet16InstanceFromCode(uint32_t field_idx,
287                                         mirror::Object* obj,
288                                         uint16_t new_value,
289                                         ArtMethod* referrer,
290                                         Thread* self)
291     REQUIRES_SHARED(Locks::mutator_lock_) {
292   return artSetCharInstanceFromCode(field_idx, obj, new_value, referrer, self);
293 }
294 
artReadBarrierMark(mirror::Object * obj)295 extern "C" mirror::Object* artReadBarrierMark(mirror::Object* obj) {
296   DCHECK(kEmitCompilerReadBarrier);
297   return ReadBarrier::Mark(obj);
298 }
299 
artReadBarrierSlow(mirror::Object * ref ATTRIBUTE_UNUSED,mirror::Object * obj,uint32_t offset)300 extern "C" mirror::Object* artReadBarrierSlow(mirror::Object* ref ATTRIBUTE_UNUSED,
301                                               mirror::Object* obj,
302                                               uint32_t offset) {
303   DCHECK(kEmitCompilerReadBarrier);
304   uint8_t* raw_addr = reinterpret_cast<uint8_t*>(obj) + offset;
305   mirror::HeapReference<mirror::Object>* ref_addr =
306      reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_addr);
307   constexpr ReadBarrierOption kReadBarrierOption =
308       kUseReadBarrier ? kWithReadBarrier : kWithoutReadBarrier;
309   mirror::Object* result =
310       ReadBarrier::Barrier<mirror::Object, kReadBarrierOption>(obj,
311                                                                MemberOffset(offset),
312                                                                ref_addr);
313   return result;
314 }
315 
artReadBarrierForRootSlow(GcRoot<mirror::Object> * root)316 extern "C" mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root) {
317   DCHECK(kEmitCompilerReadBarrier);
318   return root->Read();
319 }
320 
321 }  // namespace art
322