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