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 #ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 18 #define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 19 20 #include "base/casts.h" 21 #include "java_vm_ext.h" 22 #include "jni_env_ext-inl.h" 23 #include "art_field.h" 24 #include "read_barrier.h" 25 #include "thread-inl.h" 26 #include "verify_object.h" 27 28 namespace art { 29 30 // Scoped change into and out of a particular state. Handles Runnable transitions that require 31 // more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and 32 // ScopedObjectAccess are used to handle the change into Runnable to Get direct access to objects, 33 // the unchecked variant doesn't aid annotalysis. 34 class ScopedThreadStateChange : public ValueObject { 35 public: ScopedThreadStateChange(Thread * self,ThreadState new_thread_state)36 ScopedThreadStateChange(Thread* self, ThreadState new_thread_state) 37 REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE 38 : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) { 39 if (UNLIKELY(self_ == nullptr)) { 40 // Value chosen arbitrarily and won't be used in the destructor since thread_ == null. 41 old_thread_state_ = kTerminated; 42 Runtime* runtime = Runtime::Current(); 43 CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_)); 44 } else { 45 DCHECK_EQ(self, Thread::Current()); 46 // Read state without locks, ok as state is effectively thread local and we're not interested 47 // in the suspend count (this will be handled in the runnable transitions). 48 old_thread_state_ = self->GetState(); 49 if (old_thread_state_ != new_thread_state) { 50 if (new_thread_state == kRunnable) { 51 self_->TransitionFromSuspendedToRunnable(); 52 } else if (old_thread_state_ == kRunnable) { 53 self_->TransitionFromRunnableToSuspended(new_thread_state); 54 } else { 55 // A suspended transition to another effectively suspended transition, ok to use Unsafe. 56 self_->SetState(new_thread_state); 57 } 58 } 59 } 60 } 61 62 ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE { 63 if (UNLIKELY(self_ == nullptr)) { 64 if (!expected_has_no_thread_) { 65 Runtime* runtime = Runtime::Current(); 66 bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr); 67 CHECK(shutting_down); 68 } 69 } else { 70 if (old_thread_state_ != thread_state_) { 71 if (old_thread_state_ == kRunnable) { 72 self_->TransitionFromSuspendedToRunnable(); 73 } else if (thread_state_ == kRunnable) { 74 self_->TransitionFromRunnableToSuspended(old_thread_state_); 75 } else { 76 // A suspended transition to another effectively suspended transition, ok to use Unsafe. 77 self_->SetState(old_thread_state_); 78 } 79 } 80 } 81 } 82 Self()83 Thread* Self() const { 84 return self_; 85 } 86 87 protected: 88 // Constructor used by ScopedJniThreadState for an unattached thread that has access to the VM*. ScopedThreadStateChange()89 ScopedThreadStateChange() 90 : self_(nullptr), thread_state_(kTerminated), old_thread_state_(kTerminated), 91 expected_has_no_thread_(true) {} 92 93 Thread* const self_; 94 const ThreadState thread_state_; 95 96 private: 97 ThreadState old_thread_state_; 98 const bool expected_has_no_thread_; 99 100 friend class ScopedObjectAccessUnchecked; 101 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange); 102 }; 103 104 // Assumes we are already runnable. 105 class ScopedObjectAccessAlreadyRunnable : public ValueObject { 106 public: Self()107 Thread* Self() const { 108 return self_; 109 } 110 Env()111 JNIEnvExt* Env() const { 112 return env_; 113 } 114 Vm()115 JavaVMExt* Vm() const { 116 return vm_; 117 } 118 ForceCopy()119 bool ForceCopy() const { 120 return vm_->ForceCopy(); 121 } 122 123 /* 124 * Add a local reference for an object to the indirect reference table associated with the 125 * current stack frame. When the native function returns, the reference will be discarded. 126 * 127 * We need to allow the same reference to be added multiple times, and cope with nullptr. 128 * 129 * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and 130 * it's best if we don't grab a mutex. 131 */ 132 template<typename T> AddLocalReference(mirror::Object * obj)133 T AddLocalReference(mirror::Object* obj) const SHARED_REQUIRES(Locks::mutator_lock_) { 134 Locks::mutator_lock_->AssertSharedHeld(Self()); 135 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 136 DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal()); 137 return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj); 138 } 139 140 template<typename T> Decode(jobject obj)141 T Decode(jobject obj) const 142 SHARED_REQUIRES(Locks::mutator_lock_) { 143 Locks::mutator_lock_->AssertSharedHeld(Self()); 144 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 145 return down_cast<T>(Self()->DecodeJObject(obj)); 146 } 147 DecodeField(jfieldID fid)148 ArtField* DecodeField(jfieldID fid) const 149 SHARED_REQUIRES(Locks::mutator_lock_) { 150 Locks::mutator_lock_->AssertSharedHeld(Self()); 151 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 152 return reinterpret_cast<ArtField*>(fid); 153 } 154 EncodeField(ArtField * field)155 jfieldID EncodeField(ArtField* field) const SHARED_REQUIRES(Locks::mutator_lock_) { 156 Locks::mutator_lock_->AssertSharedHeld(Self()); 157 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 158 return reinterpret_cast<jfieldID>(field); 159 } 160 DecodeMethod(jmethodID mid)161 ArtMethod* DecodeMethod(jmethodID mid) const SHARED_REQUIRES(Locks::mutator_lock_) { 162 Locks::mutator_lock_->AssertSharedHeld(Self()); 163 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 164 return reinterpret_cast<ArtMethod*>(mid); 165 } 166 EncodeMethod(ArtMethod * method)167 jmethodID EncodeMethod(ArtMethod* method) const SHARED_REQUIRES(Locks::mutator_lock_) { 168 Locks::mutator_lock_->AssertSharedHeld(Self()); 169 DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. 170 return reinterpret_cast<jmethodID>(method); 171 } 172 IsRunnable()173 bool IsRunnable() const { 174 return self_->GetState() == kRunnable; 175 } 176 177 protected: ScopedObjectAccessAlreadyRunnable(JNIEnv * env)178 explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env) 179 REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE 180 : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) { 181 } 182 ScopedObjectAccessAlreadyRunnable(Thread * self)183 explicit ScopedObjectAccessAlreadyRunnable(Thread* self) 184 REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE 185 : self_(self), env_(down_cast<JNIEnvExt*>(self->GetJniEnv())), 186 vm_(env_ != nullptr ? env_->vm : nullptr) { 187 } 188 189 // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't 190 // change into Runnable or acquire a share on the mutator_lock_. ScopedObjectAccessAlreadyRunnable(JavaVM * vm)191 explicit ScopedObjectAccessAlreadyRunnable(JavaVM* vm) 192 : self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {} 193 194 // Here purely to force inlining. ~ScopedObjectAccessAlreadyRunnable()195 ~ScopedObjectAccessAlreadyRunnable() ALWAYS_INLINE { 196 } 197 198 // Self thread, can be null. 199 Thread* const self_; 200 // The full JNIEnv. 201 JNIEnvExt* const env_; 202 // The full JavaVM. 203 JavaVMExt* const vm_; 204 }; 205 206 // Entry/exit processing for transitions from Native to Runnable (ie within JNI functions). 207 // 208 // This class performs the necessary thread state switching to and from Runnable and lets us 209 // amortize the cost of working out the current thread. Additionally it lets us check (and repair) 210 // apps that are using a JNIEnv on the wrong thread. The class also decodes and encodes Objects 211 // into jobjects via methods of this class. Performing this here enforces the Runnable thread state 212 // for use of Object, thereby inhibiting the Object being modified by GC whilst native or VM code 213 // is also manipulating the Object. 214 // 215 // The destructor transitions back to the previous thread state, typically Native. In this state 216 // GC and thread suspension may occur. 217 // 218 // For annotalysis the subclass ScopedObjectAccess (below) makes it explicit that a shared of 219 // the mutator_lock_ will be acquired on construction. 220 class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable { 221 public: ScopedObjectAccessUnchecked(JNIEnv * env)222 explicit ScopedObjectAccessUnchecked(JNIEnv* env) 223 REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE 224 : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) { 225 Self()->VerifyStack(); 226 Locks::mutator_lock_->AssertSharedHeld(Self()); 227 } 228 ScopedObjectAccessUnchecked(Thread * self)229 explicit ScopedObjectAccessUnchecked(Thread* self) 230 REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE 231 : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) { 232 Self()->VerifyStack(); 233 Locks::mutator_lock_->AssertSharedHeld(Self()); 234 } 235 236 // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't 237 // change into Runnable or acquire a share on the mutator_lock_. ScopedObjectAccessUnchecked(JavaVM * vm)238 explicit ScopedObjectAccessUnchecked(JavaVM* vm) ALWAYS_INLINE 239 : ScopedObjectAccessAlreadyRunnable(vm), tsc_() {} 240 241 private: 242 // The scoped thread state change makes sure that we are runnable and restores the thread state 243 // in the destructor. 244 const ScopedThreadStateChange tsc_; 245 246 DISALLOW_COPY_AND_ASSIGN(ScopedObjectAccessUnchecked); 247 }; 248 249 // Annotalysis helping variant of the above. 250 class ScopedObjectAccess : public ScopedObjectAccessUnchecked { 251 public: ScopedObjectAccess(JNIEnv * env)252 explicit ScopedObjectAccess(JNIEnv* env) 253 REQUIRES(!Locks::thread_suspend_count_lock_) 254 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE 255 : ScopedObjectAccessUnchecked(env) { 256 } 257 ScopedObjectAccess(Thread * self)258 explicit ScopedObjectAccess(Thread* self) 259 REQUIRES(!Locks::thread_suspend_count_lock_) 260 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE 261 : ScopedObjectAccessUnchecked(self) { 262 } 263 UNLOCK_FUNCTION(Locks::mutator_lock_)264 ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE { 265 // Base class will release share of lock. Invoked after this destructor. 266 } 267 268 private: 269 // TODO: remove this constructor. It is used by check JNI's ScopedCheck to make it believe that 270 // routines operating with just a VM are sound, they are not, but when you have just a VM 271 // you cannot call the unsound routines. ScopedObjectAccess(JavaVM * vm)272 explicit ScopedObjectAccess(JavaVM* vm) 273 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) 274 : ScopedObjectAccessUnchecked(vm) {} 275 276 friend class ScopedCheck; 277 DISALLOW_COPY_AND_ASSIGN(ScopedObjectAccess); 278 }; 279 280 // Annotalysis helper for going to a suspended state from runnable. 281 class ScopedThreadSuspension : public ValueObject { 282 public: ScopedThreadSuspension(Thread * self,ThreadState suspended_state)283 explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state) 284 REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_) 285 UNLOCK_FUNCTION(Locks::mutator_lock_) 286 ALWAYS_INLINE 287 : self_(self), suspended_state_(suspended_state) { 288 DCHECK(self_ != nullptr); 289 self_->TransitionFromRunnableToSuspended(suspended_state); 290 } 291 SHARED_LOCK_FUNCTION(Locks::mutator_lock_)292 ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE { 293 DCHECK_EQ(self_->GetState(), suspended_state_); 294 self_->TransitionFromSuspendedToRunnable(); 295 } 296 297 private: 298 Thread* const self_; 299 const ThreadState suspended_state_; 300 DISALLOW_COPY_AND_ASSIGN(ScopedThreadSuspension); 301 }; 302 303 304 } // namespace art 305 306 #endif // ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 307