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 saved global references - if any - for: 216 * - a potentially thrown Exception 217 * - a returned refernce/array value 218 * See invoker_doInvoke() and invoke* methods where global references 219 * are being saved. 220 */ 221 static void 222 deletePotentiallySavedGlobalRefs(JNIEnv *env, InvokeRequest *request) 223 { 224 /* Delete potentially saved return value */ 225 if ((request->invokeType == INVOKE_CONSTRUCTOR) || 226 (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) || 227 (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) { 228 if (request->returnValue.l != NULL) { 229 tossGlobalRef(env, &(request->returnValue.l)); 230 } 231 } 232 /* Delete potentially saved exception */ 233 if (request->exception != NULL) { 234 tossGlobalRef(env, &(request->exception)); 235 } 236 } 237 238 /* 239 * Delete global argument references from the request which got put there before a 240 * invoke request was carried out. See fillInvokeRequest(). 241 */ 242 static void 243 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request) 244 { 245 void *cursor; 246 jint argIndex = 0; 247 jvalue *argument = request->arguments; 248 jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor); 249 250 if (request->clazz != NULL) { 251 tossGlobalRef(env, &(request->clazz)); 252 } 253 if (request->instance != NULL) { 254 tossGlobalRef(env, &(request->instance)); 255 } 256 /* Delete global argument references */ 257 while (argIndex < request->argumentCount) { 258 if ((argumentTag == JDWP_TAG(OBJECT)) || 259 (argumentTag == JDWP_TAG(ARRAY))) { 260 if (argument->l != NULL) { 261 tossGlobalRef(env, &(argument->l)); 262 } 263 } 264 argument++; 265 argIndex++; 266 argumentTag = nextArgumentTypeTag(&cursor); 267 } 268 } 269 270 static jvmtiError 271 fillInvokeRequest(JNIEnv *env, InvokeRequest *request, 272 jbyte invokeType, jbyte options, jint id, 273 jthread thread, jclass clazz, jmethodID method, 274 jobject instance, 275 jvalue *arguments, jint argumentCount) 276 { 277 jvmtiError error; 278 if (!request->available) { 279 /* 280 * Thread is not at a point where it can invoke. 281 */ 282 return AGENT_ERROR_INVALID_THREAD; 283 } 284 if (request->pending) { 285 /* 286 * Pending invoke 287 */ 288 return AGENT_ERROR_ALREADY_INVOKING; 289 } 290 291 request->invokeType = invokeType; 292 request->options = options; 293 request->detached = JNI_FALSE; 294 request->id = id; 295 request->clazz = clazz; 296 request->method = method; 297 request->instance = instance; 298 request->arguments = arguments; 299 request->arguments = arguments; 300 request->argumentCount = argumentCount; 301 302 request->returnValue.j = 0; 303 request->exception = 0; 304 305 /* 306 * Squirrel away the method signature 307 */ 308 error = methodSignature(method, NULL, &request->methodSignature, NULL); 309 if (error != JVMTI_ERROR_NONE) { 310 return error; 311 } 312 313 /* 314 * The given references for class and instance are not guaranteed 315 * to be around long enough for invocation, so create new ones 316 * here. 317 */ 318 error = createGlobalRefs(env, request); 319 if (error != JVMTI_ERROR_NONE) { 320 jvmtiDeallocate(request->methodSignature); 321 return error; 322 } 323 324 request->pending = JNI_TRUE; 325 request->available = JNI_FALSE; 326 return JVMTI_ERROR_NONE; 327 } 328 329 void 330 invoker_enableInvokeRequests(jthread thread) 331 { 332 InvokeRequest *request; 333 334 JDI_ASSERT(thread); 335 336 request = threadControl_getInvokeRequest(thread); 337 if (request == NULL) { 338 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 339 } 340 341 request->available = JNI_TRUE; 342 } 343 344 jvmtiError 345 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id, 346 jthread thread, jclass clazz, jmethodID method, 347 jobject instance, 348 jvalue *arguments, jint argumentCount) 349 { 350 JNIEnv *env = getEnv(); 351 InvokeRequest *request; 352 jvmtiError error = JVMTI_ERROR_NONE; 353 354 debugMonitorEnter(invokerLock); 355 request = threadControl_getInvokeRequest(thread); 356 if (request != NULL) { 357 error = fillInvokeRequest(env, request, invokeType, options, id, 358 thread, clazz, method, instance, 359 arguments, argumentCount); 360 } 361 debugMonitorExit(invokerLock); 362 363 if (error == JVMTI_ERROR_NONE) { 364 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) { 365 /* true means it is okay to unblock the commandLoop thread */ 366 (void)threadControl_resumeThread(thread, JNI_TRUE); 367 } else { 368 (void)threadControl_resumeAll(); 369 } 370 } 371 372 return error; 373 } 374 375 static void 376 invokeConstructor(JNIEnv *env, InvokeRequest *request) 377 { 378 jobject object; 379 380 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 381 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz, 382 request->method, 383 request->arguments); 384 request->returnValue.l = NULL; 385 if (object != NULL) { 386 saveGlobalRef(env, object, &(request->returnValue.l)); 387 } 388 } 389 390 static void 391 invokeStatic(JNIEnv *env, InvokeRequest *request) 392 { 393 switch(returnTypeTag(request->methodSignature)) { 394 case JDWP_TAG(OBJECT): 395 case JDWP_TAG(ARRAY): { 396 jobject object; 397 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 398 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env, 399 request->clazz, 400 request->method, 401 request->arguments); 402 request->returnValue.l = NULL; 403 if (object != NULL) { 404 saveGlobalRef(env, object, &(request->returnValue.l)); 405 } 406 break; 407 } 408 409 410 case JDWP_TAG(BYTE): 411 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env, 412 request->clazz, 413 request->method, 414 request->arguments); 415 break; 416 417 case JDWP_TAG(CHAR): 418 request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env, 419 request->clazz, 420 request->method, 421 request->arguments); 422 break; 423 424 case JDWP_TAG(FLOAT): 425 request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env, 426 request->clazz, 427 request->method, 428 request->arguments); 429 break; 430 431 case JDWP_TAG(DOUBLE): 432 request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env, 433 request->clazz, 434 request->method, 435 request->arguments); 436 break; 437 438 case JDWP_TAG(INT): 439 request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env, 440 request->clazz, 441 request->method, 442 request->arguments); 443 break; 444 445 case JDWP_TAG(LONG): 446 request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env, 447 request->clazz, 448 request->method, 449 request->arguments); 450 break; 451 452 case JDWP_TAG(SHORT): 453 request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env, 454 request->clazz, 455 request->method, 456 request->arguments); 457 break; 458 459 case JDWP_TAG(BOOLEAN): 460 request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env, 461 request->clazz, 462 request->method, 463 request->arguments); 464 break; 465 466 case JDWP_TAG(VOID): 467 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env, 468 request->clazz, 469 request->method, 470 request->arguments); 471 break; 472 473 default: 474 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 475 break; 476 } 477 } 478 479 static void 480 invokeVirtual(JNIEnv *env, InvokeRequest *request) 481 { 482 switch(returnTypeTag(request->methodSignature)) { 483 case JDWP_TAG(OBJECT): 484 case JDWP_TAG(ARRAY): { 485 jobject object; 486 JDI_ASSERT_MSG(request->instance, "Request instance null"); 487 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env, 488 request->instance, 489 request->method, 490 request->arguments); 491 request->returnValue.l = NULL; 492 if (object != NULL) { 493 saveGlobalRef(env, object, &(request->returnValue.l)); 494 } 495 break; 496 } 497 498 case JDWP_TAG(BYTE): 499 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env, 500 request->instance, 501 request->method, 502 request->arguments); 503 break; 504 505 case JDWP_TAG(CHAR): 506 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env, 507 request->instance, 508 request->method, 509 request->arguments); 510 break; 511 512 case JDWP_TAG(FLOAT): 513 request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env, 514 request->instance, 515 request->method, 516 request->arguments); 517 break; 518 519 case JDWP_TAG(DOUBLE): 520 request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env, 521 request->instance, 522 request->method, 523 request->arguments); 524 break; 525 526 case JDWP_TAG(INT): 527 request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env, 528 request->instance, 529 request->method, 530 request->arguments); 531 break; 532 533 case JDWP_TAG(LONG): 534 request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env, 535 request->instance, 536 request->method, 537 request->arguments); 538 break; 539 540 case JDWP_TAG(SHORT): 541 request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env, 542 request->instance, 543 request->method, 544 request->arguments); 545 break; 546 547 case JDWP_TAG(BOOLEAN): 548 request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env, 549 request->instance, 550 request->method, 551 request->arguments); 552 break; 553 554 case JDWP_TAG(VOID): 555 JNI_FUNC_PTR(env,CallVoidMethodA)(env, 556 request->instance, 557 request->method, 558 request->arguments); 559 break; 560 561 default: 562 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 563 break; 564 } 565 } 566 567 static void 568 invokeNonvirtual(JNIEnv *env, InvokeRequest *request) 569 { 570 switch(returnTypeTag(request->methodSignature)) { 571 case JDWP_TAG(OBJECT): 572 case JDWP_TAG(ARRAY): { 573 jobject object; 574 JDI_ASSERT_MSG(request->clazz, "Request clazz null"); 575 JDI_ASSERT_MSG(request->instance, "Request instance null"); 576 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env, 577 request->instance, 578 request->clazz, 579 request->method, 580 request->arguments); 581 request->returnValue.l = NULL; 582 if (object != NULL) { 583 saveGlobalRef(env, object, &(request->returnValue.l)); 584 } 585 break; 586 } 587 588 case JDWP_TAG(BYTE): 589 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env, 590 request->instance, 591 request->clazz, 592 request->method, 593 request->arguments); 594 break; 595 596 case JDWP_TAG(CHAR): 597 request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env, 598 request->instance, 599 request->clazz, 600 request->method, 601 request->arguments); 602 break; 603 604 case JDWP_TAG(FLOAT): 605 request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env, 606 request->instance, 607 request->clazz, 608 request->method, 609 request->arguments); 610 break; 611 612 case JDWP_TAG(DOUBLE): 613 request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env, 614 request->instance, 615 request->clazz, 616 request->method, 617 request->arguments); 618 break; 619 620 case JDWP_TAG(INT): 621 request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env, 622 request->instance, 623 request->clazz, 624 request->method, 625 request->arguments); 626 break; 627 628 case JDWP_TAG(LONG): 629 request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env, 630 request->instance, 631 request->clazz, 632 request->method, 633 request->arguments); 634 break; 635 636 case JDWP_TAG(SHORT): 637 request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env, 638 request->instance, 639 request->clazz, 640 request->method, 641 request->arguments); 642 break; 643 644 case JDWP_TAG(BOOLEAN): 645 request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env, 646 request->instance, 647 request->clazz, 648 request->method, 649 request->arguments); 650 break; 651 652 case JDWP_TAG(VOID): 653 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env, 654 request->instance, 655 request->clazz, 656 request->method, 657 request->arguments); 658 break; 659 660 default: 661 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature"); 662 break; 663 } 664 } 665 666 jboolean 667 invoker_doInvoke(jthread thread) 668 { 669 JNIEnv *env; 670 jboolean startNow; 671 InvokeRequest *request; 672 jbyte options; 673 jbyte invokeType; 674 675 JDI_ASSERT(thread); 676 677 debugMonitorEnter(invokerLock); 678 679 request = threadControl_getInvokeRequest(thread); 680 if (request == NULL) { 681 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 682 } 683 684 request->available = JNI_FALSE; 685 startNow = request->pending && !request->started; 686 687 if (startNow) { 688 request->started = JNI_TRUE; 689 } 690 options = request->options; 691 invokeType = request->invokeType; 692 693 debugMonitorExit(invokerLock); 694 695 if (!startNow) { 696 return JNI_FALSE; 697 } 698 699 env = getEnv(); 700 701 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */ 702 703 jobject exception; 704 705 JNI_FUNC_PTR(env,ExceptionClear)(env); 706 707 switch (invokeType) { 708 case INVOKE_CONSTRUCTOR: 709 invokeConstructor(env, request); 710 break; 711 case INVOKE_STATIC: 712 invokeStatic(env, request); 713 break; 714 case INVOKE_INSTANCE: 715 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) { 716 invokeNonvirtual(env, request); 717 } else { 718 invokeVirtual(env, request); 719 } 720 break; 721 default: 722 JDI_ASSERT(JNI_FALSE); 723 } 724 request->exception = NULL; 725 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env); 726 if (exception != NULL) { 727 JNI_FUNC_PTR(env,ExceptionClear)(env); 728 saveGlobalRef(env, exception, &(request->exception)); 729 } 730 731 } END_WITH_LOCAL_REFS(env); 732 733 return JNI_TRUE; 734 } 735 736 void 737 invoker_completeInvokeRequest(jthread thread) 738 { 739 JNIEnv *env = getEnv(); 740 PacketOutputStream out; 741 jbyte tag; 742 jobject exc; 743 jvalue returnValue; 744 jint id; 745 InvokeRequest *request; 746 jboolean detached; 747 748 JDI_ASSERT(thread); 749 750 /* Prevent gcc errors on uninitialized variables. */ 751 tag = 0; 752 exc = NULL; 753 id = 0; 754 755 eventHandler_lock(); /* for proper lock order */ 756 debugMonitorEnter(invokerLock); 757 758 request = threadControl_getInvokeRequest(thread); 759 if (request == NULL) { 760 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 761 } 762 763 JDI_ASSERT(request->pending); 764 JDI_ASSERT(request->started); 765 766 request->pending = JNI_FALSE; 767 request->started = JNI_FALSE; 768 request->available = JNI_TRUE; /* For next time around */ 769 770 detached = request->detached; 771 if (!detached) { 772 if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) { 773 (void)threadControl_suspendThread(thread, JNI_FALSE); 774 } else { 775 (void)threadControl_suspendAll(); 776 } 777 778 if (request->invokeType == INVOKE_CONSTRUCTOR) { 779 /* 780 * Although constructors technically have a return type of 781 * void, we return the object created. 782 */ 783 tag = specificTypeKey(env, request->returnValue.l); 784 } else { 785 tag = returnTypeTag(request->methodSignature); 786 } 787 id = request->id; 788 exc = request->exception; 789 returnValue = request->returnValue; 790 } 791 792 /* 793 * At this time, there's no need to retain global references on 794 * arguments since the reply is processed. No one will deal with 795 * this request ID anymore, so we must call deleteGlobalArgumentRefs(). 796 * 797 * We cannot delete saved exception or return value references 798 * since otherwise a deleted handle would escape when writing 799 * the response to the stream. Instead, we clean those refs up 800 * after writing the respone. 801 */ 802 deleteGlobalArgumentRefs(env, request); 803 804 /* 805 * Give up the lock before I/O operation 806 */ 807 debugMonitorExit(invokerLock); 808 eventHandler_unlock(); 809 810 if (!detached) { 811 outStream_initReply(&out, id); 812 (void)outStream_writeValue(env, &out, tag, returnValue); 813 (void)outStream_writeObjectTag(env, &out, exc); 814 (void)outStream_writeObjectRef(env, &out, exc); 815 outStream_sendReply(&out); 816 } 817 818 /* 819 * Delete potentially saved global references of return value 820 * and exception 821 */ 822 eventHandler_lock(); // for proper lock order 823 debugMonitorEnter(invokerLock); 824 deletePotentiallySavedGlobalRefs(env, request); 825 debugMonitorExit(invokerLock); 826 eventHandler_unlock(); 827 } 828 829 jboolean 830 invoker_isPending(jthread thread) 831 { 832 InvokeRequest *request; 833 834 JDI_ASSERT(thread); 835 request = threadControl_getInvokeRequest(thread); 836 if (request == NULL) { 837 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 838 } 839 return request->pending; 840 } 841 842 jboolean 843 invoker_isEnabled(jthread thread) 844 { 845 InvokeRequest *request; 846 847 JDI_ASSERT(thread); 848 request = threadControl_getInvokeRequest(thread); 849 if (request == NULL) { 850 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request"); 851 } 852 return request->available; 853 } 854 855 void 856 invoker_detach(InvokeRequest *request) 857 { 858 JDI_ASSERT(request); 859 debugMonitorEnter(invokerLock); 860 request->detached = JNI_TRUE; 861 debugMonitorExit(invokerLock); 862 } 863