| Elliott Hughes | 0f3c553 | 2012-03-30 14:51:51 -0700 | [diff] [blame] | 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 |  */ | 
| buzbee | 5433072 | 2011-08-23 16:46:55 -0700 | [diff] [blame] | 16 |  | 
| Ian Rogers | 7655f29 | 2013-07-29 11:07:13 -0700 | [diff] [blame] | 17 | #ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ | 
 | 18 | #define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ | 
| Ian Rogers | 450dcb5 | 2013-09-20 17:36:02 -0700 | [diff] [blame] | 19 |  | 
 | 20 | #include "base/macros.h" | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 21 | #include "class_linker.h" | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 22 | #include "common_throws.h" | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 23 | #include "dex_file.h" | 
| Ian Rogers | 81d425b | 2012-09-27 16:03:43 -0700 | [diff] [blame] | 24 | #include "indirect_reference_table.h" | 
| Elliott Hughes | 0f3c553 | 2012-03-30 14:51:51 -0700 | [diff] [blame] | 25 | #include "invoke_type.h" | 
| Ian Rogers | 81d425b | 2012-09-27 16:03:43 -0700 | [diff] [blame] | 26 | #include "jni_internal.h" | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 27 | #include "mirror/art_method.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 28 | #include "mirror/array.h" | 
| Ian Rogers | 693ff61 | 2013-02-01 10:56:12 -0800 | [diff] [blame] | 29 | #include "mirror/class-inl.h" | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 30 | #include "mirror/object-inl.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 31 | #include "mirror/throwable.h" | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 32 | #include "locks.h" | 
| Ian Rogers | 450dcb5 | 2013-09-20 17:36:02 -0700 | [diff] [blame] | 33 | #include "object_utils.h" | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 34 | #include "sirt_ref.h" | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 35 | #include "thread.h" | 
 | 36 |  | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 37 | namespace art { | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 38 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 39 | namespace mirror { | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 40 |   class Class; | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 41 |   class ArtField; | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 42 |   class Object; | 
 | 43 | }  // namespace mirror | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 44 |  | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 45 | // TODO: Fix no thread safety analysis when GCC can handle template specialization. | 
 | 46 | template <const bool kAccessCheck> | 
 | 47 | ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx, | 
 | 48 |                                                             mirror::ArtMethod* method, | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 49 |                                                             Thread* self, bool* slow_path) | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 50 |     NO_THREAD_SAFETY_ANALYSIS { | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 51 |   mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx); | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 52 |   if (UNLIKELY(klass == NULL)) { | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 53 |     klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 54 |     *slow_path = true; | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 55 |     if (klass == NULL) { | 
 | 56 |       DCHECK(self->IsExceptionPending()); | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 57 |       return nullptr;  // Failure | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 58 |     } | 
 | 59 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 60 |   if (kAccessCheck) { | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 61 |     if (UNLIKELY(!klass->IsInstantiable())) { | 
 | 62 |       ThrowLocation throw_location = self->GetCurrentLocationForThrow(); | 
 | 63 |       self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;", | 
 | 64 |                               PrettyDescriptor(klass).c_str()); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 65 |       *slow_path = true; | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 66 |       return nullptr;  // Failure | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 67 |     } | 
 | 68 |     mirror::Class* referrer = method->GetDeclaringClass(); | 
 | 69 |     if (UNLIKELY(!referrer->CanAccess(klass))) { | 
 | 70 |       ThrowIllegalAccessErrorClass(referrer, klass); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 71 |       *slow_path = true; | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 72 |       return nullptr;  // Failure | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 73 |     } | 
 | 74 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 75 |   if (UNLIKELY(!klass->IsInitialized())) { | 
 | 76 |     SirtRef<mirror::Class> sirt_klass(self, klass); | 
 | 77 |     // The class initializer might cause a GC. | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 78 |     if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 79 |       DCHECK(self->IsExceptionPending()); | 
 | 80 |       return nullptr;  // Failure | 
 | 81 |     } | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 82 |     // TODO: EnsureInitialized may cause us to suspend meaning that another thread may try to | 
 | 83 |     // change the allocator while we are stuck in the entrypoints of an old allocator. To handle | 
 | 84 |     // this case we mark the slow path boolean as true so that the caller knows to check the | 
 | 85 |     // allocator type to see if it has changed. | 
 | 86 |     *slow_path = true; | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 87 |     return sirt_klass.get(); | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 88 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 89 |   return klass; | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 90 | } | 
 | 91 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 92 | // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it | 
 | 93 | // cannot be resolved, throw an error. If it can, use it to create an instance. | 
 | 94 | // When verification/compiler hasn't been able to verify access, optionally perform an access | 
 | 95 | // check. | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 96 | // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. | 
 | 97 | template <bool kAccessCheck, bool kInstrumented> | 
 | 98 | ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx, | 
 | 99 |                                                                 mirror::ArtMethod* method, | 
 | 100 |                                                                 Thread* self, | 
 | 101 |                                                                 gc::AllocatorType allocator_type) | 
 | 102 |     NO_THREAD_SAFETY_ANALYSIS { | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 103 |   bool slow_path = false; | 
 | 104 |   mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path); | 
 | 105 |   if (UNLIKELY(slow_path)) { | 
 | 106 |     if (klass == nullptr) { | 
 | 107 |       return nullptr; | 
 | 108 |     } | 
 | 109 |     gc::Heap* heap = Runtime::Current()->GetHeap(); | 
 | 110 |     return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator()); | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 111 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 112 |   return klass->Alloc<kInstrumented>(self, allocator_type); | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 113 | } | 
 | 114 |  | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 115 | // TODO: Fix no thread safety analysis when GCC can handle template specialization. | 
 | 116 | template <bool kAccessCheck> | 
 | 117 | ALWAYS_INLINE static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx, | 
 | 118 |                                                            mirror::ArtMethod* method, | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 119 |                                                            int32_t component_count, | 
 | 120 |                                                            bool* slow_path) | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 121 |     NO_THREAD_SAFETY_ANALYSIS { | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 122 |   if (UNLIKELY(component_count < 0)) { | 
 | 123 |     ThrowNegativeArraySizeException(component_count); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 124 |     *slow_path = true; | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 125 |     return nullptr;  // Failure | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 126 |   } | 
 | 127 |   mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx); | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 128 |   if (UNLIKELY(klass == nullptr)) {  // Not in dex cache so try to resolve | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 129 |     klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 130 |     *slow_path = true; | 
 | 131 |     if (klass == nullptr) {  // Error | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 132 |       DCHECK(Thread::Current()->IsExceptionPending()); | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 133 |       return nullptr;  // Failure | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 134 |     } | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 135 |     CHECK(klass->IsArrayClass()) << PrettyClass(klass); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 136 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 137 |   if (kAccessCheck) { | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 138 |     mirror::Class* referrer = method->GetDeclaringClass(); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 139 |     if (UNLIKELY(!referrer->CanAccess(klass))) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 140 |       ThrowIllegalAccessErrorClass(referrer, klass); | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 141 |       *slow_path = true; | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 142 |       return nullptr;  // Failure | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 143 |     } | 
 | 144 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 145 |   return klass; | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 146 | } | 
 | 147 |  | 
 | 148 | // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If | 
 | 149 | // it cannot be resolved, throw an error. If it can, use it to create an array. | 
 | 150 | // When verification/compiler hasn't been able to verify access, optionally perform an access | 
 | 151 | // check. | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 152 | // TODO: Fix no thread safety analysis when GCC can handle template specialization. | 
 | 153 | template <bool kAccessCheck, bool kInstrumented> | 
 | 154 | ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx, | 
 | 155 |                                                               mirror::ArtMethod* method, | 
 | 156 |                                                               int32_t component_count, | 
 | 157 |                                                               Thread* self, | 
 | 158 |                                                               gc::AllocatorType allocator_type) | 
 | 159 |     NO_THREAD_SAFETY_ANALYSIS { | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 160 |   bool slow_path = false; | 
 | 161 |   mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count, | 
 | 162 |                                                        &slow_path); | 
 | 163 |   if (UNLIKELY(slow_path)) { | 
 | 164 |     if (klass == nullptr) { | 
 | 165 |       return nullptr; | 
 | 166 |     } | 
 | 167 |     gc::Heap* heap = Runtime::Current()->GetHeap(); | 
 | 168 |     return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, | 
 | 169 |                                                heap->GetCurrentAllocator()); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 170 |   } | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 171 |   return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, allocator_type); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 172 | } | 
 | 173 |  | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 174 | extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method, | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 175 |                                                  int32_t component_count, Thread* self, | 
 | 176 |                                                  bool access_check, | 
 | 177 |                                                  gc::AllocatorType allocator_type) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 178 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 179 |  | 
