1/* Copyright (C) 2017 The Android Open Source Project 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This file implements interfaces from the file jvmti.h. This implementation 5 * is licensed under the same terms as the file jvmti.h. The 6 * copyright and license information for the file jvmti.h follows. 7 * 8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10 * 11 * This code is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License version 2 only, as 13 * published by the Free Software Foundation. Oracle designates this 14 * particular file as subject to the "Classpath" exception as provided 15 * by Oracle in the LICENSE file that accompanied this code. 16 * 17 * This code is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 * version 2 for more details (a copy is included in the LICENSE file that 21 * accompanied this code). 22 * 23 * You should have received a copy of the GNU General Public License version 24 * 2 along with this work; if not, write to the Free Software Foundation, 25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26 * 27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28 * or visit www.oracle.com if you need additional information or have any 29 * questions. 30 */ 31 32#include "ti_phase.h" 33 34#include "art_jvmti.h" 35#include "base/macros.h" 36#include "events-inl.h" 37#include "runtime.h" 38#include "runtime_callbacks.h" 39#include "ScopedLocalRef.h" 40#include "scoped_thread_state_change-inl.h" 41#include "thread-inl.h" 42#include "thread_list.h" 43#include "ti_thread.h" 44 45namespace openjdkjvmti { 46 47jvmtiPhase PhaseUtil::current_phase_ = static_cast<jvmtiPhase>(0); 48 49struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback { 50 inline static JNIEnv* GetJniEnv() { 51 return reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv()); 52 } 53 54 inline static jthread GetCurrentJThread() { 55 art::ScopedObjectAccess soa(art::Thread::Current()); 56 return soa.AddLocalReference<jthread>(soa.Self()->GetPeer()); 57 } 58 59 void NextRuntimePhase(RuntimePhase phase) REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE { 60 switch (phase) { 61 case RuntimePhase::kInitialAgents: 62 PhaseUtil::current_phase_ = JVMTI_PHASE_PRIMORDIAL; 63 break; 64 case RuntimePhase::kStart: 65 { 66 art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative); 67 event_handler->DispatchEvent<ArtJvmtiEvent::kVmStart>(nullptr, GetJniEnv()); 68 PhaseUtil::current_phase_ = JVMTI_PHASE_START; 69 } 70 break; 71 case RuntimePhase::kInit: 72 { 73 ThreadUtil::CacheData(); 74 ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread()); 75 art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative); 76 event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(nullptr, GetJniEnv(), thread.get()); 77 PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE; 78 } 79 break; 80 case RuntimePhase::kDeath: 81 { 82 art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative); 83 event_handler->DispatchEvent<ArtJvmtiEvent::kVmDeath>(nullptr, GetJniEnv()); 84 PhaseUtil::current_phase_ = JVMTI_PHASE_DEAD; 85 } 86 // TODO: Block events now. 87 break; 88 } 89 } 90 91 EventHandler* event_handler = nullptr; 92}; 93 94PhaseUtil::PhaseCallback gPhaseCallback; 95 96jvmtiError PhaseUtil::GetPhase(jvmtiEnv* env ATTRIBUTE_UNUSED, jvmtiPhase* phase_ptr) { 97 if (phase_ptr == nullptr) { 98 return ERR(NULL_POINTER); 99 } 100 jvmtiPhase now = PhaseUtil::current_phase_; 101 DCHECK(now == JVMTI_PHASE_ONLOAD || 102 now == JVMTI_PHASE_PRIMORDIAL || 103 now == JVMTI_PHASE_START || 104 now == JVMTI_PHASE_LIVE || 105 now == JVMTI_PHASE_DEAD); 106 *phase_ptr = now; 107 return ERR(NONE); 108} 109 110bool PhaseUtil::IsLivePhase() { 111 jvmtiPhase now = PhaseUtil::current_phase_; 112 DCHECK(now == JVMTI_PHASE_ONLOAD || 113 now == JVMTI_PHASE_PRIMORDIAL || 114 now == JVMTI_PHASE_START || 115 now == JVMTI_PHASE_LIVE || 116 now == JVMTI_PHASE_DEAD); 117 return now == JVMTI_PHASE_LIVE; 118} 119 120void PhaseUtil::SetToOnLoad() { 121 DCHECK_EQ(0u, static_cast<size_t>(PhaseUtil::current_phase_)); 122 PhaseUtil::current_phase_ = JVMTI_PHASE_ONLOAD; 123} 124 125void PhaseUtil::SetToPrimordial() { 126 DCHECK_EQ(static_cast<size_t>(JVMTI_PHASE_ONLOAD), static_cast<size_t>(PhaseUtil::current_phase_)); 127 PhaseUtil::current_phase_ = JVMTI_PHASE_ONLOAD; 128} 129 130void PhaseUtil::SetToLive() { 131 DCHECK_EQ(static_cast<size_t>(0), static_cast<size_t>(PhaseUtil::current_phase_)); 132 ThreadUtil::CacheData(); 133 PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE; 134} 135 136void PhaseUtil::Register(EventHandler* handler) { 137 gPhaseCallback.event_handler = handler; 138 art::ScopedThreadStateChange stsc(art::Thread::Current(), 139 art::ThreadState::kWaitingForDebuggerToAttach); 140 art::ScopedSuspendAll ssa("Add phase callback"); 141 art::Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback); 142} 143 144void PhaseUtil::Unregister() { 145 art::ScopedThreadStateChange stsc(art::Thread::Current(), 146 art::ThreadState::kWaitingForDebuggerToAttach); 147 art::ScopedSuspendAll ssa("Remove phase callback"); 148 art::Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gPhaseCallback); 149} 150 151jvmtiPhase PhaseUtil::GetPhaseUnchecked() { 152 return PhaseUtil::current_phase_; 153} 154 155} // namespace openjdkjvmti 156