Home | History | Annotate | Download | only in quick
      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_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 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>
     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 
     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 #define ART_GET_FIELD_FROM_CODE(Kind, PrimitiveType, RetType, SetType,         \
     72                                 PrimitiveOrObject, IsObject, Ptr)              \
     73   extern "C" RetType artGet ## Kind ## StaticFromCode(uint32_t field_idx,      \
     74                                                       ArtMethod* referrer,     \
     75                                                       Thread* self)            \
     76       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
     77     ScopedQuickEntrypointChecks sqec(self);                                    \
     78     ArtField* field = FindFieldFast(                                           \
     79         field_idx, referrer, Static ## PrimitiveOrObject ## Read,              \
     80         sizeof(PrimitiveType));                                                \
     81     if (LIKELY(field != nullptr)) {                                            \
     82       return field->Get ## Kind (field->GetDeclaringClass())Ptr;               \
     83     }                                                                          \
     84     field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read, true>(      \
     85         field_idx, referrer, self, sizeof(PrimitiveType));                     \
     86     if (LIKELY(field != nullptr)) {                                            \
     87       return field->Get ## Kind (field->GetDeclaringClass())Ptr;               \
     88     }                                                                          \
     89     /* Will throw exception by checking with Thread::Current. */               \
     90     return 0;                                                                  \
     91   }                                                                            \
     92                                                                                \
     93   extern "C" RetType artGet ## Kind ## InstanceFromCode(uint32_t field_idx,    \
     94                                                         mirror::Object* obj,   \
     95                                                         ArtMethod* referrer,   \
     96                                                         Thread* self)          \
     97       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
     98     ScopedQuickEntrypointChecks sqec(self);                                    \
     99     ArtField* field = FindFieldFast(                                           \
    100         field_idx, referrer, Instance ## PrimitiveOrObject ## Read,            \
    101         sizeof(PrimitiveType));                                                \
    102     if (LIKELY(field != nullptr) && obj != nullptr) {                          \
    103       return field->Get ## Kind (obj)Ptr;                                      \
    104     }                                                                          \
    105     field = FindInstanceField<Instance ## PrimitiveOrObject ## Read, true>(    \
    106         field_idx, referrer, self, sizeof(PrimitiveType), &obj);               \
    107     if (LIKELY(field != nullptr)) {                                            \
    108       return field->Get ## Kind (obj)Ptr;                                      \
    109     }                                                                          \
    110     /* Will throw exception by checking with Thread::Current. */               \
    111     return 0;                                                                  \
    112   }                                                                            \
    113                                                                                \
    114   extern "C" int artSet ## Kind ## StaticFromCode(uint32_t field_idx,          \
    115                                                   SetType new_value,           \
    116                                                   ArtMethod* referrer,         \
    117                                                   Thread* self)                \
    118       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
    119     ScopedQuickEntrypointChecks sqec(self);                                    \
    120     ArtField* field = FindFieldFast(                                           \
    121         field_idx, referrer, Static ## PrimitiveOrObject ## Write,             \
    122         sizeof(PrimitiveType));                                                \
    123     if (LIKELY(field != nullptr)) {                                            \
    124       field->Set ## Kind <false>(field->GetDeclaringClass(), new_value);       \
    125       return 0;                                                                \
    126     }                                                                          \
    127     if (IsObject) {                                                            \
    128       StackHandleScope<1> hs(self);                                            \
    129       HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(                 \
    130           reinterpret_cast<mirror::Object**>(&new_value)));                    \
    131       field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>(   \
    132           field_idx, referrer, self, sizeof(PrimitiveType));                   \
    133     } else {                                                                   \
    134       field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>(   \
    135           field_idx, referrer, self, sizeof(PrimitiveType));                   \
    136     }                                                                          \
    137     if (LIKELY(field != nullptr)) {                                            \
    138       field->Set ## Kind <false>(field->GetDeclaringClass(), new_value);       \
    139       return 0;                                                                \
    140     }                                                                          \
    141     return -1;                                                                 \
    142   }                                                                            \
    143                                                                                \
    144   extern "C" int artSet ## Kind ## InstanceFromCode(uint32_t field_idx,        \
    145                                                     mirror::Object* obj,       \
    146                                                     SetType new_value,         \
    147                                                     ArtMethod* referrer,       \
    148                                                     Thread* self)              \
    149     REQUIRES_SHARED(Locks::mutator_lock_) {                                    \
    150     ScopedQuickEntrypointChecks sqec(self);                                    \
    151     ArtField* field = FindFieldFast(                                           \
    152         field_idx, referrer, Instance ## PrimitiveOrObject ## Write,           \
    153         sizeof(PrimitiveType));                                                \
    154     if (LIKELY(field != nullptr && obj != nullptr)) {                          \
    155       field->Set ## Kind <false>(obj, new_value);                              \
    156       return 0;                                                                \
    157     }                                                                          \
    158     if (IsObject) {                                                            \
    159       StackHandleScope<1> hs(self);                                            \
    160       HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(                 \
    161           reinterpret_cast<mirror::Object**>(&new_value)));                    \
    162       field = FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
    163           field_idx,                                                           \
    164           referrer,                                                            \
    165           self,                                                                \
    166           sizeof(PrimitiveType),                                               \
    167           &obj);                                                               \
    168     } else {                                                                   \
    169       field = FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
    170           field_idx,                                                           \
    171           referrer,                                                            \
    172           self,                                                                \
    173           sizeof(PrimitiveType),                                               \
    174           &obj);                                                               \
    175     }                                                                          \
    176     if (LIKELY(field != nullptr)) {                                            \
    177       field->Set ## Kind<false>(obj, new_value);                               \
    178       return 0;                                                                \
    179     }                                                                          \
    180     return -1;                                                                 \
    181   }                                                                            \
    182                                                                                \
    183   extern "C" RetType artGet ## Kind ## StaticFromCompiledCode(                 \
    184       uint32_t field_idx,                                                      \
    185       Thread* self)                                                            \
    186       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
    187     return artGet ## Kind ## StaticFromCode(                                   \
    188         field_idx, GetReferrer(self), self);                                   \
    189   }                                                                            \
    190                                                                                \
    191   extern "C" RetType artGet ## Kind ## InstanceFromCompiledCode(               \
    192       uint32_t field_idx,                                                      \
    193       mirror::Object* obj,                                                     \
    194       Thread* self)                                                            \
    195       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
    196     return artGet ## Kind ## InstanceFromCode(                                 \
    197         field_idx, obj, GetReferrer(self), self);                              \
    198   }                                                                            \
    199                                                                                \
    200   extern "C" int artSet ## Kind ## StaticFromCompiledCode(                     \
    201       uint32_t field_idx,                                                      \
    202       SetType new_value,                                                       \
    203       Thread* self)                                                            \
    204       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
    205     return artSet ## Kind ## StaticFromCode(                                   \
    206         field_idx, new_value, GetReferrer(self), self);                        \
    207   }                                                                            \
    208                                                                                \
    209   extern "C" int artSet ## Kind ## InstanceFromCompiledCode(                   \
    210       uint32_t field_idx,                                                      \
    211       mirror::Object* obj,                                                     \
    212       SetType new_value,                                                       \
    213       Thread* self)                                                            \
    214       REQUIRES_SHARED(Locks::mutator_lock_) {                                  \
    215     return artSet ## Kind ## InstanceFromCode(                                 \
    216         field_idx, obj, new_value, GetReferrer(self), self);                   \
    217   }
    218 
    219 ART_GET_FIELD_FROM_CODE(Byte, int8_t, ssize_t, uint32_t, Primitive, false, )
    220 ART_GET_FIELD_FROM_CODE(Boolean, int8_t, size_t, uint32_t, Primitive, false, )
    221 ART_GET_FIELD_FROM_CODE(Short, int16_t, ssize_t, uint16_t, Primitive, false, )
    222 ART_GET_FIELD_FROM_CODE(Char, int16_t, size_t, uint16_t, Primitive, false, )
    223 ART_GET_FIELD_FROM_CODE(32, int32_t, size_t, uint32_t, Primitive, false, )
    224 ART_GET_FIELD_FROM_CODE(64, int64_t, uint64_t, uint64_t, Primitive, false, )
    225 ART_GET_FIELD_FROM_CODE(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*,
    226                         mirror::Object*, Object, true, .Ptr())
    227 
    228 
    229 // To cut on the number of entrypoints, we have shared entries for
    230 // byte/boolean and char/short for setting an instance or static field. We just
    231 // forward those to the unsigned variant.
    232 extern "C" int artSet8StaticFromCompiledCode(uint32_t field_idx,
    233                                              uint32_t new_value,
    234                                              Thread* self)
    235     REQUIRES_SHARED(Locks::mutator_lock_) {
    236   return artSetBooleanStaticFromCode(field_idx, new_value, GetReferrer(self), self);
    237 }
    238 
    239 extern "C" int artSet16StaticFromCompiledCode(uint32_t field_idx,
    240                                               uint16_t new_value,
    241                                               Thread* self)
    242     REQUIRES_SHARED(Locks::mutator_lock_) {
    243   return artSetCharStaticFromCode(field_idx, new_value, GetReferrer(self), self);
    244 }
    245 
    246 extern "C" int artSet8InstanceFromCompiledCode(uint32_t field_idx,
    247                                                mirror::Object* obj,
    248                                                uint8_t new_value,
    249                                                Thread* self)
    250     REQUIRES_SHARED(Locks::mutator_lock_) {
    251   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
    252 }
    253 
    254 extern "C" int artSet16InstanceFromCompiledCode(uint32_t field_idx,
    255                                                 mirror::Object* obj,
    256                                                 uint16_t new_value,
    257                                                 Thread* self)
    258     REQUIRES_SHARED(Locks::mutator_lock_) {
    259   return artSetCharInstanceFromCode(field_idx, obj, new_value, GetReferrer(self), self);
    260 }
    261 
    262 extern "C" int artSet8StaticFromCode(uint32_t field_idx,
    263                                      uint32_t new_value,
    264                                      ArtMethod* referrer,
    265                                      Thread* self)
    266     REQUIRES_SHARED(Locks::mutator_lock_) {
    267   return artSetBooleanStaticFromCode(field_idx, new_value, referrer, self);
    268 }
    269 
    270 extern "C" int artSet16StaticFromCode(uint32_t field_idx,
    271                                       uint16_t new_value,
    272                                       ArtMethod* referrer,
    273                                       Thread* self)
    274     REQUIRES_SHARED(Locks::mutator_lock_) {
    275   return artSetCharStaticFromCode(field_idx, new_value, referrer, self);
    276 }
    277 
    278 extern "C" int artSet8InstanceFromCode(uint32_t field_idx,
    279                                        mirror::Object* obj,
    280                                        uint8_t new_value,
    281                                        ArtMethod* referrer,
    282                                        Thread* self)
    283     REQUIRES_SHARED(Locks::mutator_lock_) {
    284   return artSetBooleanInstanceFromCode(field_idx, obj, new_value, referrer, self);
    285 }
    286 
    287 extern "C" int artSet16InstanceFromCode(uint32_t field_idx,
    288                                         mirror::Object* obj,
    289                                         uint16_t new_value,
    290                                         ArtMethod* referrer,
    291                                         Thread* self)
    292     REQUIRES_SHARED(Locks::mutator_lock_) {
    293   return artSetCharInstanceFromCode(field_idx, obj, new_value, referrer, self);
    294 }
    295 
    296 extern "C" mirror::Object* artReadBarrierMark(mirror::Object* obj) {
    297   DCHECK(kEmitCompilerReadBarrier);
    298   return ReadBarrier::Mark(obj);
    299 }
    300 
    301 extern "C" mirror::Object* artReadBarrierSlow(mirror::Object* ref ATTRIBUTE_UNUSED,
    302                                               mirror::Object* obj,
    303                                               uint32_t offset) {
    304   DCHECK(kEmitCompilerReadBarrier);
    305   uint8_t* raw_addr = reinterpret_cast<uint8_t*>(obj) + offset;
    306   mirror::HeapReference<mirror::Object>* ref_addr =
    307      reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_addr);
    308   constexpr ReadBarrierOption kReadBarrierOption =
    309       kUseReadBarrier ? kWithReadBarrier : kWithoutReadBarrier;
    310   mirror::Object* result =
    311       ReadBarrier::Barrier<mirror::Object, kReadBarrierOption>(obj,
    312                                                                MemberOffset(offset),
    313                                                                ref_addr);
    314   return result;
    315 }
    316 
    317 extern "C" mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root) {
    318   DCHECK(kEmitCompilerReadBarrier);
    319   return root->Read();
    320 }
    321 
    322 }  // namespace art
    323