1 /* 2 * Copyright (c) 1998, 2007, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "util.h" 27 #include "invoker.h" 28 #include "eventHandler.h" 29 #include "threadControl.h" 30 #include "outStream.h" 31 32 static jrawMonitorID invokerLock; 33 34 void 35 invoker_initialize(void) 36 { 37 invokerLock = debugMonitorCreate("JDWP Invocation Lock"); 38 } 39 40 void 41 invoker_reset(void) 42 { 43 } 44 45 void invoker_lock(void) 46 { 47 debugMonitorEnter(invokerLock); 48 } 49 50 void invoker_unlock(void) 51 { 52 debugMonitorExit(invokerLock); 53 } 54 55 static jbyte 56 returnTypeTag(char *signature) 57 { 58 char *tagPtr = strchr(signature, SIGNATURE_END_ARGS); 59 JDI_ASSERT(tagPtr); 60 tagPtr++; /* 1st character after the end of args */ 61 return (jbyte)*tagPtr; 62 } 63 64 static jbyte 65 nextArgumentTypeTag(void **cursor) 66 { 67 char *tagPtr = *cursor; 68 jbyte argumentTag = (jbyte)*tagPtr; 69 70 if (*tagPtr != SIGNATURE_END_ARGS) { 71 /* Skip any array modifiers */ 72 while (*tagPtr == JDWP_TAG(ARRAY)) { 73 tagPtr++; 74 } 75 /* Skip class name */ 76 if (*tagPtr == JDWP_TAG(OBJECT)) { 77 tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1; 78 JDI_ASSERT(tagPtr); 79 } else { 80 /* Skip primitive sig */ 81 tagPtr++; 82 } 83 } 84 85 *cursor = tagPtr; 86 return argumentTag; 87 } 88 89 static jbyte 90 firstArgumentTypeTag(char *signature, void **cursor) 91 { 92 JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS); 93 *cursor = signature + 1; /* skip to the first arg */ 94 return nextArgumentTypeTag(cursor); 95 } 96 97 98 /* 99 * Note: argument refs may be destroyed on out-of-memory error 100 */ 101 static jvmtiError 102 createGlobalRefs(JNIEnv *env, InvokeRequest *request) 103 { 104 jvmtiError error; 105 jclass clazz = NULL; 106 jobject instance = NULL; 107 jint argIndex; 108 jbyte argumentTag; 109 jvalue *argument; 110 void *cursor; 111 jobject *argRefs = NULL; 112 113 error = JVMTI_ERROR_NONE; 114 115 if ( request->argumentCount > 0 ) { 116 /*LINTED*/ 117 argRefs = jvmtiAllocate((jint)(request->argumentCount*sizeof(jobject))); 118 if ( argRefs==NULL ) { 119 error = AGENT_ERROR_OUT_OF_MEMORY; 120 } else { 121 /*LINTED*/ 122 (void)memset(argRefs, 0, request->argumentCount*sizeof(jobject)); 123 } 124 } 125 126 if ( error == JVMTI_ERROR_NONE ) { 127 saveGlobalRef(env, request->clazz, &clazz); 128 if (clazz == NULL) { 129 error = AGENT_ERROR_OUT_OF_MEMORY; 130 } 131 } 132 133 if ( error == JVMTI_ERROR_NONE && request->instance != NULL ) { 134 saveGlobalRef(env, request->instance, &instance); 135 if (instance == NULL) { 136 error = AGENT_ERROR_OUT_OF_MEMORY; 137 } 138 } 139 140 if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) { 141 argIndex = 0; 142 argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor); 143 argument = request->arguments; 144 while (argumentTag != SIGNATURE_END_ARGS) { 145 if ( argIndex > request->argumentCount ) { 146 break; 147 } 148 if ((argumentTag == JDWP_TAG(OBJECT)) || 149 (argumentTag == JDWP_TAG(ARRAY))) { 150 /* Create a global ref for any non-null argument */ 151 if (argument->l != NULL) { 152 saveGlobalRef(env, argument->l, &argRefs[argIndex]); 153 if (argRefs[argIndex] == NULL) { 154 error = AGENT_ERROR_OUT_OF_MEMORY; 155 break; 156 } 157 } 158 } 159 argument++; 160 argIndex++; 161 argumentTag = nextArgumentTypeTag(&cursor); 162 } 163 } 164 165 #ifdef FIXUP /* Why isn't this an error? */ 166 /* Make sure the argument count matches */ 167 if ( error == JVMTI_ERROR_NONE && argIndex != request->argumentCount ) { 168 error = AGENT_ERROR_INVALID_COUNT; 169 } 170 #endif 171 172 /* Finally, put the global refs into the request if no errors */ 173 if ( error == JVMTI_ERROR_NONE ) { 174 request->clazz = clazz; 175 request->instance = instance; 176 if ( argRefs!=NULL ) { 177 argIndex = 0; 178 argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor); 179 argument = request->arguments; 180 while ( argIndex < request->argumentCount ) { 181 if ((argumentTag == JDWP_TAG(OBJECT)) || 182 (argumentTag == JDWP_TAG(ARRAY))) { 183 argument->l = argRefs[argIndex]; 184 } 185 argument++; 186 argIndex++; 187 argumentTag = nextArgumentTypeTag(&cursor); 188 } 189 jvmtiDeallocate(argRefs); 190 } 191 return JVMTI_ERROR_NONE; 192 193 } else { 194 /* Delete global references */ 195 if ( clazz != NULL ) { 196 tossGlobalRef(env, &clazz); 197 } 198 if ( instance != NULL ) { 199 tossGlobalRef(env, &instance); 200 } 201 if ( argRefs!=NULL ) { 202 for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) { 203 if ( argRefs[argIndex] != NULL ) { 204 tossGlobalRef(env, &argRefs[argIndex]); 205 } 206 } 207 jvmtiDeallocate(argRefs); 208 } 209 } 210 211 return error; 212 } 213 214 /* 215 * Delete global argument references from the request which got put there before a 216 * invoke request was carried out. See fillInvokeRequest(). 217 */ 218 static void 219 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request) 220 { 221 void *cursor; 222 jint argIndex = 0; 223 jvalue *argument = request->arguments; 224 jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor); 225 226 if (request->clazz != NULL) { 227 tossGlobalRef(env, &(request->clazz)); 228 } 229 if (request->instance != NULL) { 230 tossGlobalRef(env, &(request->instance)); 231 } 232 /* Delete global argument references */ 233 while (argIndex < request->argumentCount) { 234 if ((argumentTag == JDWP_TAG(OBJECT)) || 235 (argumentTag == JDWP_TAG(ARRAY))) { 236 if (argument->l != NULL) { 237 tossGlobalRef(env, &(argument->l)); 238 } 239 } 240 argument++; 241 argIndex++; 242 argumentTag = nextArgumentTypeTag(&cursor); 243 } 244 } 245 246 static jvmtiError 247 fillInvokeRequest(JNIEnv *env, InvokeRequest *request, 248 jbyte invokeType, jbyte options, jint id, 249 jthread thread, jclass clazz, jmethodID method, 250 jobject instance, 251 jvalue *arguments, jint argumentCount) 252 { 253 jvmtiError error; 254 if (!request->available) { 255 /* 256 * Thread is not at a point where it can invoke. 257 */ 258 return AGENT_ERROR_INVALID_THREAD; 259 } 260 if (request->pending) { 261 /* 262 * Pending invoke 263 */ 264 return AGENT_ERROR_ALREADY_INVOKING; 265 } 266 267 request->invokeType = invokeType; 268 request->options = options; 269 request->detached = JNI_FALSE; 270 request->id = id; 271 request->clazz = clazz; 272 request->method = method; 273 request->instance = instance; 274 request->arguments = arguments; 275 request->arguments = arguments; 276 request->argumentCount = argumentCount; 277 278 request->returnValue.j = 0; 279 request->exception = 0; 280 281 /* 282 * Squirrel away the method signature 283 */ 284 error = methodSignature(method, NULL, &request->methodSignature, NULL); 285 if (error != JVMTI_ERROR_NONE) { 286 return error; 287 } 288 289 /* 290 * The given references for class and instance are not guaranteed 291 * to be around long enough for invocation, so create new ones 292 * here. 293 */ 294 error = createGlobalRefs(env, request); 295 if (error != JVMTI_ERROR_NONE) { 296 jvmtiDeallocate(request->methodSignature); 297 return error; 298 } 299 300 request->pending = JNI_TRUE; 301 request->available = JNI_FALSE; 302 return JVMTI_ERROR_NONE; 303 } 304 305 void 306 invoker_enableInvokeRequests(jthread thread) 307 { 308 InvokeRequest *request; 309 310 JDI_ASSERT(thread); 311 312 debugMonitorEnter(invokerLock); 313 request = threadControl_getInvokeRequest(thread); 314 if (request == NULL) { 315 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 316 } 317 318 request->available = JNI_TRUE; 319 debugMonitorExit(invokerLock); 320 } 321 322 jvmtiError 323 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id, 324 jthread thread, jclass clazz, jmethodID method, 325 jobject instance, 326 jvalue *arguments, jint argumentCount) 327 { 328 JNIEnv *env = getEnv(); 329 InvokeRequest *request; 330 jvmtiError error = JVMTI_ERROR_NONE; 331 332 debugMonitorEnter(invokerLock); 333 request = threadControl_getInvokeRequest(thread); 334 if (request != NULL) { 335 error = fillInvokeRequest(env, request, invokeType, options, id, 336 thread, clazz, method, instance, 337 arguments, argumentCount); 338 } 339 debugMonitorExit(invokerLock); 340 341 if (error == JVMTI_ERROR_NONE) { 342 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) { 343 /* true means it is okay to unblock the commandLoop thread */ 344 (void)threadControl_resumeThread(thread, JNI_TRUE); 345 } else { 346 (void)threadControl_resumeAll(); 347 } 348 } 349 350 return error; 351 } 352 353 static void 354 invokeConstructor(JNIEnv *env, InvokeRequest *request) 355 { 356 jobject object; 357 358 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 359 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz, 360 request->method, 361 request->arguments); 362 request->returnValue.l = NULL; 363 if (object != NULL) { 364 saveGlobalRef(env, object, &(request->returnValue.l)); 365 } 366 } 367 368 static void 369 invokeStatic(JNIEnv *env, InvokeRequest *request) 370 { 371 switch(returnTypeTag(request->methodSignature)) { 372 case JDWP_TAG(OBJECT): 373 case JDWP_TAG(ARRAY): { 374 jobject object; 375 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 376 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env, 377 request->clazz, 378 request->method, 379 request->arguments); 380 request->returnValue.l = NULL; 381 if (object != NULL) { 382 saveGlobalRef(env, object, &(request->returnValue.l)); 383 } 384 break; 385 } 386 387 388 case JDWP_TAG(BYTE): 389 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env, 390 request->clazz, 391 request->method, 392 request->arguments); 393 break; 394 395 case JDWP_TAG(CHAR): 396 request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env, 397 request->clazz, 398 request->method, 399 request->arguments); 400 break; 401 402 case JDWP_TAG(FLOAT): 403 request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env, 404 request->clazz, 405 request->method, 406 request->arguments); 407 break; 408 409 case JDWP_TAG(DOUBLE): 410 request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env, 411 request->clazz, 412 request->method, 413 request->arguments); 414 break; 415 416 case JDWP_TAG(INT): 417 request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env, 418 request->clazz, 419 request->method, 420 request->arguments); 421 break; 422 423 case JDWP_TAG(LONG): 424 request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env, 425 request->clazz, 426 request->method, 427 request->arguments); 428 break; 429 430 case JDWP_TAG(SHORT): 431 request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env, 432 request->clazz, 433 request->method, 434 request->arguments); 435 break; 436 437 case JDWP_TAG(BOOLEAN): 438 request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env, 439 request->clazz, 440 request->method, 441 request->arguments); 442 break; 443 444 case JDWP_TAG(VOID): 445 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env, 446 request->clazz, 447 request->method, 448 request->arguments); 449 break; 450 451 default: 452 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 453 break; 454 } 455 } 456 457 static void 458 invokeVirtual(JNIEnv *env, InvokeRequest *request) 459 { 460 switch(returnTypeTag(request->methodSignature)) { 461 case JDWP_TAG(OBJECT): 462 case JDWP_TAG(ARRAY): { 463 jobject object; 464 JDI_ASSERT_MSG(request->instance, "Request instance null"); 465 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env, 466 request->instance, 467 request->method, 468 request->arguments); 469 request->returnValue.l = NULL; 470 if (object != NULL) { 471 saveGlobalRef(env, object, &(request->returnValue.l)); 472 } 473 break; 474 } 475 476 case JDWP_TAG(BYTE): 477 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env, 478 request->instance, 479 request->method, 480 request->arguments); 481 break; 482 483 case JDWP_TAG(CHAR): 484 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env, 485 request->instance, 486 request->method, 487 request->arguments); 488 break; 489 490 case JDWP_TAG(FLOAT): 491 request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env, 492 request->instance, 493 request->method, 494 request->arguments); 495 break; 496 497 case JDWP_TAG(DOUBLE): 498 request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env, 499 request->instance, 500 request->method, 501 request->arguments); 502 break; 503 504 case JDWP_TAG(INT): 505 request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env, 506 request->instance, 507 request->method, 508 request->arguments); 509 break; 510 511 case JDWP_TAG(LONG): 512 request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env, 513 request->instance, 514 request->method, 515 request->arguments); 516 break; 517 518 case JDWP_TAG(SHORT): 519 request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env, 520 request->instance, 521 request->method, 522 request->arguments); 523 break; 524 525 case JDWP_TAG(BOOLEAN): 526 request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env, 527 request->instance, 528 request->method, 529 request->arguments); 530 break; 531 532 case JDWP_TAG(VOID): 533 JNI_FUNC_PTR(env,CallVoidMethodA)(env, 534 request->instance, 535 request->method, 536 request->arguments); 537 break; 538 539 default: 540 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 541 break; 542 } 543 } 544 545 static void 546 invokeNonvirtual(JNIEnv *env, InvokeRequest *request) 547 { 548 switch(returnTypeTag(request->methodSignature)) { 549 case JDWP_TAG(OBJECT): 550 case JDWP_TAG(ARRAY): { 551 jobject object; 552 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 553 JDI_ASSERT_MSG(request->instance, "Request instance null"); 554 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env, 555 request->instance, 556 request->clazz, 557 request->method, 558 request->arguments); 559 request->returnValue.l = NULL; 560 if (object != NULL) { 561 saveGlobalRef(env, object, &(request->returnValue.l)); 562 } 563 break; 564 } 565 566 case JDWP_TAG(BYTE): 567 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env, 568 request->instance, 569 request->clazz, 570 request->method, 571 request->arguments); 572 break; 573 574 case JDWP_TAG(CHAR): 575 request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env, 576 request->instance, 577 request->clazz, 578 request->method, 579 request->arguments); 580 break; 581 582 case JDWP_TAG(FLOAT): 583 request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env, 584 request->instance, 585 request->clazz, 586 request->method, 587 request->arguments); 588 break; 589 590 case JDWP_TAG(DOUBLE): 591 request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env, 592 request->instance, 593 request->clazz, 594 request->method, 595 request->arguments); 596 break; 597 598 case JDWP_TAG(INT): 599 request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env, 600 request->instance, 601 request->clazz, 602 request->method, 603 request->arguments); 604 break; 605 606 case JDWP_TAG(LONG): 607 request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env, 608 request->instance, 609 request->clazz, 610 request->method, 611 request->arguments); 612 break; 613 614 case JDWP_TAG(SHORT): 615 request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env, 616 request->instance, 617 request->clazz, 618 request->method, 619 request->arguments); 620 break; 621 622 case JDWP_TAG(BOOLEAN): 623 request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env, 624 request->instance, 625 request->clazz, 626 request->method, 627 request->arguments); 628 break; 629 630 case JDWP_TAG(VOID): 631 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env, 632 request->instance, 633 request->clazz, 634 request->method, 635 request->arguments); 636 break; 637 638 default: 639 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 640 break; 641 } 642 } 643 644 jboolean 645 invoker_doInvoke(jthread thread) 646 { 647 JNIEnv *env; 648 jboolean startNow; 649 InvokeRequest *request; 650 jbyte options; 651 jbyte invokeType; 652 653 JDI_ASSERT(thread); 654 655 debugMonitorEnter(invokerLock); 656 657 request = threadControl_getInvokeRequest(thread); 658 if (request == NULL) { 659 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 660 } 661 662 request->available = JNI_FALSE; 663 startNow = request->pending && !request->started; 664 665 if (startNow) { 666 request->started = JNI_TRUE; 667 } 668 options = request->options; 669 invokeType = request->invokeType; 670 671 debugMonitorExit(invokerLock); 672 673 if (!startNow) { 674 return JNI_FALSE; 675 } 676 677 env = getEnv(); 678 679 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */ 680 681 jobject exception; 682 683 JNI_FUNC_PTR(env,ExceptionClear)(env); 684 685 switch (invokeType) { 686 case INVOKE_CONSTRUCTOR: 687 invokeConstructor(env, request); 688 break; 689 case INVOKE_STATIC: 690 invokeStatic(env, request); 691 break; 692 case INVOKE_INSTANCE: 693 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) { 694 invokeNonvirtual(env, request); 695 } else { 696 invokeVirtual(env, request); 697 } 698 break; 699 default: 700 JDI_ASSERT(JNI_FALSE); 701 } 702 request->exception = NULL; 703 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env); 704 if (exception != NULL) { 705 JNI_FUNC_PTR(env,ExceptionClear)(env); 706 saveGlobalRef(env, exception, &(request->exception)); 707 } 708 709 } END_WITH_LOCAL_REFS(env); 710 711 return JNI_TRUE; 712 } 713 714 void 715 invoker_completeInvokeRequest(jthread thread) 716 { 717 JNIEnv *env = getEnv(); 718 PacketOutputStream out; 719 jbyte tag; 720 jobject exc; 721 jvalue returnValue; 722 jint id; 723 InvokeRequest *request; 724 jboolean detached; 725 726 JDI_ASSERT(thread); 727 728 /* Prevent gcc errors on uninitialized variables. */ 729 tag = 0; 730 exc = NULL; 731 id = 0; 732 733 eventHandler_lock(); /* for proper lock order */ 734 debugMonitorEnter(invokerLock); 735 736 request = threadControl_getInvokeRequest(thread); 737 if (request == NULL) { 738 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 739 } 740 741 JDI_ASSERT(request->pending); 742 JDI_ASSERT(request->started); 743 744 request->pending = JNI_FALSE; 745 request->started = JNI_FALSE; 746 request->available = JNI_TRUE; /* For next time around */ 747 748 detached = request->detached; 749 if (!detached) { 750 if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) { 751 (void)threadControl_suspendThread(thread, JNI_FALSE); 752 } else { 753 (void)threadControl_suspendAll(); 754 } 755 756 if (request->invokeType == INVOKE_CONSTRUCTOR) { 757 /* 758 * Although constructors technically have a return type of 759 * void, we return the object created. 760 */ 761 tag = specificTypeKey(env, request->returnValue.l); 762 } else { 763 tag = returnTypeTag(request->methodSignature); 764 } 765 id = request->id; 766 exc = request->exception; 767 returnValue = request->returnValue; 768 } 769 770 /* 771 * At this time, there's no need to retain global references on 772 * arguments since the reply is processed. No one will deal with 773 * this request ID anymore, so we must call deleteGlobalArgumentRefs(). 774 * 775 * We cannot delete saved exception or return value references 776 * since otherwise a deleted handle would escape when writing 777 * the response to the stream. Instead, we clean those refs up 778 * after writing the respone. 779 */ 780 deleteGlobalArgumentRefs(env, request); 781 782 /* 783 * Give up the lock before I/O operation 784 */ 785 debugMonitorExit(invokerLock); 786 eventHandler_unlock(); 787 788 if (!detached) { 789 outStream_initReply(&out, id); 790 (void)outStream_writeValue(env, &out, tag, returnValue); 791 (void)outStream_writeObjectTag(env, &out, exc); 792 (void)outStream_writeObjectRef(env, &out, exc); 793 outStream_sendReply(&out); 794 } 795 796 /* 797 * Delete potentially saved global references of return value 798 * and exception 799 */ 800 eventHandler_lock(); // for proper lock order 801 debugMonitorEnter(invokerLock); 802 /* Delete potentially saved return value */ 803 if ((request->invokeType == INVOKE_CONSTRUCTOR) || 804 (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) || 805 (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) { 806 if (request->returnValue.l != NULL) { 807 tossGlobalRef(env, &(request->returnValue.l)); 808 } 809 } 810 /* Delete potentially saved exception */ 811 if (request->exception != NULL) { 812 tossGlobalRef(env, &(request->exception)); 813 } 814 debugMonitorExit(invokerLock); 815 eventHandler_unlock(); 816 } 817 818 jboolean 819 invoker_isEnabled(jthread thread) 820 { 821 InvokeRequest *request; 822 jboolean isEnabled; 823 824 JDI_ASSERT(thread); 825 debugMonitorEnter(invokerLock); 826 request = threadControl_getInvokeRequest(thread); 827 if (request == NULL) { 828 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 829 } 830 isEnabled = request->available; 831 debugMonitorExit(invokerLock); 832 return isEnabled; 833 } 834 835 void 836 invoker_detach(InvokeRequest *request) 837 { 838 JDI_ASSERT(request); 839 debugMonitorEnter(invokerLock); 840 request->detached = JNI_TRUE; 841 debugMonitorExit(invokerLock); 842 }