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