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/iterheap002"
47 #define ROOT_OBJECT_CLASS_NAME "nsk/jvmti/IterateOverHeap/iterheap002RootTestedClass"
48 #define ROOT_OBJECT_CLASS_SIG "L" ROOT_OBJECT_CLASS_NAME ";"
49 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/IterateOverHeap/iterheap002TestedClass"
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 > 0) {
292 NSK_COMPLAIN2("A number of untagged objects were iterated:\n"
293 "# iterated untagged objects: %d\n"
294 "# untagged objects 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 NSK_COMPLAIN3("Untagged object passed to heapObjectCallback:\n"
357 "# tag: %ld\n"
358 "# class_tag: %ld\n"
359 "# size: %ld\n",
360 (long)*tag_ptr,
361 (long)class_tag,
362 (long)size);
363 nsk_jvmti_setFailStatus();
364 } else {
365 int found = 0;
366 int i;
367
368 for (i = 0; i < objectsCount; i++) {
369 if (*tag_ptr == objectDescList[i].tag) {
370 found++;
371 objectDescList[i].found++;
372 break;
373 }
374 }
375
376 if (found <= 0) {
377 NSK_COMPLAIN3("Unknown tagged object passed to heapObjectCallback:\n"
378 "# tag: %ld\n"
379 "# class_tag: %ld\n"
380 "# size: %ld\n",
381 (long)*tag_ptr,
382 (long)class_tag,
383 (long)size);
384 nsk_jvmti_setFailStatus();
385 }
386 }
387 }
388
389 if (user_data != &fakeUserData && !userDataError) {
390 NSK_COMPLAIN2("Unexpected user_data is passed to heapObjectCallback:\n"
391 "# expected: 0x%p\n"
392 "# actual: 0x%p\n",
393 user_data,
394 &fakeUserData);
395 nsk_jvmti_setFailStatus();
396 userDataError++;
397 }
398
399 return JVMTI_ITERATION_CONTINUE;
400 }
401
402 /* ============================================================================= */
403
404 /** Agent algorithm. */
405 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)406 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
407 NSK_DISPLAY0("Wait for tested objects created\n");
408 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
409 return;
410
411 {
412 NSK_DISPLAY0(">>> Obtain and tag tested objects from debugee class\n");
413 {
414 if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength,
415 &objectsCount, &objectDescList)))
416 return;
417 }
418
419 NSK_DISPLAY0(">>> Enable OBJECT_FREE event and let debugee to clean links to unreachable objects\n");
420 {
421 jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
422 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL)))
423 return;
424
425 if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
426 return;
427 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
428 return;
429 }
430
431 NSK_DISPLAY0(">>> Iterate over all object in heap with filter JVMTI_HEAP_OBJECT_TAGGED\n");
432 {
433 if (!NSK_JVMTI_VERIFY(
434 jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_TAGGED, heapObjectCallback, &fakeUserData))) {
435 nsk_jvmti_setFailStatus();
436 return;
437 }
438 }
439
440 NSK_DISPLAY0(">>> Disable OBJECT_FREE event and check if tagged objects were iterated:\n");
441 {
442 jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
443 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_DISABLE, 1, &event, NULL)))
444 return;
445
446 if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
447 nsk_jvmti_setFailStatus();
448 }
449 }
450
451 NSK_DISPLAY0(">>> Clean used data\n");
452 {
453 if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList)))
454 return;
455 }
456 }
457
458 NSK_DISPLAY0("Let debugee to finish\n");
459 if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
460 return;
461 }
462
463 /* ============================================================================= */
464
465 JNIEXPORT void JNICALL
callbackObjectFree(jvmtiEnv * jvmti,jlong tag)466 callbackObjectFree(jvmtiEnv* jvmti, jlong tag) {
467 int i;
468
469 if (info & INFO_HEAPOBJ) {
470 NSK_DISPLAY1(" <ObjectFree>: tag=%-5ld\n", tag);
471 }
472
473 if (tag != 0) {
474 for (i = 0; i < objectsCount; i++) {
475 if (tag == objectDescList[i].tag) {
476 objectDescList[i].collected++;
477 break;
478 }
479 }
480 }
481 }
482
483 /* ============================================================================= */
484
485 /** Agent library initialization. */
486 #ifdef STATIC_BUILD
Agent_OnLoad_iterheap002(JavaVM * jvm,char * options,void * reserved)487 JNIEXPORT jint JNICALL Agent_OnLoad_iterheap002(JavaVM *jvm, char *options, void *reserved) {
488 return Agent_Initialize(jvm, options, reserved);
489 }
Agent_OnAttach_iterheap002(JavaVM * jvm,char * options,void * reserved)490 JNIEXPORT jint JNICALL Agent_OnAttach_iterheap002(JavaVM *jvm, char *options, void *reserved) {
491 return Agent_Initialize(jvm, options, reserved);
492 }
JNI_OnLoad_iterheap002(JavaVM * jvm,char * options,void * reserved)493 JNIEXPORT jint JNI_OnLoad_iterheap002(JavaVM *jvm, char *options, void *reserved) {
494 return JNI_VERSION_1_8;
495 }
496 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)497 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
498 jvmtiEnv* jvmti = NULL;
499
500 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
501 return JNI_ERR;
502
503 timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
504
505 {
506 const char* infoOpt = nsk_jvmti_findOptionValue("info");
507 if (infoOpt != NULL) {
508 if (strcmp(infoOpt, "none") == 0)
509 info = INFO_NONE;
510 else if (strcmp(infoOpt, "all") == 0)
511 info = INFO_ALL;
512 else if (strcmp(infoOpt, "objref") == 0)
513 info = INFO_OBJREF;
514 else if (strcmp(infoOpt, "stackref") == 0)
515 info = INFO_STACKREF;
516 else if (strcmp(infoOpt, "heaproot") == 0)
517 info = INFO_HEAPROOT;
518 else if (strcmp(infoOpt, "heapobj") == 0)
519 info = INFO_HEAPOBJ;
520 else if (strcmp(infoOpt, "tagged") == 0)
521 info = INFO_TAGGED;
522 else {
523 NSK_COMPLAIN1("Unknown option value: info=%s\n", infoOpt);
524 return JNI_ERR;
525 }
526 }
527 }
528
529 chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH);
530 if (!NSK_VERIFY(chainLength > 0))
531 return JNI_ERR;
532
533 if (!NSK_VERIFY((jvmti =
534 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
535 return JNI_ERR;
536
537 {
538 jvmtiCapabilities caps;
539
540 memset(&caps, 0, sizeof(caps));
541 caps.can_tag_objects = 1;
542 caps.can_generate_object_free_events = 1;
543 if (!NSK_JVMTI_VERIFY(
544 jvmti->AddCapabilities(&caps))) {
545 return JNI_ERR;
546 }
547 }
548
549 {
550 jvmtiEventCallbacks eventCallbacks;
551 memset(&eventCallbacks, 0, sizeof(eventCallbacks));
552 eventCallbacks.ObjectFree = callbackObjectFree;
553 if (!NSK_JVMTI_VERIFY(
554 jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
555 return JNI_ERR;
556 }
557
558 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
559 return JNI_ERR;
560
561 return JNI_OK;
562 }
563
564 /* ============================================================================= */
565
566 }
567