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