| Mathieu Chartier | cbb2d20 | 2013-11-14 17:45:16 -0800 | [diff] [blame] | 180 | extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx, | 
 | 181 |                                                              mirror::ArtMethod* method, | 
 | 182 |                                                              int32_t component_count, Thread* self, | 
 | 183 |                                                              bool access_check, | 
 | 184 |                                                              gc::AllocatorType allocator_type) | 
| Hiroshi Yamauchi | 3b4c189 | 2013-09-12 21:33:12 -0700 | [diff] [blame] | 185 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); | 
 | 186 |  | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 187 | // Type of find field operation for fast and slow case. | 
 | 188 | enum FindFieldType { | 
 | 189 |   InstanceObjectRead, | 
 | 190 |   InstanceObjectWrite, | 
 | 191 |   InstancePrimitiveRead, | 
 | 192 |   InstancePrimitiveWrite, | 
 | 193 |   StaticObjectRead, | 
 | 194 |   StaticObjectWrite, | 
 | 195 |   StaticPrimitiveRead, | 
 | 196 |   StaticPrimitiveWrite, | 
 | 197 | }; | 
 | 198 |  | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 199 | template<FindFieldType type, bool access_check> | 
 | 200 | static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirror::ArtMethod* referrer, | 
 | 201 |                                                   Thread* self, size_t expected_size) { | 
 | 202 |   bool is_primitive; | 
 | 203 |   bool is_set; | 
 | 204 |   bool is_static; | 
 | 205 |   switch (type) { | 
 | 206 |     case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break; | 
 | 207 |     case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break; | 
 | 208 |     case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break; | 
 | 209 |     case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break; | 
 | 210 |     case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break; | 
 | 211 |     case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break; | 
 | 212 |     case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break; | 
 | 213 |     case StaticPrimitiveWrite:   // Keep GCC happy by having a default handler, fall-through. | 
 | 214 |     default:                     is_primitive = true;  is_set = true;  is_static = true;  break; | 
 | 215 |   } | 
 | 216 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 217 |   mirror::ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static); | 
 | 218 |   if (UNLIKELY(resolved_field == nullptr)) { | 
 | 219 |     DCHECK(self->IsExceptionPending());  // Throw exception and unwind. | 
 | 220 |     return nullptr;  // Failure. | 
 | 221 |   } | 
 | 222 |   mirror::Class* fields_class = resolved_field->GetDeclaringClass(); | 
 | 223 |   if (access_check) { | 
 | 224 |     if (UNLIKELY(resolved_field->IsStatic() != is_static)) { | 
 | 225 |       ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer); | 
 | 226 |       return nullptr; | 
 | 227 |     } | 
 | 228 |     mirror::Class* referring_class = referrer->GetDeclaringClass(); | 
