Home | History | Annotate | Download | only in back
      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 }
    863