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