1 /*
2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 #include <string.h>
25 #include "jvmti.h"
26 #include "agent_common.h"
27 #include "jni_tools.h"
28 #include "jvmti_tools.h"
29 
30 extern "C" {
31 
32 /* ============================================================================= */
33 
34 /* scaffold objects */
35 static JNIEnv* jni = NULL;
36 static jvmtiEnv *jvmti = NULL;
37 static jlong timeout = 0;
38 
39 /* constant names */
40 #define DEBUGEE_CLASS_NAME      "nsk/jvmti/scenarios/events/EM05/em05t002"
41 #define THREAD_CLASS_NAME       "nsk/jvmti/scenarios/events/EM05/em05t002Thread"
42 #define THREAD_FIELD_NAME       "thread"
43 #define THREAD_FIELD_SIG        "L" THREAD_CLASS_NAME ";"
44 
45 /* constants */
46 #define MAX_NAME_LENGTH         64
47 #define EVENTS_COUNT            2
48 #define METHODS_COUNT           2
49 #define MOMENTS_COUNT           3
50 
51 /* compilation moments */
52 #define COMPILATION_MOMENT_BEFORE       0
53 #define COMPILATION_MOMENT_RUNNING      1
54 #define COMPILATION_MOMENT_AFTER        2
55 
56 /* tested events */
57 static jvmtiEvent eventsList[EVENTS_COUNT] = {
58     JVMTI_EVENT_COMPILED_METHOD_LOAD,
59     JVMTI_EVENT_COMPILED_METHOD_UNLOAD
60 };
61 
62 /* method description structure */
63 typedef struct {
64     char methodName[MAX_NAME_LENGTH];
65     char methodSig[MAX_NAME_LENGTH];
66     jmethodID method;
67     int compiled;
68     int loadEvents[MOMENTS_COUNT];
69     int unloadEvents[MOMENTS_COUNT];
70 } MethodDesc;
71 
72 /* descriptions of tested methods */
73 static MethodDesc methodsDesc[METHODS_COUNT] = {
74     { "javaMethod", "(I)I", NULL, 0, {}, {} },
75     { "nativeMethod", "(I)I", NULL, 0, {}, {} }
76 };
77 
78 /* current compilation moment */
79 static volatile int moment = COMPILATION_MOMENT_BEFORE;
80 
81 /* ============================================================================= */
82 
83 /* testcase(s) */
84 static int prepare();
85 static int generateEvents();
86 static int checkEvents();
87 static int clean();
88 
89 /* ============================================================================= */
90 
91 /** Agent algorithm. */
92 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * agentJNI,void * arg)93 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
94     jni = agentJNI;
95 
96     NSK_DISPLAY0("Wait for debuggee to become ready\n");
97     if (!nsk_jvmti_waitForSync(timeout))
98         return;
99 
100     {
101         NSK_DISPLAY0("Prepare data\n");
102         if (!prepare()) {
103             nsk_jvmti_setFailStatus();
104             return;
105         }
106 
107         NSK_DISPLAY0("Testcase #1: generate events before running thread\n");
108         moment = COMPILATION_MOMENT_BEFORE;
109         NSK_DISPLAY0("Call GenerateEvents() before running methods\n");
110         if (!generateEvents())
111             return;
112         NSK_DISPLAY0("Check if events received\n");
113         if (!checkEvents())
114             return;
115 
116         NSK_DISPLAY0("Testcase #2: run methods to provoke compilation\n");
117         moment = COMPILATION_MOMENT_RUNNING;
118         NSK_DISPLAY0("Provoke methods compilation\n");
119         if (!nsk_jvmti_resumeSync())
120             return;
121         NSK_DISPLAY0("Wait for thread to completed\n");
122         if (!nsk_jvmti_waitForSync(timeout))
123             return;
124         NSK_DISPLAY0("Check if events received\n");
125         if (!checkEvents())
126             return;
127 
128         NSK_DISPLAY0("Testcase #3: generate events before running thread\n");
129         moment = COMPILATION_MOMENT_AFTER;
130         NSK_DISPLAY0("Call GenerateEvents() after running methods\n");
131         if (!generateEvents())
132             return;
133         NSK_DISPLAY0("Check if events received\n");
134         if (!checkEvents())
135             return;
136 
137         NSK_DISPLAY0("Clean data\n");
138         if (!clean()) {
139             nsk_jvmti_setFailStatus();
140             return;
141         }
142     }
143 
144     NSK_DISPLAY0("Let debuggee to finish\n");
145     if (!nsk_jvmti_resumeSync())
146         return;
147 }
148 
149 /* ============================================================================= */
150 
151 /**
152  * Generate tested events (COMPILED_METHOD_LOAD only).
153  */
generateEvents()154 static int generateEvents() {
155     if (!NSK_JVMTI_VERIFY(jvmti->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
156         nsk_jvmti_setFailStatus();
157         return NSK_FALSE;
158     }
159     return NSK_TRUE;
160 }
161 
162 /**
163  * Prepare data.
164  *    - find tested thread
165  *    - get tested methodIDs
166  *    - enable events
167  */
prepare()168 static int prepare() {
169     jclass debugeeClass = NULL;
170     jclass threadClass = NULL;
171     jfieldID threadFieldID = NULL;
172     jthread thread = NULL;
173     int i;
174 
175     for (i = 0; i < METHODS_COUNT; i++) {
176         int j;
177         methodsDesc[i].method = (jmethodID)NULL;
178         methodsDesc[i].compiled = NSK_FALSE;
179         for (j = 0; j < MOMENTS_COUNT; j++) {
180             methodsDesc[i].loadEvents[j] = 0;
181             methodsDesc[i].unloadEvents[j] = 0;
182         }
183     }
184 
185     if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL))
186         return NSK_FALSE;
187 
188     if (!NSK_JNI_VERIFY(jni, (threadFieldID =
189             jni->GetStaticFieldID(debugeeClass, THREAD_FIELD_NAME, THREAD_FIELD_SIG)) != NULL))
190         return NSK_FALSE;
191 
192     if (!NSK_JNI_VERIFY(jni, (thread = (jthread)
193             jni->GetStaticObjectField(debugeeClass, threadFieldID)) != NULL))
194         return NSK_FALSE;
195 
196     if (!NSK_JNI_VERIFY(jni, (threadClass = jni->GetObjectClass(thread)) != NULL))
197         return NSK_FALSE;
198 
199     NSK_DISPLAY0("Find tested methods:\n");
200     for (i = 0; i < METHODS_COUNT; i++) {
201         if (!NSK_JNI_VERIFY(jni, (methodsDesc[i].method =
202                 jni->GetMethodID(threadClass, methodsDesc[i].methodName, methodsDesc[i].methodSig)) != NULL))
203             return NSK_FALSE;
204         NSK_DISPLAY3("    method #%d (%s): 0x%p\n",
205                                 i, methodsDesc[i].methodName, (void*)methodsDesc[i].method);
206     }
207 
208     NSK_DISPLAY0("Enable events\n");
209     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
210         return NSK_FALSE;
211 
212     return NSK_TRUE;
213 }
214 
215 /**
216  * Testcase: check tested events.
217  *   - check if expected events received for each method
218  *
219  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
220  */
checkEvents()221 static int checkEvents() {
222     int i;
223 
224     for (i = 0; i < METHODS_COUNT; i++) {
225         NSK_DISPLAY2("  method #%d (%s):\n",
226                                 i, methodsDesc[i].methodName);
227         NSK_DISPLAY2("    COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
228                                 methodsDesc[i].loadEvents[moment],
229                                 methodsDesc[i].unloadEvents[moment]);
230 
231         if (moment == COMPILATION_MOMENT_AFTER) {
232             int loadEventsTotal = methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE]
233                                 + methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING];
234             int unloadEventsTotal = methodsDesc[i].unloadEvents[COMPILATION_MOMENT_BEFORE]
235                                   + methodsDesc[i].unloadEvents[COMPILATION_MOMENT_RUNNING];
236 
237             /* complain if no COMPILED_METHOD_LOAD events finally generated for compiled events */
238             if (methodsDesc[i].compiled) {
239                 if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
240                     NSK_COMPLAIN4("No COMPILED_METHOD_LOAD events finally generated for compiled method: %s\n"
241                               "#   total COMPILED_METHOD_LOAD:   %d\n"
242                               "#   total COMPILED_METHOD_UNLOAD: %d\n"
243                               "#         final GenerateEvents(): %d\n",
244                                 methodsDesc[i].methodName,
245                                 loadEventsTotal,
246                                 unloadEventsTotal,
247                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
248                     nsk_jvmti_setFailStatus();
249                 }
250             }
251 
252             /* complain if too many COMPILED_METHOD_LOAD events finally generated */
253             if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
254                 NSK_COMPLAIN5("Too many COMPILED_METHOD_LOAD events finally generated for method: %s\n"
255                               "#   GenerateEvents() before execution: %d\n"
256                               "#   generated during execution:        %d\n"
257                               "#                    total:            %d\n"
258                               "#   GenerateEvents() after execution:  %d\n",
259                                 methodsDesc[i].methodName,
260                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE],
261                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING],
262                                 loadEventsTotal,
263                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
264                 nsk_jvmti_setFailStatus();
265             }
266 
267             /* warn if too mamy COMPILED_METHOD_UNLOAD events received */
268             if (unloadEventsTotal > loadEventsTotal) {
269                 NSK_DISPLAY1("# WARNING: Too many COMPILED_METHOD_UNLOAD events for method: %s\n",
270                                     methodsDesc[i].methodName);
271                 NSK_DISPLAY2("#   COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
272                                     loadEventsTotal, unloadEventsTotal);
273             }
274         }
275     }
276     return NSK_TRUE;
277 }
278 
279 /**
280  * Clean data.
281  *   - disable events
282  */
clean()283 static int clean() {
284     NSK_DISPLAY0("Disable events\n");
285     if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
286         return NSK_FALSE;
287 
288     return NSK_TRUE;
289 }
290 
291 /* ============================================================================= */
292 
293 /**
294  * COMPILED_METHOD_LOAD callback.
295  *   - turm on flag that method is compiled
296  */
297 JNIEXPORT void JNICALL
callbackCompiledMethodLoad(jvmtiEnv * jvmti,jmethodID method,jint code_size,const void * code_addr,jint map_length,const jvmtiAddrLocationMap * map,const void * compile_info)298 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
299                             jint code_size, const void* code_addr,
300                             jint map_length, const jvmtiAddrLocationMap* map,
301                             const void* compile_info) {
302     int i;
303 
304     /* check if event is for tested method and count it */
305     for (i = 0; i < METHODS_COUNT; i++) {
306         if (methodsDesc[i].method == method) {
307             methodsDesc[i].loadEvents[moment]++;
308             methodsDesc[i].compiled = NSK_TRUE;
309 
310             NSK_DISPLAY3("  COMPILED_METHOD_LOAD for method #%d (%s): %d times\n",
311                                 i, methodsDesc[i].methodName,
312                                 methodsDesc[i].loadEvents[moment]);
313             NSK_DISPLAY1("    methodID:   0x%p\n",
314                                 (void*)methodsDesc[i].method);
315             NSK_DISPLAY1("    code_size:  %d\n",
316                                 (int)code_size);
317             NSK_DISPLAY1("    map_length: %d\n",
318                                 (int)map_length);
319             break;
320         }
321     }
322 }
323 
324 /**
325  * COMPILED_METHOD_UNLOAD callback.
326  *   - turn off flag that method is compiled
327  */
328 JNIEXPORT void JNICALL
callbackCompiledMethodUnload(jvmtiEnv * jvmti,jmethodID method,const void * code_addr)329 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
330                              const void* code_addr) {
331     int i;
332 
333     /* check if event is for tested method and count it */
334     for (i = 0; i < METHODS_COUNT; i++) {
335         if (methodsDesc[i].method == method) {
336             methodsDesc[i].unloadEvents[moment]++;
337             methodsDesc[i].compiled = NSK_FALSE;
338 
339             NSK_DISPLAY3("  COMPILED_METHOD_UNLOAD for method #%d (%s): %d times\n",
340                                 i, methodsDesc[i].methodName,
341                                 methodsDesc[i].loadEvents[moment]);
342             NSK_DISPLAY1("    methodID:   0x%p\n",
343                                 (void*)methodsDesc[i].method);
344             break;
345         }
346     }
347 }
348 
349 /* ============================================================================= */
350 
351 /** Native running method in tested thread. */
352 JNIEXPORT jint JNICALL
Java_nsk_jvmti_scenarios_events_EM05_em05t002Thread_nativeMethod(JNIEnv * jni,jobject obj,jint i)353 Java_nsk_jvmti_scenarios_events_EM05_em05t002Thread_nativeMethod(JNIEnv* jni,
354                                                                     jobject obj, jint i) {
355     jint k = 0;
356     jint j;
357 
358     for (j = 0; j < i; j++) {
359         k += (i - j);
360     }
361     return k;
362 }
363 
364 /* ============================================================================= */
365 
366 /** Agent library initialization. */
367 #ifdef STATIC_BUILD
Agent_OnLoad_em05t002(JavaVM * jvm,char * options,void * reserved)368 JNIEXPORT jint JNICALL Agent_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
369     return Agent_Initialize(jvm, options, reserved);
370 }
Agent_OnAttach_em05t002(JavaVM * jvm,char * options,void * reserved)371 JNIEXPORT jint JNICALL Agent_OnAttach_em05t002(JavaVM *jvm, char *options, void *reserved) {
372     return Agent_Initialize(jvm, options, reserved);
373 }
JNI_OnLoad_em05t002(JavaVM * jvm,char * options,void * reserved)374 JNIEXPORT jint JNI_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
375     return JNI_VERSION_1_8;
376 }
377 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)378 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
379 
380     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
381         return JNI_ERR;
382 
383     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
384 
385     if (!NSK_VERIFY((jvmti =
386             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
387         return JNI_ERR;
388 
389     {
390         jvmtiCapabilities caps;
391         memset(&caps, 0, sizeof(caps));
392         caps.can_generate_compiled_method_load_events = 1;
393         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
394             return JNI_ERR;
395     }
396 
397     {
398         jvmtiEventCallbacks eventCallbacks;
399         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
400         eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
401         eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
402         if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
403             return JNI_ERR;
404     }
405 
406     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
407         return JNI_ERR;
408 
409     return JNI_OK;
410 }
411 
412 /* ============================================================================= */
413 
414 }
415