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