1+ /* ******************************************************************************
2+ * Copyright (c) 2021, 2021 IBM Corp. and others
3+ *
4+ * This program and the accompanying materials are made available under
5+ * the terms of the Eclipse Public License 2.0 which accompanies this
6+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+ * or the Apache License, Version 2.0 which accompanies this distribution and
8+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
9+ *
10+ * This Source Code may also be made available under the following
11+ * Secondary Licenses when the conditions for such availability set
12+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+ * General Public License, version 2 with the GNU Classpath
14+ * Exception [1] and GNU General Public License, version 2 with the
15+ * OpenJDK Assembly Exception [2].
16+ *
17+ * [1] https://www.gnu.org/software/classpath/license.html
18+ * [2] http://openjdk.java.net/legal/assembly-exception.html
19+ *
20+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+ *******************************************************************************/
22+
23+ #include " control/DebugAgent.hpp"
24+
25+ #include " codegen/CodeGenerator.hpp"
26+ #include " control/MethodToBeCompiled.hpp"
27+ #include " control/CompilationRuntime.hpp"
28+ #include " control/CompilationThread.hpp"
29+ #include " env/ut_j9jit.h"
30+ #include " env/VMAccessCriticalSection.hpp"
31+ #include " env/VMJ9.h"
32+ #include " ilgen/J9ByteCodeIlGenerator.hpp"
33+ #include " jithash.h"
34+ #include " nls/j9dmpnls.h"
35+ #include < queue>
36+ #include < set>
37+
38+ BOOLEAN
39+ debugAgentStart (J9VMThread* vmThread)
40+ {
41+ PORT_ACCESS_FROM_VMC (vmThread);
42+
43+ J9JITConfig *jitConfig = vmThread->javaVM ->jitConfig ;
44+ if (NULL == jitConfig)
45+ {
46+ fprintf (stderr, " Could not locate J9JITConfig\n " );
47+ return false ;
48+ }
49+
50+ TR::CompilationInfo *compInfo = TR::CompilationInfo::get (jitConfig);
51+ if (NULL == compInfo)
52+ {
53+ fprintf (stderr, " Could not locate TR::CompilationInfo\n " );
54+ return false ;
55+ }
56+
57+ TR_J9VMBase *frontendOfThread = TR_J9VMBase::get (jitConfig, vmThread);
58+ if (NULL == frontendOfThread)
59+ {
60+ fprintf (stderr, " Could not locate TR_J9VMBase\n " );
61+ return false ;
62+ }
63+
64+ // To avoid a deadlock, release compilation monitor until we are no longer holding it
65+ while (compInfo->getCompilationMonitor ()->owned_by_self ())
66+ {
67+ compInfo->releaseCompMonitor (vmThread);
68+ }
69+
70+ // Release other monitors as well. In particular CHTable and classUnloadMonitor must not be held.
71+ while (TR::MonitorTable::get ()->getClassTableMutex ()->owned_by_self ())
72+ {
73+ frontendOfThread->releaseClassTableMutex (false );
74+ }
75+
76+ TR::CompilationInfoPerThread *threadCompInfo = compInfo->getCompInfoForThread (vmThread);
77+ if (NULL != threadCompInfo)
78+ {
79+ TR_MethodToBeCompiled *methodBeingCompiled = threadCompInfo->getMethodBeingCompiled ();
80+
81+ // If we are currently compiling a method, wake everyone waiting for it to compile
82+ if (NULL != methodBeingCompiled && NULL != methodBeingCompiled->getMonitor ())
83+ {
84+ methodBeingCompiled->getMonitor ()->enter ();
85+ methodBeingCompiled->getMonitor ()->notifyAll ();
86+ methodBeingCompiled->getMonitor ()->exit ();
87+
88+ fprintf (stderr, " Notified threads waiting\n " );
89+ }
90+ }
91+
92+ compInfo->getPersistentInfo ()->setDisableFurtherCompilation (true );
93+
94+ TR::CompilationInfoPerThread *recompilationThreadInfo = compInfo->getCompilationInfoForDiagnosticThread ();
95+ if (NULL == recompilationThreadInfo)
96+ {
97+ j9nls_printf (PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, " JIT" , " Could not locate the diagnostic thread info" );
98+ return OMR_ERROR_INTERNAL;
99+ }
100+
101+ auto *recompilationThread = recompilationThreadInfo->getCompilationThread ();
102+ if (NULL == recompilationThread)
103+ {
104+ j9nls_printf (PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, " JIT" , " Could not locate the diagnostic thread" );
105+ return OMR_ERROR_INTERNAL;
106+ }
107+
108+ compInfo->acquireCompMonitor (vmThread);
109+ compInfo->purgeMethodQueue (compilationFailure);
110+ compInfo->releaseCompMonitor (vmThread);
111+
112+ recompilationThreadInfo->resumeCompilationThread ();
113+
114+ return true ;
115+ }
116+
117+ BOOLEAN
118+ debugAgentGetAllJitMethods (J9VMThread* vmThread, jobject jitMethodSet)
119+ {
120+ JNIEnv *env = (JNIEnv*)vmThread;
121+
122+ jclass java_lang_Long = env->FindClass (" java/lang/Long" );
123+ jmethodID java_lang_Long_init = env->GetMethodID (java_lang_Long, " <init>" , " (J)V" );
124+ jmethodID java_lang_Long_longValue = env->GetMethodID (java_lang_Long, " longValue" , " ()J" );
125+
126+ jclass java_util_HashSet = env->FindClass (" java/util/HashSet" );
127+ jmethodID java_util_HashSet_init = env->GetMethodID (java_util_HashSet, " <init>" , " ()V" );
128+ jmethodID java_util_HashSet_add = env->GetMethodID (java_util_HashSet, " add" , " (Ljava/lang/Object;)Z" );
129+ jmethodID java_util_HashSet_size = env->GetMethodID (java_util_HashSet, " size" , " ()I" );
130+
131+ jclass java_util_LinkedList = env->FindClass (" java/util/LinkedList" );
132+ jmethodID java_util_LinkedList_init = env->GetMethodID (java_util_LinkedList, " <init>" , " ()V" );
133+ jmethodID java_util_LinkedList_add = env->GetMethodID (java_util_LinkedList, " add" , " (Ljava/lang/Object;)Z" );
134+ jmethodID java_util_LinkedList_isEmpty = env->GetMethodID (java_util_LinkedList, " isEmpty" , " ()Z" );
135+ jmethodID java_util_LinkedList_remove = env->GetMethodID (java_util_LinkedList, " remove" , " ()Ljava/lang/Object;" );
136+
137+ jobject jitAVLQueue = env->NewObject (java_util_LinkedList, java_util_LinkedList_init);
138+
139+ jobject rootNode = env->NewObject (java_lang_Long, java_lang_Long_init, (jlong)jitConfig->translationArtifacts ->rootNode );
140+ env->CallBooleanMethod (jitAVLQueue, java_util_LinkedList_add, rootNode);
141+ env->DeleteLocalRef (rootNode);
142+
143+ jboolean jitAVLQueueIsEmpty = env->CallBooleanMethod (jitAVLQueue, java_util_LinkedList_isEmpty);
144+ while (jitAVLQueueIsEmpty != JNI_TRUE)
145+ {
146+ jobject nodeObject = env->CallObjectMethod (jitAVLQueue, java_util_LinkedList_remove);
147+ J9AVLTreeNode *node = (J9AVLTreeNode *)env->CallLongMethod (nodeObject, java_lang_Long_longValue);
148+ env->DeleteLocalRef (nodeObject);
149+
150+ if (NULL != node)
151+ {
152+ jobject leftChild = env->NewObject (java_lang_Long, java_lang_Long_init, (jlong)J9AVLTREENODE_LEFTCHILD (node));
153+ jobject rightChild = env->NewObject (java_lang_Long, java_lang_Long_init, (jlong)J9AVLTREENODE_RIGHTCHILD (node));
154+ env->CallBooleanMethod (jitAVLQueue, java_util_LinkedList_add, leftChild);
155+ env->CallBooleanMethod (jitAVLQueue, java_util_LinkedList_add, rightChild);
156+
157+
158+ J9JITHashTableWalkState state;
159+ J9JITExceptionTable* metadata = hash_jit_start_do (&state, reinterpret_cast <J9JITHashTable*>(node));
160+ while (NULL != metadata)
161+ {
162+ jobject jitMethod = env->NewObject (java_lang_Long, java_lang_Long_init, (jlong)metadata);
163+ env->CallBooleanMethod (jitMethodSet, java_util_HashSet_add, jitMethod);
164+ env->DeleteLocalRef (jitMethod);
165+
166+ metadata = hash_jit_next_do (&state);
167+ }
168+
169+ env->DeleteLocalRef (leftChild);
170+ env->DeleteLocalRef (rightChild);
171+ }
172+
173+ jitAVLQueueIsEmpty = env->CallBooleanMethod (jitAVLQueue, java_util_LinkedList_isEmpty);
174+ }
175+
176+ env->DeleteLocalRef (java_lang_Long);
177+ env->DeleteLocalRef (java_util_HashSet);
178+ env->DeleteLocalRef (java_util_LinkedList);
179+ env->DeleteLocalRef (jitAVLQueue);
180+
181+ return true ;
182+ }
183+
184+ BOOLEAN
185+ debugAgentRevertToInterpreter (J9VMThread* vmThread, J9JITExceptionTable *jitMethod)
186+ {
187+ J9JITConfig *jitConfig = vmThread->javaVM ->jitConfig ;
188+ if (NULL == jitConfig)
189+ {
190+ fprintf (stderr, " Could not locate J9JITConfig\n " );
191+ return false ;
192+ }
193+
194+ TR::CompilationInfo *compInfo = TR::CompilationInfo::get (jitConfig);
195+ if (NULL == compInfo)
196+ {
197+ fprintf (stderr, " Could not locate TR::CompilationInfo\n " );
198+ return false ;
199+ }
200+
201+ TR_J9VMBase *frontendOfThread = TR_J9VMBase::get (jitConfig, vmThread);
202+ if (NULL == frontendOfThread)
203+ {
204+ fprintf (stderr, " Could not locate TR_J9VMBase\n " );
205+ return false ;
206+ }
207+
208+ TR_PersistentJittedBodyInfo *bodyInfo = reinterpret_cast <TR_PersistentJittedBodyInfo *>(jitMethod->bodyInfo );
209+ if (NULL == bodyInfo)
210+ {
211+ fprintf (stderr, " Could not locate persistent body info for JIT method %p\n " , jitMethod);
212+ return false ;
213+ }
214+
215+ PORT_ACCESS_FROM_VMC (vmThread);
216+ J9Class *clazz = J9_CLASS_FROM_METHOD (jitMethod->ramMethod );
217+ J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD (jitMethod->ramMethod );
218+ J9UTF8 *methName = J9ROMMETHOD_NAME (romMethod);
219+ J9UTF8 *methSig = J9ROMMETHOD_SIGNATURE (romMethod);
220+ J9UTF8 *className = J9ROMCLASS_CLASSNAME (clazz->romClass );
221+
222+ void *pc = compInfo->getPCIfCompiled (jitMethod->ramMethod );
223+ fprintf (stderr, " Invalidating PC = %p %.*s.%.*s%.*s\n " , pc,
224+ (UDATA)J9UTF8_LENGTH (className), J9UTF8_DATA (className),
225+ (UDATA)J9UTF8_LENGTH (methName), J9UTF8_DATA (methName),
226+ (UDATA)J9UTF8_LENGTH (methSig), J9UTF8_DATA (methSig));
227+
228+ TR::Recompilation::methodCannotBeRecompiled (pc, frontendOfThread);
229+
230+ return true ;
231+ }
232+
233+ extern J9_CFUNC BOOLEAN
234+ debugAgentRecompile (J9VMThread* vmThread, J9JITExceptionTable *jitMethod, IDATA lastOptIndex, IDATA lastOptSubIndex, BOOLEAN enableTracing)
235+ {
236+ J9JITConfig *jitConfig = vmThread->javaVM ->jitConfig ;
237+ if (NULL == jitConfig)
238+ {
239+ fprintf (stderr, " Could not locate J9JITConfig\n " );
240+ return false ;
241+ }
242+
243+ TR::CompilationInfo *compInfo = TR::CompilationInfo::get (jitConfig);
244+ if (NULL == compInfo)
245+ {
246+ fprintf (stderr, " Could not locate TR::CompilationInfo\n " );
247+ return false ;
248+ }
249+
250+ TR_J9VMBase *frontendOfThread = TR_J9VMBase::get (jitConfig, vmThread);
251+ if (NULL == frontendOfThread)
252+ {
253+ fprintf (stderr, " Could not locate TR_J9VMBase\n " );
254+ return false ;
255+ }
256+
257+ TR_PersistentJittedBodyInfo *bodyInfo = reinterpret_cast <TR_PersistentJittedBodyInfo *>(jitMethod->bodyInfo );
258+ if (NULL == bodyInfo)
259+ {
260+ fprintf (stderr, " Could not locate persistent body info for JIT method %p\n " , jitMethod);
261+ return false ;
262+ }
263+
264+ PORT_ACCESS_FROM_VMC (vmThread);
265+ J9Class *clazz = J9_CLASS_FROM_METHOD (jitMethod->ramMethod );
266+ J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD (jitMethod->ramMethod );
267+ J9UTF8 *methName = J9ROMMETHOD_NAME (romMethod);
268+ J9UTF8 *methSig = J9ROMMETHOD_SIGNATURE (romMethod);
269+ J9UTF8 *className = J9ROMCLASS_CLASSNAME (clazz->romClass );
270+
271+ void *pc = compInfo->getPCIfCompiled (jitMethod->ramMethod );
272+ fprintf (stderr, " Recompiling PC = %p lastOptIndex = %d lastOptSubIndex = %d %.*s.%.*s%.*s\n " , pc, lastOptIndex, lastOptSubIndex,
273+ (UDATA)J9UTF8_LENGTH (className), J9UTF8_DATA (className),
274+ (UDATA)J9UTF8_LENGTH (methName), J9UTF8_DATA (methName),
275+ (UDATA)J9UTF8_LENGTH (methSig), J9UTF8_DATA (methSig));
276+
277+ // The request to use a trace log gets passed to the compilation via the optimization plan. The options object
278+ // created before the compile is issued will use the trace log we provide to initialize IL tracing.
279+ TR_OptimizationPlan *plan = TR_OptimizationPlan::alloc (bodyInfo->getHotness ());
280+ if (NULL == plan)
281+ {
282+ j9nls_printf (PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_OPTIMIZATION_PLAN);
283+ return false ;
284+ }
285+
286+ plan->setInsertInstrumentation (bodyInfo->getIsProfilingBody ());
287+ // plan->setLogCompilation(jitdumpFile);
288+
289+ TR::Options::getCmdLineOptions ()->setLastOptIndex (lastOptIndex);
290+ TR::Options::getCmdLineOptions ()->setLastOptSubIndex (lastOptSubIndex);
291+
292+ // This API is meant to be called from within JNI so we must acquire VM access here before queuing the compilation
293+ // beacuse we will attempt to release VM access right before a synchronous compilation
294+ vmThread->javaVM ->internalVMFunctions ->internalAcquireVMAccess (vmThread);
295+
296+ J9::JitDumpMethodDetails details (jitMethod->ramMethod , NULL , bodyInfo->getIsAotedBody ());
297+ auto rc = compilationOK;
298+ auto queued = false ;
299+ compInfo->compileMethod (vmThread, details, pc, TR_no, &rc, &queued, plan);
300+
301+ vmThread->javaVM ->internalVMFunctions ->internalReleaseVMAccess (vmThread);
302+
303+ return true ;
304+ }
305+
306+ BOOLEAN
307+ debugAgentEnd (J9VMThread* vmThread)
308+ {
309+ J9JITConfig *jitConfig = vmThread->javaVM ->jitConfig ;
310+ if (NULL == jitConfig)
311+ {
312+ fprintf (stderr, " Could not locate J9JITConfig\n " );
313+ return false ;
314+ }
315+
316+ TR::CompilationInfo *compInfo = TR::CompilationInfo::get (jitConfig);
317+ if (NULL == compInfo)
318+ {
319+ fprintf (stderr, " Could not locate TR::CompilationInfo\n " );
320+ return false ;
321+ }
322+
323+ compInfo->getPersistentInfo ()->setDisableFurtherCompilation (false );
324+
325+ // TODO: Need to suspend diagnostic thread here
326+
327+ return true ;
328+ }
0 commit comments