| Vladimir Marko | 23a2821 | 2014-01-09 19:24:37 +0000 | [diff] [blame^] | 229 |     if (UNLIKELY(!referring_class->CanAccessResolvedField<true>(fields_class, resolved_field, | 
 | 230 |                                                                 field_idx))) { | 
 | 231 |       DCHECK(self->IsExceptionPending());  // Throw exception and unwind. | 
 | 232 |       return nullptr;  // Failure. | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 233 |     } | 
 | 234 |     if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) { | 
 | 235 |       ThrowIllegalAccessErrorFinalField(referrer, resolved_field); | 
| Vladimir Marko | 23a2821 | 2014-01-09 19:24:37 +0000 | [diff] [blame^] | 236 |       return nullptr;  // Failure. | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 237 |     } else { | 
 | 238 |       FieldHelper fh(resolved_field); | 
 | 239 |       if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || | 
 | 240 |                    fh.FieldSize() != expected_size)) { | 
 | 241 |         ThrowLocation throw_location = self->GetCurrentLocationForThrow(); | 
 | 242 |         DCHECK(throw_location.GetMethod() == referrer); | 
 | 243 |         self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;", | 
 | 244 |                                  "Attempted read of %zd-bit %s on field '%s'", | 
 | 245 |                                  expected_size * (32 / sizeof(int32_t)), | 
 | 246 |                                  is_primitive ? "primitive" : "non-primitive", | 
 | 247 |                                  PrettyField(resolved_field, true).c_str()); | 
