1 /*
   2  * Copyright (c) 1998, 2016, 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     debugMonitorEnter(invokerLock);
 337     request = threadControl_getInvokeRequest(thread);
 338     if (request == NULL) {
 339         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 340     }
 341 
 342     request->available = JNI_TRUE;
 343     debugMonitorExit(invokerLock);
 344 }
 345 
 346 /*
 347  * Check that method is in the specified clazz or one of its super classes.
 348  * We have to enforce this check at the JDWP layer because the JNI layer
 349  * has different requirements.
 350  */
 351 static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method)
 352 {
 353     jclass containing_class;
 354     jvmtiError error;
 355 
 356     error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
 357                 (gdata->jvmti, method, &containing_class);
 358     if (error != JVMTI_ERROR_NONE) {
 359         return JVMTI_ERROR_NONE;  /* Bad jmethodID ?  This will be handled elsewhere */
 360     }
 361 
 362     if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) {
 363         return JVMTI_ERROR_NONE;
 364     }
 365 
 366     // If not the same class then check that containing_class is a super type of
 367     // clazz and not an interface (hence it's a super class).
 368     if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) &&
 369         referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) {
 370         return JVMTI_ERROR_NONE;
 371     }
 372     return JVMTI_ERROR_INVALID_METHODID;
 373 }
 374 
 375 jvmtiError
 376 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
 377                       jthread thread, jclass clazz, jmethodID method,
 378                       jobject instance,
 379                       jvalue *arguments, jint argumentCount)
 380 {
 381     JNIEnv *env = getEnv();
 382     InvokeRequest *request;
 383     jvmtiError error = JVMTI_ERROR_NONE;
 384 
 385     if (invokeType == INVOKE_STATIC) {
 386         error = check_methodClass(env, clazz, method);
 387         if (error != JVMTI_ERROR_NONE) {
 388             return error;
 389         }
 390     }
 391 
 392     debugMonitorEnter(invokerLock);
 393     request = threadControl_getInvokeRequest(thread);
 394     if (request != NULL) {
 395         error = fillInvokeRequest(env, request, invokeType, options, id,
 396                                   thread, clazz, method, instance,
 397                                   arguments, argumentCount);
 398     }
 399     debugMonitorExit(invokerLock);
 400 
 401     if (error == JVMTI_ERROR_NONE) {
 402         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
 403             /* true means it is okay to unblock the commandLoop thread */
 404             (void)threadControl_resumeThread(thread, JNI_TRUE);
 405         } else {
 406             (void)threadControl_resumeAll();
 407         }
 408     }
 409 
 410     return error;
 411 }
 412 
 413 static void
 414 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 415 {
 416     jobject object;
 417 
 418     JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 419     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
 420                                      request->method,
 421                                      request->arguments);
 422     request->returnValue.l = NULL;
 423     if (object != NULL) {
 424         saveGlobalRef(env, object, &(request->returnValue.l));
 425     }
 426 }
 427 
 428 static void
 429 invokeStatic(JNIEnv *env, InvokeRequest *request)
 430 {
 431     switch(returnTypeTag(request->methodSignature)) {
 432         case JDWP_TAG(OBJECT):
 433         case JDWP_TAG(ARRAY): {
 434             jobject object;
 435             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 436             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
 437                                        request->clazz,
 438                                        request->method,
 439                                        request->arguments);
 440             request->returnValue.l = NULL;
 441             if (object != NULL) {
 442                 saveGlobalRef(env, object, &(request->returnValue.l));
 443             }
 444             break;
 445         }
 446 
 447 
 448         case JDWP_TAG(BYTE):
 449             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
 450                                                        request->clazz,
 451                                                        request->method,
 452                                                        request->arguments);
 453             break;
 454 
 455         case JDWP_TAG(CHAR):
 456             request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env,
 457                                                        request->clazz,
 458                                                        request->method,
 459                                                        request->arguments);
 460             break;
 461 
 462         case JDWP_TAG(FLOAT):
 463             request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env,
 464                                                        request->clazz,
 465                                                        request->method,
 466                                                        request->arguments);
 467             break;
 468 
 469         case JDWP_TAG(DOUBLE):
 470             request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env,
 471                                                        request->clazz,
 472                                                        request->method,
 473                                                        request->arguments);
 474             break;
 475 
 476         case JDWP_TAG(INT):
 477             request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env,
 478                                                        request->clazz,
 479                                                        request->method,
 480                                                        request->arguments);
 481             break;
 482 
 483         case JDWP_TAG(LONG):
 484             request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env,
 485                                                        request->clazz,
 486                                                        request->method,
 487                                                        request->arguments);
 488             break;
 489 
 490         case JDWP_TAG(SHORT):
 491             request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env,
 492                                                        request->clazz,
 493                                                        request->method,
 494                                                        request->arguments);
 495             break;
 496 
 497         case JDWP_TAG(BOOLEAN):
 498             request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env,
 499                                                        request->clazz,
 500                                                        request->method,
 501                                                        request->arguments);
 502             break;
 503 
 504         case JDWP_TAG(VOID):
 505             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
 506                                           request->clazz,
 507                                           request->method,
 508                                           request->arguments);
 509             break;
 510 
 511         default:
 512             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 513             break;
 514     }
 515 }
 516 
 517 static void
 518 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 519 {
 520     switch(returnTypeTag(request->methodSignature)) {
 521         case JDWP_TAG(OBJECT):
 522         case JDWP_TAG(ARRAY): {
 523             jobject object;
 524             JDI_ASSERT_MSG(request->instance, "Request instance null");
 525             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
 526                                  request->instance,
 527                                  request->method,
 528                                  request->arguments);
 529             request->returnValue.l = NULL;
 530             if (object != NULL) {
 531                 saveGlobalRef(env, object, &(request->returnValue.l));
 532             }
 533             break;
 534         }
 535 
 536         case JDWP_TAG(BYTE):
 537             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
 538                                                  request->instance,
 539                                                  request->method,
 540                                                  request->arguments);
 541             break;
 542 
 543         case JDWP_TAG(CHAR):
 544             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
 545                                                  request->instance,
 546                                                  request->method,
 547                                                  request->arguments);
 548             break;
 549 
 550         case JDWP_TAG(FLOAT):
 551             request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env,
 552                                                  request->instance,
 553                                                  request->method,
 554                                                  request->arguments);
 555             break;
 556 
 557         case JDWP_TAG(DOUBLE):
 558             request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env,
 559                                                  request->instance,
 560                                                  request->method,
 561                                                  request->arguments);
 562             break;
 563 
 564         case JDWP_TAG(INT):
 565             request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env,
 566                                                  request->instance,
 567                                                  request->method,
 568                                                  request->arguments);
 569             break;
 570 
 571         case JDWP_TAG(LONG):
 572             request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env,
 573                                                  request->instance,
 574                                                  request->method,
 575                                                  request->arguments);
 576             break;
 577 
 578         case JDWP_TAG(SHORT):
 579             request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env,
 580                                                  request->instance,
 581                                                  request->method,
 582                                                  request->arguments);
 583             break;
 584 
 585         case JDWP_TAG(BOOLEAN):
 586             request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env,
 587                                                  request->instance,
 588                                                  request->method,
 589                                                  request->arguments);
 590             break;
 591 
 592         case JDWP_TAG(VOID):
 593             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
 594                                     request->instance,
 595                                     request->method,
 596                                     request->arguments);
 597             break;
 598 
 599         default:
 600             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 601             break;
 602     }
 603 }
 604 
 605 static void
 606 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 607 {
 608     switch(returnTypeTag(request->methodSignature)) {
 609         case JDWP_TAG(OBJECT):
 610         case JDWP_TAG(ARRAY): {
 611             jobject object;
 612             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 613             JDI_ASSERT_MSG(request->instance, "Request instance null");
 614             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
 615                                            request->instance,
 616                                            request->clazz,
 617                                            request->method,
 618                                            request->arguments);
 619             request->returnValue.l = NULL;
 620             if (object != NULL) {
 621                 saveGlobalRef(env, object, &(request->returnValue.l));
 622             }
 623             break;
 624         }
 625 
 626         case JDWP_TAG(BYTE):
 627             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
 628                                                  request->instance,
 629                                                  request->clazz,
 630                                                  request->method,
 631                                                  request->arguments);
 632             break;
 633 
 634         case JDWP_TAG(CHAR):
 635             request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env,
 636                                                  request->instance,
 637                                                  request->clazz,
 638                                                  request->method,
 639                                                  request->arguments);
 640             break;
 641 
 642         case JDWP_TAG(FLOAT):
 643             request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env,
 644                                                  request->instance,
 645                                                  request->clazz,
 646                                                  request->method,
 647                                                  request->arguments);
 648             break;
 649 
 650         case JDWP_TAG(DOUBLE):
 651             request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env,
 652                                                  request->instance,
 653                                                  request->clazz,
 654                                                  request->method,
 655                                                  request->arguments);
 656             break;
 657 
 658         case JDWP_TAG(INT):
 659             request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env,
 660                                                  request->instance,
 661                                                  request->clazz,
 662                                                  request->method,
 663                                                  request->arguments);
 664             break;
 665 
 666         case JDWP_TAG(LONG):
 667             request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env,
 668                                                  request->instance,
 669                                                  request->clazz,
 670                                                  request->method,
 671                                                  request->arguments);
 672             break;
 673 
 674         case JDWP_TAG(SHORT):
 675             request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env,
 676                                                  request->instance,
 677                                                  request->clazz,
 678                                                  request->method,
 679                                                  request->arguments);
 680             break;
 681 
 682         case JDWP_TAG(BOOLEAN):
 683             request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env,
 684                                                  request->instance,
 685                                                  request->clazz,
 686                                                  request->method,
 687                                                  request->arguments);
 688             break;
 689 
 690         case JDWP_TAG(VOID):
 691             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
 692                                     request->instance,
 693                                     request->clazz,
 694                                     request->method,
 695                                     request->arguments);
 696             break;
 697 
 698         default:
 699             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 700             break;
 701     }
 702 }
 703 
 704 jboolean
 705 invoker_doInvoke(jthread thread)
 706 {
 707     JNIEnv *env;
 708     jboolean startNow;
 709     InvokeRequest *request;
 710     jbyte options;
 711     jbyte invokeType;
 712 
 713     JDI_ASSERT(thread);
 714 
 715     debugMonitorEnter(invokerLock);
 716 
 717     request = threadControl_getInvokeRequest(thread);
 718     if (request == NULL) {
 719         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 720     }
 721 
 722     request->available = JNI_FALSE;
 723     startNow = request->pending && !request->started;
 724 
 725     if (startNow) {
 726         request->started = JNI_TRUE;
 727     }
 728     options = request->options;
 729     invokeType = request->invokeType;
 730 
 731     debugMonitorExit(invokerLock);
 732 
 733     if (!startNow) {
 734         return JNI_FALSE;
 735     }
 736 
 737     env = getEnv();
 738 
 739     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
 740 
 741         jobject exception;
 742 
 743         JNI_FUNC_PTR(env,ExceptionClear)(env);
 744 
 745         switch (invokeType) {
 746             case INVOKE_CONSTRUCTOR:
 747                 invokeConstructor(env, request);
 748                 break;
 749             case INVOKE_STATIC:
 750                 invokeStatic(env, request);
 751                 break;
 752             case INVOKE_INSTANCE:
 753                 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
 754                     invokeNonvirtual(env, request);
 755                 } else {
 756                     invokeVirtual(env, request);
 757                 }
 758                 break;
 759             default:
 760                 JDI_ASSERT(JNI_FALSE);
 761         }
 762         request->exception = NULL;
 763         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
 764         if (exception != NULL) {
 765             JNI_FUNC_PTR(env,ExceptionClear)(env);
 766             saveGlobalRef(env, exception, &(request->exception));
 767         }
 768 
 769     } END_WITH_LOCAL_REFS(env);
 770 
 771     return JNI_TRUE;
 772 }
 773 
 774 void
 775 invoker_completeInvokeRequest(jthread thread)
 776 {
 777     JNIEnv *env = getEnv();
 778     PacketOutputStream out;
 779     jbyte tag;
 780     jobject exc;
 781     jvalue returnValue;
 782     jint id;
 783     InvokeRequest *request;
 784     jboolean detached;
 785 
 786     JDI_ASSERT(thread);
 787 
 788     /* Prevent gcc errors on uninitialized variables. */
 789     tag = 0;
 790     exc = NULL;
 791     id  = 0;
 792 
 793     eventHandler_lock(); /* for proper lock order */
 794     debugMonitorEnter(invokerLock);
 795 
 796     request = threadControl_getInvokeRequest(thread);
 797     if (request == NULL) {
 798         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 799     }
 800 
 801     JDI_ASSERT(request->pending);
 802     JDI_ASSERT(request->started);
 803 
 804     request->pending = JNI_FALSE;
 805     request->started = JNI_FALSE;
 806     request->available = JNI_TRUE; /* For next time around */
 807 
 808     detached = request->detached;
 809     if (!detached) {
 810         if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) {
 811             (void)threadControl_suspendThread(thread, JNI_FALSE);
 812         } else {
 813             (void)threadControl_suspendAll();
 814         }
 815 
 816         if (request->invokeType == INVOKE_CONSTRUCTOR) {
 817             /*
 818              * Although constructors technically have a return type of
 819              * void, we return the object created.
 820              */
 821             tag = specificTypeKey(env, request->returnValue.l);
 822         } else {
 823             tag = returnTypeTag(request->methodSignature);
 824         }
 825         id = request->id;
 826         exc = request->exception;
 827         returnValue = request->returnValue;
 828     }
 829 
 830     /*
 831      * At this time, there's no need to retain global references on
 832      * arguments since the reply is processed. No one will deal with
 833      * this request ID anymore, so we must call deleteGlobalArgumentRefs().
 834      *
 835      * We cannot delete saved exception or return value references
 836      * since otherwise a deleted handle would escape when writing
 837      * the response to the stream. Instead, we clean those refs up
 838      * after writing the respone.
 839      */
 840     deleteGlobalArgumentRefs(env, request);
 841 
 842     /*
 843      * Give up the lock before I/O operation
 844      */
 845     debugMonitorExit(invokerLock);
 846     eventHandler_unlock();
 847 
 848     if (!detached) {
 849         outStream_initReply(&out, id);
 850         (void)outStream_writeValue(env, &out, tag, returnValue);
 851         (void)outStream_writeObjectTag(env, &out, exc);
 852         (void)outStream_writeObjectRef(env, &out, exc);
 853         outStream_sendReply(&out);
 854     }
 855 
 856     /*
 857      * Delete potentially saved global references of return value
 858      * and exception
 859      */
 860     eventHandler_lock(); // for proper lock order
 861     debugMonitorEnter(invokerLock);
 862     deletePotentiallySavedGlobalRefs(env, request);
 863     debugMonitorExit(invokerLock);
 864     eventHandler_unlock();
 865 }
 866 
 867 jboolean
 868 invoker_isEnabled(jthread thread)
 869 {
 870     InvokeRequest *request;
 871     jboolean isEnabled;
 872 
 873     JDI_ASSERT(thread);
 874     debugMonitorEnter(invokerLock);
 875     request = threadControl_getInvokeRequest(thread);
 876     if (request == NULL) {
 877         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 878     }
 879     isEnabled = request->available;
 880     debugMonitorExit(invokerLock);
 881     return isEnabled;
 882 }
 883 
 884 void
 885 invoker_detach(InvokeRequest *request)
 886 {
 887     JDI_ASSERT(request);
 888     debugMonitorEnter(invokerLock);
 889     request->detached = JNI_TRUE;
 890     debugMonitorExit(invokerLock);
 891 }
--- EOF ---