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 static jlong timeout = 0;
35
36 #define INFO_NONE 0x00
37 #define INFO_ALL 0xFF
38 #define INFO_OBJREF 0x01
39 #define INFO_STACKREF 0x02
40 #define INFO_HEAPROOT 0x04
41 #define INFO_HEAPOBJ 0x08
42 #define INFO_TAGGED 0x10
43
44 static unsigned int info = INFO_NONE;
45
46 #define DEBUGEE_CLASS_NAME "nsk/jvmti/IterateOverHeap/iterheap001"
47 #define ROOT_OBJECT_CLASS_NAME "nsk/jvmti/IterateOverHeap/iterheap001RootTestedClass"
48 #define ROOT_OBJECT_CLASS_SIG "L" ROOT_OBJECT_CLASS_NAME ";"
49 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/IterateOverHeap/iterheap001TestedClass"
50 #define CHAIN_OBJECT_CLASS_SIG "L" CHAIN_OBJECT_CLASS_NAME ";"
51
52 #define OBJECT_FIELD_NAME "object"
53 #define REACHABLE_CHAIN_FIELD_NAME "reachableChain"
54 #define UNREACHABLE_CHAIN_FIELD_NAME "unreachableChain"
55 #define TAIL_FIELD_NAME "tail"
56
57 #define DEFAULT_CHAIN_LENGTH 4
58
59 typedef struct ObjectDescStruct {
60 jlong tag;
61 jint found;
62 int collected;
63 } ObjectDesc;
64
65 static int chainLength = 0;
66 static int objectsCount = 0;
67
68 static ObjectDesc* objectDescList = NULL;
69
70 static volatile int foundUntagged = 0;
71
72 static int fakeUserData = 0;
73 static int userDataError = 0;
74
75 /* ============================================================================= */
76
77 /** Obtain chain of tested objects and tag them recursively. */
getChainObjects(jvmtiEnv * jvmti,JNIEnv * jni,jobject firstObject,jfieldID firstField,const char firstFieldName[],jfieldID nextField,const char nextFieldName[],int count,ObjectDesc objectDescList[],jlong tag,int reachable)78 static int getChainObjects(jvmtiEnv* jvmti, JNIEnv* jni, jobject firstObject,
79 jfieldID firstField, const char firstFieldName[],
80 jfieldID nextField, const char nextFieldName[],
81 int count, ObjectDesc objectDescList[],
82 jlong tag, int reachable) {
83
84 int success = NSK_TRUE;
85 jobject obj = NULL;
86 jlong objTag = (!reachable ? -tag : (tag % 2 != 0) ? tag : (jlong)0);
87
88 if (count <= 0)
89 return NSK_TRUE;
90
91 count--;
92 tag++;
93
94 if (!NSK_JNI_VERIFY(jni, (obj =
95 jni->GetObjectField(firstObject, firstField)) != NULL)) {
96 nsk_jvmti_setFailStatus();
97 return NSK_FALSE;
98 }
99
100 objectDescList[count].tag = objTag;
101 if (!NSK_JVMTI_VERIFY(
102 jvmti->SetTag(obj, objTag))) {
103 nsk_jvmti_setFailStatus();
104 return NSK_FALSE;
105 }
106 NSK_DISPLAY2(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj);
107
108 if (!getChainObjects(jvmti, jni, obj, nextField, nextFieldName,
109 nextField, nextFieldName,
110 count, objectDescList, tag, reachable)) {
111 return NSK_FALSE;
112 }
113
114 NSK_TRACE(jni->DeleteLocalRef(obj));
115 return success;
116 }
117
118 /** Obtain all tested objects from debugee class and tag them recursively. */
getTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,int * objectsCount,ObjectDesc ** objectDescList)119 static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength,
120 int *objectsCount, ObjectDesc* *objectDescList) {
121 jclass debugeeClass = NULL;
122 jclass rootObjectClass = NULL;
123 jclass chainObjectClass = NULL;
124
125 jfieldID objectField = NULL;
126 jfieldID reachableChainField = NULL;
127 jfieldID unreachableChainField = NULL;
128 jfieldID tailField = NULL;
129
130 jobject rootObject = NULL;
131
132 jlong chainObjectTag = 100;
133
134 *objectsCount = 2 * chainLength;
135
136 NSK_DISPLAY1("Allocate memory for objects list: %d objects\n", *objectsCount);
137 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) {
138 nsk_jvmti_setFailStatus();
139 return NSK_FALSE;
140 }
141 NSK_DISPLAY1(" ... allocated array: 0x%p\n", (void*)objectDescList);
142
143 {
144 int k;
145 for (k = 0; k < *objectsCount; k++) {
146 (*objectDescList)[k].tag = 0;
147 (*objectDescList)[k].found = 0;
148 (*objectDescList)[k].collected = 0;
149 }
150 }
151
152 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_CLASS_NAME);
153 if (!NSK_JNI_VERIFY(jni, (debugeeClass =
154 jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) {
155 nsk_jvmti_setFailStatus();
156 return NSK_FALSE;
157 }
158 NSK_DISPLAY1(" ... found class: 0x%p\n", (void*)debugeeClass);
159
160 NSK_DISPLAY1("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME);
161 if (!NSK_JNI_VERIFY(jni, (rootObjectClass =
162 jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != NULL)) {
163 nsk_jvmti_setFailStatus();
164 return NSK_FALSE;
165 }
166 NSK_DISPLAY1(" ... found class: 0x%p\n", (void*)rootObjectClass);
167
168 NSK_DISPLAY1("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME);
169 if (!NSK_JNI_VERIFY(jni, (chainObjectClass =
170 jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != NULL)) {
171 nsk_jvmti_setFailStatus();
172 return NSK_FALSE;
173 }
174 NSK_DISPLAY1(" ... found class: 0x%p\n", (void*)chainObjectClass);
175
176 NSK_DISPLAY1("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME);
177 if (!NSK_JNI_VERIFY(jni, (objectField =
178 jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != NULL)) {
179 nsk_jvmti_setFailStatus();
180 return NSK_FALSE;
181 }
182 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)objectField);
183
184 NSK_DISPLAY1("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME);
185 if (!NSK_JNI_VERIFY(jni, (reachableChainField =
186 jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
187 nsk_jvmti_setFailStatus();
188 return NSK_FALSE;
189 }
190 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)reachableChainField);
191
192 NSK_DISPLAY1("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME);
193 if (!NSK_JNI_VERIFY(jni, (unreachableChainField =
194 jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
195 nsk_jvmti_setFailStatus();
196 return NSK_FALSE;
197 }
198 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)unreachableChainField);
199
200 NSK_DISPLAY1("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME);
201 if (!NSK_JNI_VERIFY(jni, (tailField =
202 jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
203 nsk_jvmti_setFailStatus();
204 return NSK_FALSE;
205 }
206 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)tailField);
207
208 NSK_DISPLAY1("Get root object from static field: %s\n", OBJECT_FIELD_NAME);
209 if (!NSK_JNI_VERIFY(jni, (rootObject =
210 jni->GetStaticObjectField(debugeeClass, objectField)) != NULL)) {
211 nsk_jvmti_setFailStatus();
212 return NSK_FALSE;
213 }
214 NSK_DISPLAY1(" ... got object: 0x%p\n", (void*)rootObject);
215
216 NSK_DISPLAY0("Obtain and tag chain objects:\n");
217
218 NSK_DISPLAY1(" reachable objects chain: %d objects\n", chainLength);
219 if (!getChainObjects(jvmti, jni, rootObject,
220 reachableChainField, REACHABLE_CHAIN_FIELD_NAME,
221 tailField, TAIL_FIELD_NAME,
222 chainLength, *objectDescList,
223 chainObjectTag, NSK_TRUE)) {
224 nsk_jvmti_setFailStatus();
225 return NSK_FALSE;
226 }
227
228 NSK_DISPLAY1(" unreachable objects chain: %d objects\n", chainLength);
229 if (!getChainObjects(jvmti, jni, rootObject,
230 unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME,
231 tailField, TAIL_FIELD_NAME,
232 chainLength, *objectDescList + chainLength,
233 chainObjectTag, NSK_FALSE)) {
234 nsk_jvmti_setFailStatus();
235 return NSK_FALSE;
236 }
237
238 return NSK_TRUE;
239 }
240
241 /** Check if tagged objects were iterated. */
checkTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,ObjectDesc objectDescList[])242 static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni,
243 int chainLength, ObjectDesc objectDescList[]) {
244 int success = NSK_TRUE;
245 int expectedUntagged = 0;
246 int i;
247
248 NSK_DISPLAY0("Following tagged/untagged objects were iterated:\n");
249
250 NSK_DISPLAY0(" reachable objects:\n");
251 for (i = 0; i < chainLength; i++) {
252 NSK_DISPLAY2(" tag=%-5ld iterated=%d times\n",
253 (long)objectDescList[i].tag, objectDescList[i].found);
254
255 if (objectDescList[i].found <= 0
256 && objectDescList[i].tag != 0) {
257 NSK_COMPLAIN2("Reachable tagged object was not iterated:\n"
258 "# tag: %ld\n"
259 "# iterated: %d times\n",
260 (long)objectDescList[i].tag,
261 objectDescList[i].found);
262 nsk_jvmti_setFailStatus();
263 }
264
265 if (objectDescList[i].tag == 0) {
266 expectedUntagged++;
267 }
268 }
269
270 NSK_DISPLAY0(" unreachable objects:\n");
271 for (i = 0; i < chainLength; i++) {
272 NSK_DISPLAY3(" tag=%-5ld iterated=%-3d collected=%d times\n",
273 (long)objectDescList[i + chainLength].tag,
274 objectDescList[i + chainLength].found,
275 objectDescList[i + chainLength].collected);
276
277 if (objectDescList[i + chainLength].found <= 0
278 && objectDescList[i + chainLength].collected <= 0) {
279 NSK_COMPLAIN2("Not collected unreachable tagged object was not iterated:\n"
280 "# tag: %ld\n"
281 "# iterated: %d times\n",
282 (long)objectDescList[i + chainLength].tag,
283 objectDescList[i + chainLength].found);
284 nsk_jvmti_setFailStatus();
285 }
286 }
287
288 NSK_DISPLAY0(" untagged objects:\n");
289 NSK_DISPLAY2(" minimum=%-3d iterated=%d objects\n",
290 expectedUntagged, foundUntagged);
291 if (foundUntagged < expectedUntagged) {
292 NSK_COMPLAIN2("Unexpected number of untagged objects were iterated:\n"
293 "# iterated untagged objects: %d\n"
294 "# expected at least: %d\n",
295 foundUntagged, expectedUntagged);
296 nsk_jvmti_setFailStatus();
297 }
298
299 return NSK_TRUE;
300 }
301
302 /** Release references to the tested objects and free allocated memory. */
releaseTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,ObjectDesc * objectDescList)303 static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength,
304 ObjectDesc* objectDescList) {
305 if (objectDescList != NULL) {
306 NSK_DISPLAY1("Deallocate objects list: 0x%p\n", (void*)objectDescList);
307 if (!NSK_JVMTI_VERIFY(
308 jvmti->Deallocate((unsigned char*)objectDescList))) {
309 nsk_jvmti_setFailStatus();
310 }
311 }
312
313 return NSK_TRUE;
314 }
315
316 /* ============================================================================= */
317
318 /** heapRootCallback for heap iterator. */
319 jvmtiIterationControl JNICALL
heapObjectCallback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)320 heapObjectCallback(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data) {
321
322 if (info & INFO_HEAPOBJ) {
323 NSK_DISPLAY3(" heapObjectCallback: class_tag=%-3ld size=%-3ld *tag_ptr=%-5ld\n",
324 (long)class_tag, (long)size,
325 (long)(tag_ptr == NULL ? (jlong)0 : *tag_ptr));
326 } else if ((info & INFO_TAGGED) != 0 &&
327 tag_ptr != NULL && *tag_ptr != 0) {
328 NSK_DISPLAY3(" heapObjectCallback: class_tag=%-3ld size=%-3ld *tag_ptr=%-5ld\n",
329 (long)class_tag, (long)size,
330 (long)*tag_ptr);
331 }
332
333 if (class_tag != 0) {
334 NSK_COMPLAIN3("Unexpected class_tag passed to heapObjectCallback:\n"
335 "# object tag: %ld\n"
336 "# class_tag: %ld\n"
337 "# size: %ld\n",
338 (long)*tag_ptr,
339 (long)class_tag,
340 (long)size);
341 nsk_jvmti_setFailStatus();
342 }
343
344 if (tag_ptr == NULL) {
345 NSK_COMPLAIN3("NULL tag_ptr is passed to heapObjectCallback:\n"
346 "# tag_ptr: 0x%p\n"
347 "# class_tag: %ld\n"
348 "# size: %ld\n",
349 (void*)tag_ptr,
350 (long)class_tag,
351 (long)size);
352 nsk_jvmti_setFailStatus();
353 } else {
354 if (*tag_ptr == 0) {
355 foundUntagged++;
356 } else {
357 int found = 0;
358 int i;
359
360 for (i = 0; i < objectsCount; i++) {
361 if (*tag_ptr == objectDescList[i].tag) {
362 found++;
363 objectDescList[i].found++;
364 break;
365 }
366 }
367
368 if (found <= 0) {
369 NSK_COMPLAIN3("Unknown tagged object passed to heapObjectCallback:\n"
370 "# tag: %ld\n"
371 "# class_tag: %ld\n"
372 "# size: %ld\n",
373 (long)*tag_ptr,
374 (long)class_tag,
375 (long)size);
376 nsk_jvmti_setFailStatus();
377 }
378 }
379 }
380
381 if (user_data != &fakeUserData && !userDataError) {
382 NSK_COMPLAIN2("Unexpected user_data is passed to heapObjectCallback:\n"
383 "# expected: 0x%p\n"
384 "# actual: 0x%p\n",
385 user_data,
386 &fakeUserData);
387 nsk_jvmti_setFailStatus();
388 userDataError++;
389 }
390
391 return JVMTI_ITERATION_CONTINUE;
392 }
393
394 /* ============================================================================= */
395
396 /** Agent algorithm. */
397 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)398 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
399 NSK_DISPLAY0("Wait for tested objects created\n");
400 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
401 return;
402
403 {
404 NSK_DISPLAY0(">>> Obtain and tag tested objects from debugee class\n");
405 {
406 if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength,
407 &objectsCount, &objectDescList)))
408 return;
409 }
410
411 NSK_DISPLAY0(">>> Enable OBJECT_FREE event and let debugee to clean links to unreachable objects\n");
412 {
413 jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
414 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL)))
415 return;
416
417 if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
418 return;
419 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
420 return;
421 }
422
423 NSK_DISPLAY0(">>> Iterate over all object in heap with filter JVMTI_HEAP_OBJECT_EITHER\n");
424 {
425 if (!NSK_JVMTI_VERIFY(
426 jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_EITHER, heapObjectCallback, &fakeUserData))) {
427 nsk_jvmti_setFailStatus();
428 return;
429 }
430 }
431
432 NSK_DISPLAY0(">>> Disable OBJECT_FREE event and check if tagged/untagged objects were iterated:\n");
433 {
434 jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
435 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_DISABLE, 1, &event, NULL)))
436 return;
437
438 if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
439 nsk_jvmti_setFailStatus();
440 }
441 }
442
443 NSK_DISPLAY0(">>> Clean used data\n");
444 {
445 if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList)))
446 return;
447 }
448 }
449
450 NSK_DISPLAY0("Let debugee to finish\n");
451 if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
452 return;
453 }
454
455 /* ============================================================================= */
456
457 JNIEXPORT void JNICALL
callbackObjectFree(jvmtiEnv * jvmti,jlong tag)458 callbackObjectFree(jvmtiEnv* jvmti, jlong tag) {
459 int i;
460
461 if (info & INFO_HEAPOBJ) {
462 NSK_DISPLAY1(" <ObjectFree>: tag=%-5ld\n", tag);
463 }
464
465 if (tag != 0) {
466 for (i = 0; i < objectsCount; i++) {
467 if (tag == objectDescList[i].tag) {
468 objectDescList[i].collected++;
469 break;
470 }
471 }
472 }
473 }
474
475 /* ============================================================================= */
476
477 /** Agent library initialization. */
478 #ifdef STATIC_BUILD
Agent_OnLoad_iterheap001(JavaVM * jvm,char * options,void * reserved)479 JNIEXPORT jint JNICALL Agent_OnLoad_iterheap001(JavaVM *jvm, char *options, void *reserved) {
480 return Agent_Initialize(jvm, options, reserved);
481 }
Agent_OnAttach_iterheap001(JavaVM * jvm,char * options,void * reserved)482 JNIEXPORT jint JNICALL Agent_OnAttach_iterheap001(JavaVM *jvm, char *options, void *reserved) {
483 return Agent_Initialize(jvm, options, reserved);
484 }
JNI_OnLoad_iterheap001(JavaVM * jvm,char * options,void * reserved)485 JNIEXPORT jint JNI_OnLoad_iterheap001(JavaVM *jvm, char *options, void *reserved) {
486 return JNI_VERSION_1_8;
487 }
488 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)489 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
490 jvmtiEnv* jvmti = NULL;
491
492 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
493 return JNI_ERR;
494
495 timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
496
497 {
498 const char* infoOpt = nsk_jvmti_findOptionValue("info");
499 if (infoOpt != NULL) {
500 if (strcmp(infoOpt, "none") == 0)
501 info = INFO_NONE;
502 else if (strcmp(infoOpt, "all") == 0)
503 info = INFO_ALL;
504 else if (strcmp(infoOpt, "objref") == 0)
505 info = INFO_OBJREF;
506 else if (strcmp(infoOpt, "stackref") == 0)
507 info = INFO_STACKREF;
508 else if (strcmp(infoOpt, "heaproot") == 0)
509 info = INFO_HEAPROOT;
510 else if (strcmp(infoOpt, "heapobj") == 0)
511 info = INFO_HEAPOBJ;
512 else if (strcmp(infoOpt, "tagged") == 0)
513 info = INFO_TAGGED;
514 else {
515 NSK_COMPLAIN1("Unknown option value: info=%s\n", infoOpt);
516 return JNI_ERR;
517 }
518 }
519 }
520
521 chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH);
522 if (!NSK_VERIFY(chainLength > 0))
523 return JNI_ERR;
524
525 if (!NSK_VERIFY((jvmti =
526 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
527 return JNI_ERR;
528
529 {
530 jvmtiCapabilities caps;
531
532 memset(&caps, 0, sizeof(caps));
533 caps.can_tag_objects = 1;
534 caps.can_generate_object_free_events = 1;
535 if (!NSK_JVMTI_VERIFY(
536 jvmti->AddCapabilities(&caps))) {
537 return JNI_ERR;
538 }
539 }
540
541 {
542 jvmtiEventCallbacks eventCallbacks;
543 memset(&eventCallbacks, 0, sizeof(eventCallbacks));
544 eventCallbacks.ObjectFree = callbackObjectFree;
545 if (!NSK_JVMTI_VERIFY(
546 jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
547 return JNI_ERR;
548 }
549
550 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
551 return JNI_ERR;
552
553 return JNI_OK;
554 }
555
556 /* ============================================================================= */
557
558 }
559