| Vladimir Marko | 23a2821 | 2014-01-09 19:24:37 +0000 | [diff] [blame^] | 248 |         return nullptr;  // Failure. | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 249 |       } | 
 | 250 |     } | 
 | 251 |   } | 
 | 252 |   if (!is_static) { | 
 | 253 |     // instance fields must be being accessed on an initialized class | 
 | 254 |     return resolved_field; | 
 | 255 |   } else { | 
 | 256 |     // If the class is initialized we're done. | 
 | 257 |     if (LIKELY(fields_class->IsInitialized())) { | 
 | 258 |       return resolved_field; | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 259 |     } else { | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 260 |       SirtRef<mirror::Class> sirt_class(self, fields_class); | 
 | 261 |       if (LIKELY(class_linker->EnsureInitialized(sirt_class, true, true))) { | 
 | 262 |         // Otherwise let's ensure the class is initialized before resolving the field. | 
 | 263 |         return resolved_field; | 
 | 264 |       } else { | 
 | 265 |         DCHECK(self->IsExceptionPending());  // Throw exception and unwind | 
| Vladimir Marko | 23a2821 | 2014-01-09 19:24:37 +0000 | [diff] [blame^] | 266 |         return nullptr;  // Failure. | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 267 |       } | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 268 |     } | 
 | 269 |   } | 
 | 270 | } | 
 | 271 |  | 
 | 272 | // Explicit template declarations of FindFieldFromCode for all field access types. | 
 | 273 | #define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \ | 
 | 274 | template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \ | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 275 | mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \ | 
 | 276 |                                                           const mirror::ArtMethod* referrer, \ | 
 | 277 |                                                           Thread* self, size_t expected_size) \ | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 278 |  | 
 | 279 | #define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ | 
 | 280 |     EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \ | 
 | 281 |     EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true) | 
 | 282 |  | 
 | 283 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead); | 
 | 284 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite); | 
 | 285 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead); | 
 | 286 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite); | 
 | 287 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead); | 
 | 288 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite); | 
 | 289 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead); | 
 | 290 | EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite); | 
 | 291 |  | 
 | 292 | #undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL | 
 | 293 | #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL | 
 | 294 |  | 
 | 295 | template<InvokeType type, bool access_check> | 
 | 296 | static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object, | 
 | 297 |                                                     mirror::ArtMethod* referrer, Thread* self) { | 
 | 298 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 299 |   mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type); | 
 | 300 |   if (UNLIKELY(resolved_method == nullptr)) { | 
 | 301 |     DCHECK(self->IsExceptionPending());  // Throw exception and unwind. | 
 | 302 |     return nullptr;  // Failure. | 
 | 303 |   } else if (UNLIKELY(this_object == nullptr && type != kStatic)) { | 
 | 304 |     // Maintain interpreter-like semantics where NullPointerException is thrown | 
 | 305 |     // after potential NoSuchMethodError from class linker. | 
 | 306 |     ThrowLocation throw_location = self->GetCurrentLocationForThrow(); | 
 | 307 |     DCHECK(referrer == throw_location.GetMethod()); | 
 | 308 |     ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type); | 
 | 309 |     return nullptr;  // Failure. | 
 | 310 |   } else if (access_check) { | 
 | 311 |     // Incompatible class change should have been handled in resolve method. | 
 | 312 |     if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) { | 
 | 313 |       ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method, | 
 | 314 |                                         referrer); | 
 | 315 |       return nullptr;  // Failure. | 
 | 316 |     } | 
 | 317 |     mirror::Class* methods_class = resolved_method->GetDeclaringClass(); | 
 | 318 |     mirror::Class* referring_class = referrer->GetDeclaringClass(); | 
