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