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