1 /*
   2  * Copyright (c) 1998, 2019, 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 "ThreadReferenceImpl.h"
  28 #include "eventHandler.h"
  29 #include "threadControl.h"
  30 #include "inStream.h"
  31 #include "outStream.h"
  32 #include "FrameID.h"
  33 
  34 static jboolean
  35 name(PacketInputStream *in, PacketOutputStream *out)
  36 {
  37     JNIEnv *env;
  38     jthread thread;
  39 
  40     env = getEnv();
  41 
  42     thread = inStream_readThreadRef(env, in);
  43     if (inStream_error(in)) {
  44         return JNI_TRUE;
  45     }
  46 
  47     if (threadControl_isDebugThread(thread)) {
  48         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
  49         return JNI_TRUE;
  50     }
  51 
  52     WITH_LOCAL_REFS(env, 3) {
  53         jboolean is_fiber = isFiber(thread);
  54         if (!is_fiber) {
  55             /* Get the thread name */
  56             jvmtiThreadInfo info;
  57             jvmtiError error;
  58 
  59             (void)memset(&info, 0, sizeof(info));
  60             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
  61                 (gdata->jvmti, thread, &info);
  62 
  63             if (error != JVMTI_ERROR_NONE) {
  64                 outStream_setError(out, map2jdwpError(error));
  65             } else {
  66                 (void)outStream_writeString(out, info.name);
  67             }
  68 
  69             if ( info.name != NULL ) {
  70                 threadControl_setName(thread, info.name);
  71                 jvmtiDeallocate(info.name);
  72             }
  73         } else {
  74             /* Use Fiber.toString() instead of the Thread name. */
  75             jstring fiberName = JNI_FUNC_PTR(env,CallObjectMethod)
  76                 (env, thread, gdata->fiberToString);
  77             if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
  78                 JNI_FUNC_PTR(env,ExceptionClear)(env);
  79                 fiberName = NULL;
  80             }
  81 
  82             if (fiberName == NULL) {
  83                 (void)outStream_writeString(out, "<UNKNOWN FIBER>");
  84             } else {
  85                 const char *utf;
  86                 /* Get the UTF8 encoding for this fiberName string. */
  87                 utf = JNI_FUNC_PTR(env,GetStringUTFChars)(env, fiberName, NULL);
  88                 if (!(*env)->ExceptionCheck(env)) {
  89                     (void)outStream_writeString(out, (char*)utf);
  90                     threadControl_setName(thread, utf);
  91                     JNI_FUNC_PTR(env,ReleaseStringUTFChars)(env, fiberName, utf);
  92                 } else {
  93                     (void)outStream_writeString(out, "<UNKNOWN FIBER>");
  94                 }
  95             }
  96         }
  97 
  98     } END_WITH_LOCAL_REFS(env);
  99 
 100     return JNI_TRUE;
 101 }
 102 
 103 static jboolean
 104 suspend(PacketInputStream *in, PacketOutputStream *out)
 105 {
 106     jvmtiError error;
 107     jthread thread;
 108 
 109     thread = inStream_readThreadRef(getEnv(), in);
 110     if (inStream_error(in)) {
 111         return JNI_TRUE;
 112     }
 113 
 114     if (threadControl_isDebugThread(thread)) {
 115         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 116         return JNI_TRUE;
 117     }
 118     error = threadControl_suspendThread(thread, JNI_FALSE);
 119     if (error != JVMTI_ERROR_NONE) {
 120         outStream_setError(out, map2jdwpError(error));
 121     }
 122     return JNI_TRUE;
 123 }
 124 
 125 static jboolean
 126 resume(PacketInputStream *in, PacketOutputStream *out)
 127 {
 128     jvmtiError error;
 129     jthread thread;
 130 
 131     thread = inStream_readThreadRef(getEnv(), in);
 132     if (inStream_error(in)) {
 133         return JNI_TRUE;
 134     }
 135 
 136     if (threadControl_isDebugThread(thread)) {
 137         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 138         return JNI_TRUE;
 139     }
 140 
 141     /* true means it is okay to unblock the commandLoop thread */
 142     error = threadControl_resumeThread(thread, JNI_TRUE);
 143     if (error != JVMTI_ERROR_NONE) {
 144         outStream_setError(out, map2jdwpError(error));
 145     }
 146     return JNI_TRUE;
 147 }
 148 
 149 static jboolean
 150 status(PacketInputStream *in, PacketOutputStream *out)
 151 {
 152     jdwpThreadStatus threadStatus;
 153     jint statusFlags;
 154     jvmtiError error;
 155     jthread thread;
 156 
 157     thread = inStream_readThreadRef(getEnv(), in);
 158     if (inStream_error(in)) {
 159         return JNI_TRUE;
 160     }
 161 
 162     if (threadControl_isDebugThread(thread)) {
 163         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 164         return JNI_TRUE;
 165     }
 166 
 167     error = threadControl_applicationThreadStatus(thread, &threadStatus,
 168                                                           &statusFlags);
 169     if (error != JVMTI_ERROR_NONE) {
 170         outStream_setError(out, map2jdwpError(error));
 171         return JNI_TRUE;
 172     }
 173     (void)outStream_writeInt(out, threadStatus);
 174     (void)outStream_writeInt(out, statusFlags);
 175     return JNI_TRUE;
 176 }
 177 
 178 static jboolean
 179 threadGroup(PacketInputStream *in, PacketOutputStream *out)
 180 {
 181     JNIEnv *env;
 182     jthread thread;
 183 
 184     env = getEnv();
 185 
 186     thread = inStream_readThreadRef(env, in);
 187     if (inStream_error(in)) {
 188         return JNI_TRUE;
 189     }
 190 
 191     if (threadControl_isDebugThread(thread)) {
 192         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 193         return JNI_TRUE;
 194     }
 195 
 196     WITH_LOCAL_REFS(env, 1) {
 197 
 198         jvmtiThreadInfo info;
 199         jvmtiError error;
 200         jboolean is_fiber = isFiber(thread);
 201         
 202         if (is_fiber) {
 203             /* If it's a fiber, use the well known thread group for Fibers. */
 204             JDI_ASSERT(gdata->fiberThreadGroup != NULL);
 205             (void)outStream_writeObjectRef(env, out, gdata->fiberThreadGroup);
 206         } else {
 207             (void)memset(&info, 0, sizeof(info));
 208             error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
 209                                       (gdata->jvmti, thread, &info);
 210 
 211             if (error != JVMTI_ERROR_NONE) {
 212                 outStream_setError(out, map2jdwpError(error));
 213             } else {
 214                 (void)outStream_writeObjectRef(env, out, info.thread_group);
 215             }
 216 
 217             if ( info.name!=NULL )
 218                 jvmtiDeallocate(info.name);
 219         }
 220 
 221     } END_WITH_LOCAL_REFS(env);
 222 
 223     return JNI_TRUE;
 224 }
 225 
 226 /*
 227  * Validate that the thread or fiber is suspended, and returns a thread that can
 228  * be used for stack operations, even for unmounted fibers.
 229  */
 230 static jthread
 231 validateSuspendedThread(PacketOutputStream *out, jthread thread)
 232 {
 233     jvmtiError error;
 234     jint count;
 235     jthread result = thread;
 236 
 237     error = threadControl_suspendCount(thread, &count);
 238     if (error != JVMTI_ERROR_NONE) {
 239         outStream_setError(out, map2jdwpError(error));
 240         return NULL;
 241     }
 242 
 243     if (count == 0) {
 244         outStream_setError(out, JDWP_ERROR(THREAD_NOT_SUSPENDED));
 245         return NULL;
 246     }
 247 
 248     if (isFiber(thread)) {
 249         /* Make sure the Fiber is mounted on a thread that we can do stack operations on. */
 250         result = threadControl_getFiberCarrierOrHelperThread(thread);
 251         if (result == NULL) {
 252             /* fiber fixme: this should never happen once we get proper unmounted fiber supported. */
 253             (void)outStream_writeInt(out, 0);
 254         }
 255     }
 256 
 257     return result;
 258 }
 259 
 260 static jboolean
 261 frames(PacketInputStream *in, PacketOutputStream *out)
 262 {
 263     jvmtiError error;
 264     FrameNumber index;
 265     jint count;
 266     jint filledIn;
 267     JNIEnv *env;
 268     jthread thread;
 269     jint startIndex;
 270     jint length;
 271     jvmtiFrameInfo* frames;
 272     jthread originalThread;
 273 
 274     env = getEnv();
 275 
 276     thread = inStream_readThreadRef(env, in);
 277     originalThread = thread;
 278     if (inStream_error(in)) {
 279         return JNI_TRUE;
 280     }
 281     startIndex = inStream_readInt(in);
 282     if (inStream_error(in)) {
 283         return JNI_TRUE;
 284     }
 285     length = inStream_readInt(in);
 286     if (inStream_error(in)) {
 287         return JNI_TRUE;
 288     }
 289 
 290     if (threadControl_isDebugThread(thread)) {
 291         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 292         return JNI_TRUE;
 293     }
 294 
 295     thread = validateSuspendedThread(out, thread);
 296     if (thread == NULL) {
 297         return JNI_TRUE;
 298     }
 299 
 300     error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
 301                         (gdata->jvmti, thread, &count);
 302     if (error != JVMTI_ERROR_NONE) {
 303         outStream_setError(out, map2jdwpError(error));
 304         return JNI_TRUE;
 305     }
 306 
 307     if (length == -1) {
 308         length = count - startIndex;
 309     }
 310 
 311     if (length == 0) {
 312         (void)outStream_writeInt(out, 0);
 313         return JNI_TRUE;
 314     }
 315 
 316     if ((startIndex < 0) || (startIndex > count - 1)) {
 317         outStream_setError(out, JDWP_ERROR(INVALID_INDEX));
 318         return JNI_TRUE;
 319     }
 320 
 321     if ((length < 0) || (length + startIndex > count)) {
 322         outStream_setError(out, JDWP_ERROR(INVALID_LENGTH));
 323         return JNI_TRUE;
 324     }
 325 
 326     (void)outStream_writeInt(out, length);
 327 
 328     frames = jvmtiAllocate(sizeof(jvmtiFrameInfo) * length);
 329 
 330     if (frames == NULL) {
 331         outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
 332         return JNI_TRUE;
 333     }
 334 
 335     error = JVMTI_FUNC_PTR(gdata->jvmti, GetStackTrace)
 336                           (gdata->jvmti, thread, startIndex, length, frames,
 337                            &filledIn);
 338 
 339     /* Should not happen. */
 340     if (error == JVMTI_ERROR_NONE && length != filledIn) {
 341         error = JVMTI_ERROR_INTERNAL;
 342     }
 343 
 344     for (index = 0; index < filledIn && error == JVMTI_ERROR_NONE; ++index) {
 345         WITH_LOCAL_REFS(env, 1) {
 346             jclass clazz;
 347             error = methodClass(frames[index].method, &clazz);
 348 
 349             if (error == JVMTI_ERROR_NONE) {
 350                 FrameID frame = createFrameID(originalThread, index + startIndex);
 351                 outStream_writeFrameID(out, frame);
 352                 writeCodeLocation(out, clazz, frames[index].method,
 353                                   frames[index].location);
 354             }
 355         } END_WITH_LOCAL_REFS(env);
 356     }
 357 
 358     jvmtiDeallocate(frames);
 359 
 360     if (error != JVMTI_ERROR_NONE) {
 361         outStream_setError(out, map2jdwpError(error));
 362     }
 363     return JNI_TRUE;
 364 }
 365 
 366 static jboolean
 367 getFrameCount(PacketInputStream *in, PacketOutputStream *out)
 368 {
 369     jvmtiError error;
 370     jint count;
 371     jthread thread;
 372 
 373     thread = inStream_readThreadRef(getEnv(), in);
 374     if (inStream_error(in)) {
 375         return JNI_TRUE;
 376     }
 377 
 378     if (threadControl_isDebugThread(thread)) {
 379         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 380         return JNI_TRUE;
 381     }
 382 
 383     thread = validateSuspendedThread(out, thread);
 384     if (thread == NULL) {
 385         return JNI_TRUE;
 386     }
 387 
 388     error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
 389                         (gdata->jvmti, thread, &count);
 390     if (error != JVMTI_ERROR_NONE) {
 391         outStream_setError(out, map2jdwpError(error));
 392         return JNI_TRUE;
 393     }
 394     (void)outStream_writeInt(out, count);
 395 
 396     return JNI_TRUE;
 397 }
 398 
 399 static jboolean
 400 ownedMonitors(PacketInputStream *in, PacketOutputStream *out)
 401 {
 402     JNIEnv *env;
 403     jthread thread;
 404 
 405     env = getEnv();
 406 
 407     thread = inStream_readThreadRef(env, in);
 408     if (inStream_error(in)) {
 409         return JNI_TRUE;
 410     }
 411 
 412     if (threadControl_isDebugThread(thread)) {
 413         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 414         return JNI_TRUE;
 415     }
 416 
 417     thread = validateSuspendedThread(out, thread);
 418     if (thread == NULL) {
 419         return JNI_TRUE;
 420     }
 421 
 422     WITH_LOCAL_REFS(env, 1) {
 423 
 424         jvmtiError error;
 425         jint count = 0;
 426         jobject *monitors = NULL;
 427 
 428         error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorInfo)
 429                                 (gdata->jvmti, thread, &count, &monitors);
 430         if (error != JVMTI_ERROR_NONE) {
 431             outStream_setError(out, map2jdwpError(error));
 432         } else {
 433             int i;
 434             (void)outStream_writeInt(out, count);
 435             for (i = 0; i < count; i++) {
 436                 jobject monitor = monitors[i];
 437                 (void)outStream_writeByte(out, specificTypeKey(env, monitor));
 438                 (void)outStream_writeObjectRef(env, out, monitor);
 439             }
 440         }
 441         if (monitors != NULL)
 442             jvmtiDeallocate(monitors);
 443 
 444     } END_WITH_LOCAL_REFS(env);
 445 
 446     return JNI_TRUE;
 447 }
 448 
 449 static jboolean
 450 currentContendedMonitor(PacketInputStream *in, PacketOutputStream *out)
 451 {
 452     JNIEnv *env;
 453     jthread thread;
 454 
 455     env = getEnv();
 456 
 457     thread = inStream_readThreadRef(env, in);
 458     if (inStream_error(in)) {
 459         return JNI_TRUE;
 460     }
 461 
 462     if (thread == NULL || threadControl_isDebugThread(thread)) {
 463         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 464         return JNI_TRUE;
 465     }
 466 
 467     thread = validateSuspendedThread(out, thread);
 468     if (thread == NULL) {
 469         return JNI_TRUE;
 470     }
 471 
 472     WITH_LOCAL_REFS(env, 1) {
 473 
 474         jobject monitor;
 475         jvmtiError error;
 476 
 477         error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentContendedMonitor)
 478                                 (gdata->jvmti, thread, &monitor);
 479 
 480         if (error != JVMTI_ERROR_NONE) {
 481             outStream_setError(out, map2jdwpError(error));
 482         } else {
 483             (void)outStream_writeByte(out, specificTypeKey(env, monitor));
 484             (void)outStream_writeObjectRef(env, out, monitor);
 485         }
 486 
 487     } END_WITH_LOCAL_REFS(env);
 488 
 489     return JNI_TRUE;
 490 }
 491 
 492 static jboolean
 493 stop(PacketInputStream *in, PacketOutputStream *out)
 494 {
 495     jvmtiError error;
 496     jthread thread;
 497     jobject throwable;
 498     JNIEnv *env;
 499 
 500     env = getEnv();
 501     thread = inStream_readThreadRef(env, in);
 502     if (inStream_error(in)) {
 503         return JNI_TRUE;
 504     }
 505     throwable = inStream_readObjectRef(env, in);
 506     if (inStream_error(in)) {
 507         return JNI_TRUE;
 508     }
 509 
 510     if (threadControl_isDebugThread(thread)) {
 511         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 512         return JNI_TRUE;
 513     }
 514 
 515     /* fiber fixme: add fiber support */
 516     if (isFiber(thread)) {
 517         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 518         return JNI_TRUE;
 519     }
 520 
 521     error = threadControl_stop(thread, throwable);
 522     if (error != JVMTI_ERROR_NONE) {
 523         outStream_setError(out, map2jdwpError(error));
 524     }
 525     return JNI_TRUE;
 526 }
 527 
 528 static jboolean
 529 interrupt(PacketInputStream *in, PacketOutputStream *out)
 530 {
 531     jvmtiError error;
 532     jthread thread;
 533 
 534     thread = inStream_readThreadRef(getEnv(), in);
 535     if (inStream_error(in)) {
 536         return JNI_TRUE;
 537     }
 538 
 539     if (threadControl_isDebugThread(thread)) {
 540         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 541         return JNI_TRUE;
 542     }
 543 
 544     /* fiber fixme: add fiber support */
 545     if (isFiber(thread)) {
 546         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 547         return JNI_TRUE;
 548     }
 549 
 550     error = threadControl_interrupt(thread);
 551     if (error != JVMTI_ERROR_NONE) {
 552         outStream_setError(out, map2jdwpError(error));
 553     }
 554     return JNI_TRUE;
 555 }
 556 
 557 static jboolean
 558 suspendCount(PacketInputStream *in, PacketOutputStream *out)
 559 {
 560     jvmtiError error;
 561     jint count;
 562     jthread thread;
 563 
 564     thread = inStream_readThreadRef(getEnv(), in);
 565     if (inStream_error(in)) {
 566         return JNI_TRUE;
 567     }
 568 
 569     if (threadControl_isDebugThread(thread)) {
 570         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 571         return JNI_TRUE;
 572     }
 573 
 574     error = threadControl_suspendCount(thread, &count);
 575     if (error != JVMTI_ERROR_NONE) {
 576         outStream_setError(out, map2jdwpError(error));
 577         return JNI_TRUE;
 578     }
 579 
 580     (void)outStream_writeInt(out, count);
 581     return JNI_TRUE;
 582 }
 583 
 584 static jboolean
 585 ownedMonitorsWithStackDepth(PacketInputStream *in, PacketOutputStream *out)
 586 {
 587     JNIEnv *env;
 588     jthread thread;
 589 
 590     thread = inStream_readThreadRef(getEnv(), in);
 591     if (inStream_error(in)) {
 592         return JNI_TRUE;
 593     }
 594 
 595     if (thread == NULL || threadControl_isDebugThread(thread)) {
 596         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 597         return JNI_TRUE;
 598     }
 599 
 600     thread = validateSuspendedThread(out, thread);
 601     if (thread == NULL) {
 602         return JNI_TRUE;
 603     }
 604 
 605     env = getEnv();
 606 
 607     WITH_LOCAL_REFS(env, 1) {
 608 
 609         jvmtiError error = JVMTI_ERROR_NONE;
 610         jint count = 0;
 611         jvmtiMonitorStackDepthInfo *monitors=NULL;
 612 
 613         error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorStackDepthInfo)
 614                                 (gdata->jvmti, thread, &count, &monitors);
 615 
 616         if (error != JVMTI_ERROR_NONE) {
 617             outStream_setError(out, map2jdwpError(error));
 618         } else {
 619             int i;
 620             (void)outStream_writeInt(out, count);
 621             for (i = 0; i < count; i++) {
 622                 jobject monitor = monitors[i].monitor;
 623                 (void)outStream_writeByte(out, specificTypeKey(env, monitor));
 624                 (void)outStream_writeObjectRef(getEnv(), out, monitor);
 625                 (void)outStream_writeInt(out,monitors[i].stack_depth);
 626             }
 627         }
 628         if (monitors != NULL) {
 629             jvmtiDeallocate(monitors);
 630         }
 631 
 632     } END_WITH_LOCAL_REFS(env);
 633 
 634     return JNI_TRUE;
 635 }
 636 
 637 static jboolean
 638 forceEarlyReturn(PacketInputStream *in, PacketOutputStream *out)
 639 {
 640     JNIEnv *env;
 641     jthread thread;
 642     jvalue value;
 643     jbyte typeKey;
 644     jvmtiError error;
 645 
 646     env = getEnv();
 647     thread = inStream_readThreadRef(env, in);
 648     if (inStream_error(in)) {
 649         return JNI_TRUE;
 650     }
 651 
 652     if (threadControl_isDebugThread(thread)) {
 653         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 654         return JNI_TRUE;
 655     }
 656 
 657     /* fiber fixme: add fiber support */
 658     if (isFiber(thread)) {
 659         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 660         return JNI_TRUE;
 661     }
 662 
 663     typeKey = inStream_readByte(in);
 664     if (inStream_error(in)) {
 665         return JNI_TRUE;
 666     }
 667 
 668     if (isObjectTag(typeKey)) {
 669         value.l = inStream_readObjectRef(env, in);
 670         error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnObject)
 671                         (gdata->jvmti, thread, value.l);
 672     } else {
 673         switch (typeKey) {
 674             case JDWP_TAG(VOID):
 675                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnVoid)
 676                                 (gdata->jvmti, thread);
 677                 break;
 678             case JDWP_TAG(BYTE):
 679                 value.b = inStream_readByte(in);
 680                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
 681                                 (gdata->jvmti, thread, value.b);
 682                 break;
 683 
 684             case JDWP_TAG(CHAR):
 685                 value.c = inStream_readChar(in);
 686                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
 687                                 (gdata->jvmti, thread, value.c);
 688                 break;
 689 
 690             case JDWP_TAG(FLOAT):
 691                 value.f = inStream_readFloat(in);
 692                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnFloat)
 693                                 (gdata->jvmti, thread, value.f);
 694                 break;
 695 
 696             case JDWP_TAG(DOUBLE):
 697                 value.d = inStream_readDouble(in);
 698                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnDouble)
 699                                 (gdata->jvmti, thread, value.d);
 700                 break;
 701 
 702             case JDWP_TAG(INT):
 703                 value.i = inStream_readInt(in);
 704                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
 705                                 (gdata->jvmti, thread, value.i);
 706                 break;
 707 
 708             case JDWP_TAG(LONG):
 709                 value.j = inStream_readLong(in);
 710                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnLong)
 711                                 (gdata->jvmti, thread, value.j);
 712                 break;
 713 
 714             case JDWP_TAG(SHORT):
 715                 value.s = inStream_readShort(in);
 716                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
 717                                 (gdata->jvmti, thread, value.s);
 718                 break;
 719 
 720             case JDWP_TAG(BOOLEAN):
 721                 value.z = inStream_readBoolean(in);
 722                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
 723                                 (gdata->jvmti, thread, value.z);
 724                 break;
 725 
 726             default:
 727                 error =  AGENT_ERROR_INVALID_TAG;
 728                 break;
 729         }
 730     }
 731     {
 732       jdwpError serror = map2jdwpError(error);
 733       if (serror != JDWP_ERROR(NONE)) {
 734         outStream_setError(out, serror);
 735       }
 736     }
 737     return JNI_TRUE;
 738 }
 739 
 740 
 741 void *ThreadReference_Cmds[] = { (void *)14,
 742     (void *)name,
 743     (void *)suspend,
 744     (void *)resume,
 745     (void *)status,
 746     (void *)threadGroup,
 747     (void *)frames,
 748     (void *)getFrameCount,
 749     (void *)ownedMonitors,
 750     (void *)currentContendedMonitor,
 751     (void *)stop,
 752     (void *)interrupt,
 753     (void *)suspendCount,
 754     (void *)ownedMonitorsWithStackDepth,
 755     (void *)forceEarlyReturn
 756     };