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 "nativehelper/scoped_local_ref.h"
38 #include "runtime.h"
39 #include "runtime_callbacks.h"
40 #include "scoped_thread_state_change-inl.h"
41 #include "thread-current-inl.h"
42 #include "thread_list.h"
43 #include "ti_thread.h"
44 
45 namespace openjdkjvmti {
46 
47 jvmtiPhase PhaseUtil::current_phase_ = static_cast<jvmtiPhase>(0);
48 
49 struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback {
GetJniEnvopenjdkjvmti::PhaseUtil::PhaseCallback50   inline static JNIEnv* GetJniEnv() {
51     return reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv());
52   }
53 
GetCurrentJThreadopenjdkjvmti::PhaseUtil::PhaseCallback54   inline static jthread GetCurrentJThread() {
55     art::ScopedObjectAccess soa(art::Thread::Current());
56     return soa.AddLocalReference<jthread>(soa.Self()->GetPeer());
57   }
58 
NextRuntimePhaseopenjdkjvmti::PhaseUtil::PhaseCallback59   void NextRuntimePhase(RuntimePhase phase) REQUIRES_SHARED(art::Locks::mutator_lock_) override {
60     art::Thread* self = art::Thread::Current();
61     switch (phase) {
62       case RuntimePhase::kInitialAgents:
63         PhaseUtil::current_phase_ = JVMTI_PHASE_PRIMORDIAL;
64         break;
65       case RuntimePhase::kStart:
66         {
67           PhaseUtil::current_phase_ = JVMTI_PHASE_START;
68           event_handler->DispatchEvent<ArtJvmtiEvent::kVmStart>(self, GetJniEnv());
69         }
70         break;
71       case RuntimePhase::kInit:
72         {
73           ThreadUtil::CacheData();
74           PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
75           {
76             ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread());
77             event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(self, GetJniEnv(), thread.get());
78           }
79           // We need to have these events be ordered to match behavior expected by some real-world
80           // agents. The spec does not really require this but compatibility is a useful property to
81           // maintain.
82           ThreadUtil::VMInitEventSent();
83         }
84         break;
85       case RuntimePhase::kDeath:
86         {
87           event_handler->DispatchEvent<ArtJvmtiEvent::kVmDeath>(self, GetJniEnv());
88           PhaseUtil::current_phase_ = JVMTI_PHASE_DEAD;
89         }
90         // TODO: Block events now.
91         break;
92     }
93   }
94 
95   EventHandler* event_handler = nullptr;
96 };
97 
98 PhaseUtil::PhaseCallback gPhaseCallback;
99 
GetPhase(jvmtiEnv * env ATTRIBUTE_UNUSED,jvmtiPhase * phase_ptr)100 jvmtiError PhaseUtil::GetPhase(jvmtiEnv* env ATTRIBUTE_UNUSED, jvmtiPhase* phase_ptr) {
101   if (phase_ptr == nullptr) {
102     return ERR(NULL_POINTER);
103   }
104   jvmtiPhase now = PhaseUtil::current_phase_;
105   DCHECK(now == JVMTI_PHASE_ONLOAD ||
106          now == JVMTI_PHASE_PRIMORDIAL ||
107          now == JVMTI_PHASE_START ||
108          now == JVMTI_PHASE_LIVE ||
109          now == JVMTI_PHASE_DEAD);
110   *phase_ptr = now;
111   return ERR(NONE);
112 }
113 
IsLivePhase()114 bool PhaseUtil::IsLivePhase() {
115   jvmtiPhase now = PhaseUtil::current_phase_;
116   DCHECK(now == JVMTI_PHASE_ONLOAD ||
117          now == JVMTI_PHASE_PRIMORDIAL ||
118          now == JVMTI_PHASE_START ||
119          now == JVMTI_PHASE_LIVE ||
120          now == JVMTI_PHASE_DEAD);
121   return now == JVMTI_PHASE_LIVE;
122 }
123 
SetToOnLoad()124 void PhaseUtil::SetToOnLoad() {
125   DCHECK_EQ(0u, static_cast<size_t>(PhaseUtil::current_phase_));
126   PhaseUtil::current_phase_ = JVMTI_PHASE_ONLOAD;
127 }
128 
SetToPrimordial()129 void PhaseUtil::SetToPrimordial() {
130   DCHECK_EQ(static_cast<size_t>(JVMTI_PHASE_ONLOAD), static_cast<size_t>(PhaseUtil::current_phase_));
131   PhaseUtil::current_phase_ = JVMTI_PHASE_ONLOAD;
132 }
133 
SetToLive()134 void PhaseUtil::SetToLive() {
135   DCHECK_EQ(static_cast<size_t>(0), static_cast<size_t>(PhaseUtil::current_phase_));
136   ThreadUtil::CacheData();
137   PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
138 }
139 
Register(EventHandler * handler)140 void PhaseUtil::Register(EventHandler* handler) {
141   gPhaseCallback.event_handler = handler;
142   art::ScopedThreadStateChange stsc(art::Thread::Current(),
143                                     art::ThreadState::kWaitingForDebuggerToAttach);
144   art::ScopedSuspendAll ssa("Add phase callback");
145   art::Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback);
146 }
147 
Unregister()148 void PhaseUtil::Unregister() {
149   art::ScopedThreadStateChange stsc(art::Thread::Current(),
150                                     art::ThreadState::kWaitingForDebuggerToAttach);
151   art::ScopedSuspendAll ssa("Remove phase callback");
152   art::Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gPhaseCallback);
153 }
154 
GetPhaseUnchecked()155 jvmtiPhase PhaseUtil::GetPhaseUnchecked() {
156   return PhaseUtil::current_phase_;
157 }
158 
159 }  // namespace openjdkjvmti
160