| Vladimir Marko | 23a2821 | 2014-01-09 19:24:37 +0000 | [diff] [blame^] | 319 |     if (!referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method, | 
 | 320 |                                                               method_idx)) { | 
 | 321 |       DCHECK(self->IsExceptionPending());  // Throw exception and unwind. | 
 | 322 |       return nullptr;  // Failure. | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 323 |     } | 
 | 324 |   } | 
 | 325 |   switch (type) { | 
 | 326 |     case kStatic: | 
 | 327 |     case kDirect: | 
 | 328 |       return resolved_method; | 
 | 329 |     case kVirtual: { | 
 | 330 |       mirror::ObjectArray<mirror::ArtMethod>* vtable = this_object->GetClass()->GetVTable(); | 
 | 331 |       uint16_t vtable_index = resolved_method->GetMethodIndex(); | 
 | 332 |       if (access_check && | 
 | 333 |           (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) { | 
 | 334 |         // Behavior to agree with that of the verifier. | 
 | 335 |         MethodHelper mh(resolved_method); | 
 | 336 |         ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(), | 
 | 337 |                                mh.GetSignature()); | 
 | 338 |         return nullptr;  // Failure. | 
 | 339 |       } | 
 | 340 |       DCHECK(vtable != nullptr); | 
 | 341 |       return vtable->GetWithoutChecks(vtable_index); | 
 | 342 |     } | 
 | 343 |     case kSuper: { | 
 | 344 |       mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass(); | 
 | 345 |       uint16_t vtable_index = resolved_method->GetMethodIndex(); | 
 | 346 |       mirror::ObjectArray<mirror::ArtMethod>* vtable; | 
 | 347 |       if (access_check) { | 
 | 348 |         // Check existence of super class. | 
 | 349 |         vtable = (super_class != nullptr) ? super_class->GetVTable() : nullptr; | 
 | 350 |         if (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength())) { | 
 | 351 |           // Behavior to agree with that of the verifier. | 
 | 352 |           MethodHelper mh(resolved_method); | 
 | 353 |           ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(), | 
 | 354 |                                  mh.GetSignature()); | 
 | 355 |           return nullptr;  // Failure. | 
 | 356 |         } | 
 | 357 |       } else { | 
 | 358 |         // Super class must exist. | 
 | 359 |         DCHECK(super_class != nullptr); | 
 | 360 |         vtable = super_class->GetVTable(); | 
 | 361 |       } | 
 | 362 |       DCHECK(vtable != nullptr); | 
 | 363 |       return vtable->GetWithoutChecks(vtable_index); | 
 | 364 |     } | 
 | 365 |     case kInterface: { | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 366 |       uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize; | 
 | 367 |       mirror::ObjectArray<mirror::ArtMethod>* imt_table = this_object->GetClass()->GetImTable(); | 
 | 368 |       mirror::ArtMethod* imt_method = imt_table->Get(imt_index); | 
 | 369 |       if (!imt_method->IsImtConflictMethod()) { | 
 | 370 |         return imt_method; | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 371 |       } else { | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 372 |         mirror::ArtMethod* interface_method = | 
 | 373 |             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); | 
 | 374 |         if (UNLIKELY(interface_method == nullptr)) { | 
 | 375 |           ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, | 
 | 376 |                                                                      referrer); | 
 | 377 |           return nullptr;  // Failure. | 
 | 378 |         } else { | 
 | 379 |           return interface_method; | 
 | 380 |         } | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 381 |       } | 
 | 382 |     } | 
 | 383 |     default: | 
 | 384 |       LOG(FATAL) << "Unknown invoke type " << type; | 
 | 385 |       return nullptr;  // Failure. | 
 | 386 |   } | 
 | 387 | } | 
 | 388 |  | 
 | 389 | // Explicit template declarations of FindMethodFromCode for all invoke types. | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 390 | #define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \ | 
 | 391 |   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \ | 
 | 392 |   mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \ | 
 | 393 |                                                               mirror::Object* this_object, \ | 
 | 394 |                                                               mirror::ArtMethod* referrer, \ | 
 | 395 |                                                               Thread* self) | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 396 | #define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ | 
 | 397 |     EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \ | 
 | 398 |     EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true) | 
 | 399 |  | 
 | 400 | EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic); | 
 | 401 | EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect); | 
 | 402 | EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual); | 
 | 403 | EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper); | 
 | 404 | EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface); | 
 | 405 |  | 
 | 406 | #undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL | 
 | 407 | #undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 408 |  | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 409 | // Fast path field resolution that can't initialize classes or throw exceptions. | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 410 | static inline mirror::ArtField* FindFieldFast(uint32_t field_idx, | 
 | 411 |                                               const mirror::ArtMethod* referrer, | 
 | 412 |                                               FindFieldType type, size_t expected_size) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 413 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 414 |   mirror::ArtField* resolved_field = | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 415 |       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 416 |   if (UNLIKELY(resolved_field == NULL)) { | 
 | 417 |     return NULL; | 
 | 418 |   } | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 419 |   mirror::Class* fields_class = resolved_field->GetDeclaringClass(); | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 420 |   // Check class is initiliazed or initializing. | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 421 |   if (UNLIKELY(!fields_class->IsInitializing())) { | 
 | 422 |     return NULL; | 
 | 423 |   } | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 424 |   // Check for incompatible class change. | 
 | 425 |   bool is_primitive; | 
 | 426 |   bool is_set; | 
 | 427 |   bool is_static; | 
 | 428 |   switch (type) { | 
 | 429 |     case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break; | 
 | 430 |     case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break; | 
 | 431 |     case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break; | 
 | 432 |     case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break; | 
 | 433 |     case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break; | 
 | 434 |     case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break; | 
 | 435 |     case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break; | 
 | 436 |     case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break; | 
| Brian Carlstrom | f69863b | 2013-07-17 21:53:13 -0700 | [diff] [blame] | 437 |     default: | 
 | 438 |       LOG(FATAL) << "UNREACHABLE";  // Assignment below to avoid GCC warnings. | 
 | 439 |       is_primitive = true; | 
 | 440 |       is_set = true; | 
 | 441 |       is_static = true; | 
 | 442 |       break; | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 443 |   } | 
 | 444 |   if (UNLIKELY(resolved_field->IsStatic() != is_static)) { | 
 | 445 |     // Incompatible class change. | 
 | 446 |     return NULL; | 
 | 447 |   } | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 448 |   mirror::Class* referring_class = referrer->GetDeclaringClass(); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 449 |   if (UNLIKELY(!referring_class->CanAccess(fields_class) || | 
 | 450 |                !referring_class->CanAccessMember(fields_class, | 
 | 451 |                                                  resolved_field->GetAccessFlags()) || | 
 | 452 |                (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) { | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 453 |     // Illegal access. | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 454 |     return NULL; | 
 | 455 |   } | 
 | 456 |   FieldHelper fh(resolved_field); | 
 | 457 |   if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || | 
 | 458 |                fh.FieldSize() != expected_size)) { | 
 | 459 |     return NULL; | 
 | 460 |   } | 
 | 461 |   return resolved_field; | 
 | 462 | } | 
 | 463 |  | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 464 | // Fast path method resolution that can't throw exceptions. | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 465 | static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx, | 
 | 466 |                                                 mirror::Object* this_object, | 
 | 467 |                                                 const mirror::ArtMethod* referrer, | 
 | 468 |                                                 bool access_check, InvokeType type) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 469 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 470 |   bool is_direct = type == kStatic || type == kDirect; | 
 | 471 |   if (UNLIKELY(this_object == NULL && !is_direct)) { | 
 | 472 |     return NULL; | 
 | 473 |   } | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 474 |   mirror::ArtMethod* resolved_method = | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 475 |       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx); | 
 | 476 |   if (UNLIKELY(resolved_method == NULL)) { | 
 | 477 |     return NULL; | 
 | 478 |   } | 
 | 479 |   if (access_check) { | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 480 |     // Check for incompatible class change errors and access. | 
 | 481 |     bool icce = resolved_method->CheckIncompatibleClassChange(type); | 
 | 482 |     if (UNLIKELY(icce)) { | 
 | 483 |       return NULL; | 
 | 484 |     } | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 485 |     mirror::Class* methods_class = resolved_method->GetDeclaringClass(); | 
 | 486 |     mirror::Class* referring_class = referrer->GetDeclaringClass(); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 487 |     if (UNLIKELY(!referring_class->CanAccess(methods_class) || | 
 | 488 |                  !referring_class->CanAccessMember(methods_class, | 
 | 489 |                                                    resolved_method->GetAccessFlags()))) { | 
| Ian Rogers | 08f753d | 2012-08-24 14:35:25 -0700 | [diff] [blame] | 490 |       // Potential illegal access, may need to refine the method's class. | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 491 |       return NULL; | 
 | 492 |     } | 
 | 493 |   } | 
 | 494 |   if (type == kInterface) {  // Most common form of slow path dispatch. | 
 | 495 |     return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); | 
 | 496 |   } else if (is_direct) { | 
 | 497 |     return resolved_method; | 
 | 498 |   } else if (type == kSuper) { | 
 | 499 |     return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()-> | 
 | 500 |         Get(resolved_method->GetMethodIndex()); | 
 | 501 |   } else { | 
 | 502 |     DCHECK(type == kVirtual); | 
 | 503 |     return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex()); | 
 | 504 |   } | 
 | 505 | } | 
 | 506 |  | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 507 | static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 508 |                                                     const mirror::ArtMethod* referrer, | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 509 |                                                     Thread* self, bool can_run_clinit, | 
 | 510 |                                                     bool verify_access) | 
 | 511 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 512 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 513 |   mirror::Class* klass = class_linker->ResolveType(type_idx, referrer); | 
