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