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