| Ian Rogers | 5ddb410 | 2014-01-07 08:58:46 -0800 | [diff] [blame] | 514 |   if (UNLIKELY(klass == nullptr)) { | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 515 |     CHECK(self->IsExceptionPending()); | 
| Ian Rogers | 5ddb410 | 2014-01-07 08:58:46 -0800 | [diff] [blame] | 516 |     return nullptr;  // Failure - Indicate to caller to deliver exception | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 517 |   } | 
 | 518 |   // Perform access check if necessary. | 
 | 519 |   mirror::Class* referring_class = referrer->GetDeclaringClass(); | 
 | 520 |   if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) { | 
 | 521 |     ThrowIllegalAccessErrorClass(referring_class, klass); | 
| Ian Rogers | 5ddb410 | 2014-01-07 08:58:46 -0800 | [diff] [blame] | 522 |     return nullptr;  // Failure - Indicate to caller to deliver exception | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 523 |   } | 
 | 524 |   // If we're just implementing const-class, we shouldn't call <clinit>. | 
 | 525 |   if (!can_run_clinit) { | 
 | 526 |     return klass; | 
 | 527 |   } | 
 | 528 |   // If we are the <clinit> of this class, just return our storage. | 
 | 529 |   // | 
 | 530 |   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished | 
 | 531 |   // running. | 
| Ian Rogers | 241b5de | 2013-10-09 17:58:57 -0700 | [diff] [blame] | 532 |   if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) { | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 533 |     return klass; | 
 | 534 |   } | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 535 |   SirtRef<mirror::Class> sirt_class(self, klass); | 
 | 536 |   if (!class_linker->EnsureInitialized(sirt_class, true, true)) { | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 537 |     CHECK(self->IsExceptionPending()); | 
| Ian Rogers | 5ddb410 | 2014-01-07 08:58:46 -0800 | [diff] [blame] | 538 |     return nullptr;  // Failure - Indicate to caller to deliver exception | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 539 |   } | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 540 |   return sirt_class.get(); | 
| Ian Rogers | fa46d3e | 2013-05-15 00:16:04 -0700 | [diff] [blame] | 541 | } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 542 |  | 
| jeffhao | d752132 | 2012-11-21 15:38:24 -0800 | [diff] [blame] | 543 | extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); | 
 | 544 |  | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 545 | static inline mirror::String* ResolveStringFromCode(const mirror::ArtMethod* referrer, | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 546 |                                                     uint32_t string_idx) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 547 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 548 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 549 |   return class_linker->ResolveString(string_idx, referrer); | 
 | 550 | } | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 551 |  | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 552 | static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 553 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 554 |     UNLOCK_FUNCTION(monitor_lock_) { | 
 | 555 |   // Save any pending exception over monitor exit call. | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 556 |   mirror::Throwable* saved_exception = NULL; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 557 |   ThrowLocation saved_throw_location; | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 558 |   if (UNLIKELY(self->IsExceptionPending())) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 559 |     saved_exception = self->GetException(&saved_throw_location); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 560 |     self->ClearException(); | 
 | 561 |   } | 
 | 562 |   // Decode locked object and unlock, before popping local references. | 
 | 563 |   self->DecodeJObject(locked)->MonitorExit(self); | 
 | 564 |   if (UNLIKELY(self->IsExceptionPending())) { | 
 | 565 |     LOG(FATAL) << "Synchronized JNI code returning with an exception:\n" | 
 | 566 |         << saved_exception->Dump() | 
 | 567 |         << "\nEncountered second exception during implicit MonitorExit:\n" | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 568 |         << self->GetException(NULL)->Dump(); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 569 |   } | 
 | 570 |   // Restore pending exception. | 
 | 571 |   if (saved_exception != NULL) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 572 |     self->SetException(saved_throw_location, saved_exception); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 573 |   } | 
 | 574 | } | 
 | 575 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 576 | static inline void CheckReferenceResult(mirror::Object* o, Thread* self) | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 577 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 578 |   if (o == NULL) { | 
 | 579 |     return; | 
 | 580 |   } | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 581 |   mirror::ArtMethod* m = self->GetCurrentMethod(NULL); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 582 |   if (o == kInvalidIndirectRefObject) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 583 |     JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str()); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 584 |   } | 
 | 585 |   // Make sure that the result is an instance of the type this method was expected to return. | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 586 |   mirror::Class* return_type = MethodHelper(m).GetReturnType(); | 
