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