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