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