| TDYa127 | 3d71d80 | 2012-08-15 03:47:03 -0700 | [diff] [blame] | 587 |  | 
 | 588 |   if (!o->InstanceOf(return_type)) { | 
 | 589 |     JniAbortF(NULL, "attempt to return an instance of %s from %s", | 
 | 590 |               PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str()); | 
 | 591 |   } | 
 | 592 | } | 
 | 593 |  | 
| Ian Rogers | af6e67a | 2013-01-16 08:38:37 -0800 | [diff] [blame] | 594 | static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
| jeffhao | 373c52f | 2012-11-20 16:11:52 -0800 | [diff] [blame] | 595 |   for (;;) { | 
 | 596 |     if (thread->ReadFlag(kCheckpointRequest)) { | 
 | 597 |       thread->RunCheckpointFunction(); | 
| jeffhao | 373c52f | 2012-11-20 16:11:52 -0800 | [diff] [blame] | 598 |     } else if (thread->ReadFlag(kSuspendRequest)) { | 
 | 599 |       thread->FullSuspendCheck(); | 
 | 600 |     } else { | 
 | 601 |       break; | 
 | 602 |     } | 
 | 603 |   } | 
 | 604 | } | 
 | 605 |  | 
| Ian Rogers | af6e67a | 2013-01-16 08:38:37 -0800 | [diff] [blame] | 606 | JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty, | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 607 |                                     jobject rcvr_jobj, jobject interface_art_method_jobj, | 
| Ian Rogers | af6e67a | 2013-01-16 08:38:37 -0800 | [diff] [blame] | 608 |                                     std::vector<jvalue>& args) | 
| Brian Carlstrom | 02c8cc6 | 2013-07-18 15:54:44 -0700 | [diff] [blame] | 609 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); | 
| Ian Rogers | af6e67a | 2013-01-16 08:38:37 -0800 | [diff] [blame] | 610 |  | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 611 | // Entry point for deoptimization. | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 612 | extern "C" void art_quick_deoptimize(); | 
 | 613 | static inline uintptr_t GetQuickDeoptimizationEntryPoint() { | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 614 |   return reinterpret_cast<uintptr_t>(art_quick_deoptimize); | 
 | 615 | } | 
 | 616 |  | 
 | 617 | // Return address of instrumentation stub. | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 618 | extern "C" void art_quick_instrumentation_entry(void*); | 
 | 619 | static inline void* GetQuickInstrumentationEntryPoint() { | 
 | 620 |   return reinterpret_cast<void*>(art_quick_instrumentation_entry); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 621 | } | 
 | 622 |  | 
 | 623 | // The return_pc of instrumentation exit stub. | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 624 | extern "C" void art_quick_instrumentation_exit(); | 
 | 625 | static inline uintptr_t GetQuickInstrumentationExitPc() { | 
 | 626 |   return reinterpret_cast<uintptr_t>(art_quick_instrumentation_exit); | 
 | 627 | } | 
 | 628 |  | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 629 | extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 630 | static inline const void* GetPortableToInterpreterBridge() { | 
 | 631 |   return reinterpret_cast<void*>(art_portable_to_interpreter_bridge); | 
 | 632 | } | 
 | 633 |  | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 634 | extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 635 | static inline const void* GetQuickToInterpreterBridge() { | 
 | 636 |   return reinterpret_cast<void*>(art_quick_to_interpreter_bridge); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 637 | } | 
 | 638 |  | 
 | 639 | // Return address of interpreter stub. | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 640 | static inline const void* GetCompiledCodeToInterpreterBridge() { | 
 | 641 | #if defined(ART_USE_PORTABLE_COMPILER) | 
 | 642 |   return GetPortableToInterpreterBridge(); | 
 | 643 | #else | 
 | 644 |   return GetQuickToInterpreterBridge(); | 
 | 645 | #endif | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 646 | } | 
 | 647 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 648 |  | 
