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