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/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 // 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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    386 extern "C" mirror::Object* artReadBarrierMark(mirror::Object* obj) {
    387   DCHECK(kEmitCompilerReadBarrier);
    388   return ReadBarrier::Mark(obj);
    389 }
    390 
    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 
    409 extern "C" mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root) {
    410   DCHECK(kEmitCompilerReadBarrier);
    411   return root->Read();
    412 }
    413 
    414 }  // namespace art
    415