| Jeff Hao | 0aba0ba | 2013-06-03 14:49:28 -0700 | [diff] [blame] | 649 | static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) { | 
 | 650 |   return class_linker->GetPortableResolutionTrampoline(); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 651 | } | 
 | 652 |  | 
| Jeff Hao | 0aba0ba | 2013-06-03 14:49:28 -0700 | [diff] [blame] | 653 | static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) { | 
 | 654 |   return class_linker->GetQuickResolutionTrampoline(); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 655 | } | 
 | 656 |  | 
 | 657 | // Return address of resolution trampoline stub for defined compiler. | 
| Jeff Hao | 0aba0ba | 2013-06-03 14:49:28 -0700 | [diff] [blame] | 658 | static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 659 | #if defined(ART_USE_PORTABLE_COMPILER) | 
| Jeff Hao | 0aba0ba | 2013-06-03 14:49:28 -0700 | [diff] [blame] | 660 |   return GetPortableResolutionTrampoline(class_linker); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 661 | #else | 
| Jeff Hao | 0aba0ba | 2013-06-03 14:49:28 -0700 | [diff] [blame] | 662 |   return GetQuickResolutionTrampoline(class_linker); | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 663 | #endif | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 664 | } | 
 | 665 |  | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 666 | static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) { | 
 | 667 |   return class_linker->GetPortableImtConflictTrampoline(); | 
 | 668 | } | 
 | 669 |  | 
 | 670 | static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) { | 
 | 671 |   return class_linker->GetQuickImtConflictTrampoline(); | 
 | 672 | } | 
 | 673 |  | 
 | 674 | // Return address of imt conflict trampoline stub for defined compiler. | 
 | 675 | static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) { | 
 | 676 | #if defined(ART_USE_PORTABLE_COMPILER) | 
 | 677 |   return GetPortableImtConflictTrampoline(class_linker); | 
 | 678 | #else | 
 | 679 |   return GetQuickImtConflictTrampoline(class_linker); | 
 | 680 | #endif | 
 | 681 | } | 
 | 682 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 683 | extern "C" void art_portable_proxy_invoke_handler(); | 
 | 684 | static inline const void* GetPortableProxyInvokeHandler() { | 
 | 685 |   return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 686 | } | 
 | 687 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 688 | extern "C" void art_quick_proxy_invoke_handler(); | 
 | 689 | static inline const void* GetQuickProxyInvokeHandler() { | 
 | 690 |   return reinterpret_cast<void*>(art_quick_proxy_invoke_handler); | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 691 | } | 
 | 692 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 693 | static inline const void* GetProxyInvokeHandler() { | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 694 | #if defined(ART_USE_PORTABLE_COMPILER) | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 695 |   return GetPortableProxyInvokeHandler(); | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 696 | #else | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 697 |   return GetQuickProxyInvokeHandler(); | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 698 | #endif | 
 | 699 | } | 
 | 700 |  | 
| Ian Rogers | 848871b | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 701 | extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject); | 
| Jeff Hao | 79fe539 | 2013-04-24 18:41:58 -0700 | [diff] [blame] | 702 | static inline void* GetJniDlsymLookupStub() { | 
 | 703 |   return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub); | 
 | 704 | } | 
| Jeff Hao | 58df327 | 2013-04-22 15:28:53 -0700 | [diff] [blame] | 705 |  | 
| Ian Rogers | 450dcb5 | 2013-09-20 17:36:02 -0700 | [diff] [blame] | 706 | template <typename INT_TYPE, typename FLOAT_TYPE> | 
 | 707 | static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) { | 
 | 708 |   const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max()); | 
 | 709 |   const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min()); | 
 | 710 |   const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt); | 
 | 711 |   const FLOAT_TYPE kMinIntAsFloat = static_cast<FLOAT_TYPE>(kMinInt); | 
 | 712 |   if (LIKELY(f > kMinIntAsFloat)) { | 
 | 713 |      if (LIKELY(f < kMaxIntAsFloat)) { | 
 | 714 |        return static_cast<INT_TYPE>(f); | 
 | 715 |      } else { | 
 | 716 |        return kMaxInt; | 
 | 717 |      } | 
 | 718 |   } else { | 
 | 719 |     return (f != f) ? 0 : kMinInt;  // f != f implies NaN | 
 | 720 |   } | 
 | 721 | } | 
 | 722 |  | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 723 | }  // namespace art | 
| Ian Rogers | ad42e13 | 2011-09-17 20:23:33 -0700 | [diff] [blame] | 724 |  | 
| Ian Rogers | 7655f29 | 2013-07-29 11:07:13 -0700 | [diff] [blame] | 725 | #endif  // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ |