775 lines
25 KiB
C
775 lines
25 KiB
C
/*
|
|
* Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Sun designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Sun in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
* have any questions.
|
|
*/
|
|
|
|
#include "util.h"
|
|
#include "invoker.h"
|
|
#include "eventHandler.h"
|
|
#include "threadControl.h"
|
|
#include "outStream.h"
|
|
|
|
static jrawMonitorID invokerLock;
|
|
|
|
void
|
|
invoker_initialize(void)
|
|
{
|
|
invokerLock = debugMonitorCreate("JDWP Invocation Lock");
|
|
}
|
|
|
|
void
|
|
invoker_reset(void)
|
|
{
|
|
}
|
|
|
|
void invoker_lock(void)
|
|
{
|
|
debugMonitorEnter(invokerLock);
|
|
}
|
|
|
|
void invoker_unlock(void)
|
|
{
|
|
debugMonitorExit(invokerLock);
|
|
}
|
|
|
|
static jbyte
|
|
returnTypeTag(char *signature)
|
|
{
|
|
char *tagPtr = strchr(signature, SIGNATURE_END_ARGS);
|
|
JDI_ASSERT(tagPtr);
|
|
tagPtr++; /* 1st character after the end of args */
|
|
return (jbyte)*tagPtr;
|
|
}
|
|
|
|
static jbyte
|
|
nextArgumentTypeTag(void **cursor)
|
|
{
|
|
char *tagPtr = *cursor;
|
|
jbyte argumentTag = (jbyte)*tagPtr;
|
|
|
|
if (*tagPtr != SIGNATURE_END_ARGS) {
|
|
/* Skip any array modifiers */
|
|
while (*tagPtr == JDWP_TAG(ARRAY)) {
|
|
tagPtr++;
|
|
}
|
|
/* Skip class name */
|
|
if (*tagPtr == JDWP_TAG(OBJECT)) {
|
|
tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1;
|
|
JDI_ASSERT(tagPtr);
|
|
} else {
|
|
/* Skip primitive sig */
|
|
tagPtr++;
|
|
}
|
|
}
|
|
|
|
*cursor = tagPtr;
|
|
return argumentTag;
|
|
}
|
|
|
|
static jbyte
|
|
firstArgumentTypeTag(char *signature, void **cursor)
|
|
{
|
|
JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS);
|
|
*cursor = signature + 1; /* skip to the first arg */
|
|
return nextArgumentTypeTag(cursor);
|
|
}
|
|
|
|
|
|
/*
|
|
* Note: argument refs may be destroyed on out-of-memory error
|
|
*/
|
|
static jvmtiError
|
|
createGlobalRefs(JNIEnv *env, InvokeRequest *request)
|
|
{
|
|
jvmtiError error;
|
|
jclass clazz = NULL;
|
|
jobject instance = NULL;
|
|
jint argIndex;
|
|
jbyte argumentTag;
|
|
jvalue *argument;
|
|
void *cursor;
|
|
jobject *argRefs = NULL;
|
|
|
|
error = JVMTI_ERROR_NONE;
|
|
|
|
if ( request->argumentCount > 0 ) {
|
|
/*LINTED*/
|
|
argRefs = jvmtiAllocate((jint)(request->argumentCount*sizeof(jobject)));
|
|
if ( argRefs==NULL ) {
|
|
error = AGENT_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
/*LINTED*/
|
|
(void)memset(argRefs, 0, request->argumentCount*sizeof(jobject));
|
|
}
|
|
}
|
|
|
|
if ( error == JVMTI_ERROR_NONE ) {
|
|
saveGlobalRef(env, request->clazz, &clazz);
|
|
if (clazz == NULL) {
|
|
error = AGENT_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
if ( error == JVMTI_ERROR_NONE && request->instance != NULL ) {
|
|
saveGlobalRef(env, request->instance, &instance);
|
|
if (instance == NULL) {
|
|
error = AGENT_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) {
|
|
argIndex = 0;
|
|
argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
|
|
argument = request->arguments;
|
|
while (argumentTag != SIGNATURE_END_ARGS) {
|
|
if ( argIndex > request->argumentCount ) {
|
|
break;
|
|
}
|
|
if ((argumentTag == JDWP_TAG(OBJECT)) ||
|
|
(argumentTag == JDWP_TAG(ARRAY))) {
|
|
/* Create a global ref for any non-null argument */
|
|
if (argument->l != NULL) {
|
|
saveGlobalRef(env, argument->l, &argRefs[argIndex]);
|
|
if (argRefs[argIndex] == NULL) {
|
|
error = AGENT_ERROR_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
argument++;
|
|
argIndex++;
|
|
argumentTag = nextArgumentTypeTag(&cursor);
|
|
}
|
|
}
|
|
|
|
#ifdef FIXUP /* Why isn't this an error? */
|
|
/* Make sure the argument count matches */
|
|
if ( error == JVMTI_ERROR_NONE && argIndex != request->argumentCount ) {
|
|
error = AGENT_ERROR_INVALID_COUNT;
|
|
}
|
|
#endif
|
|
|
|
/* Finally, put the global refs into the request if no errors */
|
|
if ( error == JVMTI_ERROR_NONE ) {
|
|
request->clazz = clazz;
|
|
request->instance = instance;
|
|
if ( argRefs!=NULL ) {
|
|
argIndex = 0;
|
|
argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
|
|
argument = request->arguments;
|
|
while ( argIndex < request->argumentCount ) {
|
|
if ((argumentTag == JDWP_TAG(OBJECT)) ||
|
|
(argumentTag == JDWP_TAG(ARRAY))) {
|
|
argument->l = argRefs[argIndex];
|
|
}
|
|
argument++;
|
|
argIndex++;
|
|
argumentTag = nextArgumentTypeTag(&cursor);
|
|
}
|
|
jvmtiDeallocate(argRefs);
|
|
}
|
|
return JVMTI_ERROR_NONE;
|
|
|
|
} else {
|
|
/* Delete global references */
|
|
if ( clazz != NULL ) {
|
|
tossGlobalRef(env, &clazz);
|
|
}
|
|
if ( instance != NULL ) {
|
|
tossGlobalRef(env, &instance);
|
|
}
|
|
if ( argRefs!=NULL ) {
|
|
for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) {
|
|
if ( argRefs[argIndex] != NULL ) {
|
|
tossGlobalRef(env, &argRefs[argIndex]);
|
|
}
|
|
}
|
|
jvmtiDeallocate(argRefs);
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static jvmtiError
|
|
fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
|
|
jbyte invokeType, jbyte options, jint id,
|
|
jthread thread, jclass clazz, jmethodID method,
|
|
jobject instance,
|
|
jvalue *arguments, jint argumentCount)
|
|
{
|
|
jvmtiError error;
|
|
if (!request->available) {
|
|
/*
|
|
* Thread is not at a point where it can invoke.
|
|
*/
|
|
return AGENT_ERROR_INVALID_THREAD;
|
|
}
|
|
if (request->pending) {
|
|
/*
|
|
* Pending invoke
|
|
*/
|
|
return AGENT_ERROR_ALREADY_INVOKING;
|
|
}
|
|
|
|
request->invokeType = invokeType;
|
|
request->options = options;
|
|
request->detached = JNI_FALSE;
|
|
request->id = id;
|
|
request->clazz = clazz;
|
|
request->method = method;
|
|
request->instance = instance;
|
|
request->arguments = arguments;
|
|
request->arguments = arguments;
|
|
request->argumentCount = argumentCount;
|
|
|
|
request->returnValue.j = 0;
|
|
request->exception = 0;
|
|
|
|
/*
|
|
* Squirrel away the method signature
|
|
*/
|
|
error = methodSignature(method, NULL, &request->methodSignature, NULL);
|
|
if (error != JVMTI_ERROR_NONE) {
|
|
return error;
|
|
}
|
|
|
|
/*
|
|
* The given references for class and instance are not guaranteed
|
|
* to be around long enough for invocation, so create new ones
|
|
* here.
|
|
*/
|
|
error = createGlobalRefs(env, request);
|
|
if (error != JVMTI_ERROR_NONE) {
|
|
jvmtiDeallocate(request->methodSignature);
|
|
return error;
|
|
}
|
|
|
|
request->pending = JNI_TRUE;
|
|
request->available = JNI_FALSE;
|
|
return JVMTI_ERROR_NONE;
|
|
}
|
|
|
|
void
|
|
invoker_enableInvokeRequests(jthread thread)
|
|
{
|
|
InvokeRequest *request;
|
|
|
|
JDI_ASSERT(thread);
|
|
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request == NULL) {
|
|
EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
|
|
}
|
|
|
|
request->available = JNI_TRUE;
|
|
}
|
|
|
|
jvmtiError
|
|
invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
|
|
jthread thread, jclass clazz, jmethodID method,
|
|
jobject instance,
|
|
jvalue *arguments, jint argumentCount)
|
|
{
|
|
JNIEnv *env = getEnv();
|
|
InvokeRequest *request;
|
|
jvmtiError error = JVMTI_ERROR_NONE;
|
|
|
|
debugMonitorEnter(invokerLock);
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request != NULL) {
|
|
error = fillInvokeRequest(env, request, invokeType, options, id,
|
|
thread, clazz, method, instance,
|
|
arguments, argumentCount);
|
|
}
|
|
debugMonitorExit(invokerLock);
|
|
|
|
if (error == JVMTI_ERROR_NONE) {
|
|
if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
|
|
/* true means it is okay to unblock the commandLoop thread */
|
|
(void)threadControl_resumeThread(thread, JNI_TRUE);
|
|
} else {
|
|
(void)threadControl_resumeAll();
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static void
|
|
invokeConstructor(JNIEnv *env, InvokeRequest *request)
|
|
{
|
|
jobject object;
|
|
object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
request->returnValue.l = NULL;
|
|
if (object != NULL) {
|
|
saveGlobalRef(env, object, &(request->returnValue.l));
|
|
}
|
|
}
|
|
|
|
static void
|
|
invokeStatic(JNIEnv *env, InvokeRequest *request)
|
|
{
|
|
switch(returnTypeTag(request->methodSignature)) {
|
|
case JDWP_TAG(OBJECT):
|
|
case JDWP_TAG(ARRAY): {
|
|
jobject object;
|
|
object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
request->returnValue.l = NULL;
|
|
if (object != NULL) {
|
|
saveGlobalRef(env, object, &(request->returnValue.l));
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case JDWP_TAG(BYTE):
|
|
request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(CHAR):
|
|
request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(FLOAT):
|
|
request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(DOUBLE):
|
|
request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(INT):
|
|
request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(LONG):
|
|
request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(SHORT):
|
|
request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(BOOLEAN):
|
|
request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(VOID):
|
|
JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
default:
|
|
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
invokeVirtual(JNIEnv *env, InvokeRequest *request)
|
|
{
|
|
switch(returnTypeTag(request->methodSignature)) {
|
|
case JDWP_TAG(OBJECT):
|
|
case JDWP_TAG(ARRAY): {
|
|
jobject object;
|
|
object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
request->returnValue.l = NULL;
|
|
if (object != NULL) {
|
|
saveGlobalRef(env, object, &(request->returnValue.l));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case JDWP_TAG(BYTE):
|
|
request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(CHAR):
|
|
request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(FLOAT):
|
|
request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(DOUBLE):
|
|
request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(INT):
|
|
request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(LONG):
|
|
request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(SHORT):
|
|
request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(BOOLEAN):
|
|
request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(VOID):
|
|
JNI_FUNC_PTR(env,CallVoidMethodA)(env,
|
|
request->instance,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
default:
|
|
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
|
|
{
|
|
switch(returnTypeTag(request->methodSignature)) {
|
|
case JDWP_TAG(OBJECT):
|
|
case JDWP_TAG(ARRAY): {
|
|
jobject object;
|
|
object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
request->returnValue.l = NULL;
|
|
if (object != NULL) {
|
|
saveGlobalRef(env, object, &(request->returnValue.l));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case JDWP_TAG(BYTE):
|
|
request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(CHAR):
|
|
request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(FLOAT):
|
|
request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(DOUBLE):
|
|
request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(INT):
|
|
request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(LONG):
|
|
request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(SHORT):
|
|
request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(BOOLEAN):
|
|
request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
case JDWP_TAG(VOID):
|
|
JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
|
|
request->instance,
|
|
request->clazz,
|
|
request->method,
|
|
request->arguments);
|
|
break;
|
|
|
|
default:
|
|
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
|
|
break;
|
|
}
|
|
}
|
|
|
|
jboolean
|
|
invoker_doInvoke(jthread thread)
|
|
{
|
|
JNIEnv *env;
|
|
jboolean startNow;
|
|
InvokeRequest *request;
|
|
|
|
JDI_ASSERT(thread);
|
|
|
|
debugMonitorEnter(invokerLock);
|
|
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request == NULL) {
|
|
EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
|
|
}
|
|
|
|
request->available = JNI_FALSE;
|
|
startNow = request->pending && !request->started;
|
|
|
|
if (startNow) {
|
|
request->started = JNI_TRUE;
|
|
}
|
|
debugMonitorExit(invokerLock);
|
|
|
|
if (!startNow) {
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
env = getEnv();
|
|
|
|
WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */
|
|
|
|
jobject exception;
|
|
|
|
JNI_FUNC_PTR(env,ExceptionClear)(env);
|
|
|
|
switch (request->invokeType) {
|
|
case INVOKE_CONSTRUCTOR:
|
|
invokeConstructor(env, request);
|
|
break;
|
|
case INVOKE_STATIC:
|
|
invokeStatic(env, request);
|
|
break;
|
|
case INVOKE_INSTANCE:
|
|
if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
|
|
invokeNonvirtual(env, request);
|
|
} else {
|
|
invokeVirtual(env, request);
|
|
}
|
|
break;
|
|
default:
|
|
JDI_ASSERT(JNI_FALSE);
|
|
}
|
|
request->exception = NULL;
|
|
exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
|
|
if (exception != NULL) {
|
|
JNI_FUNC_PTR(env,ExceptionClear)(env);
|
|
saveGlobalRef(env, exception, &(request->exception));
|
|
}
|
|
|
|
} END_WITH_LOCAL_REFS(env);
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
void
|
|
invoker_completeInvokeRequest(jthread thread)
|
|
{
|
|
JNIEnv *env = getEnv();
|
|
PacketOutputStream out;
|
|
jbyte tag;
|
|
jobject exc;
|
|
jvalue returnValue;
|
|
jint id;
|
|
InvokeRequest *request;
|
|
jboolean detached;
|
|
|
|
JDI_ASSERT(thread);
|
|
|
|
/* Prevent gcc errors on uninitialized variables. */
|
|
tag = 0;
|
|
exc = NULL;
|
|
id = 0;
|
|
|
|
eventHandler_lock(); /* for proper lock order */
|
|
debugMonitorEnter(invokerLock);
|
|
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request == NULL) {
|
|
EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
|
|
}
|
|
|
|
JDI_ASSERT(request->pending);
|
|
JDI_ASSERT(request->started);
|
|
|
|
request->pending = JNI_FALSE;
|
|
request->started = JNI_FALSE;
|
|
request->available = JNI_TRUE; /* For next time around */
|
|
|
|
detached = request->detached;
|
|
if (!detached) {
|
|
if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) {
|
|
(void)threadControl_suspendThread(thread, JNI_FALSE);
|
|
} else {
|
|
(void)threadControl_suspendAll();
|
|
}
|
|
|
|
if (request->invokeType == INVOKE_CONSTRUCTOR) {
|
|
/*
|
|
* Although constructors technically have a return type of
|
|
* void, we return the object created.
|
|
*/
|
|
tag = specificTypeKey(env, request->returnValue.l);
|
|
} else {
|
|
tag = returnTypeTag(request->methodSignature);
|
|
}
|
|
id = request->id;
|
|
exc = request->exception;
|
|
returnValue = request->returnValue;
|
|
}
|
|
|
|
/*
|
|
* Give up the lock before I/O operation
|
|
*/
|
|
debugMonitorExit(invokerLock);
|
|
eventHandler_unlock();
|
|
|
|
|
|
if (!detached) {
|
|
outStream_initReply(&out, id);
|
|
(void)outStream_writeValue(env, &out, tag, returnValue);
|
|
(void)outStream_writeObjectTag(env, &out, exc);
|
|
(void)outStream_writeObjectRef(env, &out, exc);
|
|
outStream_sendReply(&out);
|
|
}
|
|
}
|
|
|
|
jboolean
|
|
invoker_isPending(jthread thread)
|
|
{
|
|
InvokeRequest *request;
|
|
|
|
JDI_ASSERT(thread);
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request == NULL) {
|
|
EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
|
|
}
|
|
return request->pending;
|
|
}
|
|
|
|
jboolean
|
|
invoker_isEnabled(jthread thread)
|
|
{
|
|
InvokeRequest *request;
|
|
|
|
JDI_ASSERT(thread);
|
|
request = threadControl_getInvokeRequest(thread);
|
|
if (request == NULL) {
|
|
EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
|
|
}
|
|
return request->available;
|
|
}
|
|
|
|
void
|
|
invoker_detach(InvokeRequest *request)
|
|
{
|
|
JDI_ASSERT(request);
|
|
debugMonitorEnter(invokerLock);
|
|
request->detached = JNI_TRUE;
|
|
debugMonitorExit(invokerLock);
|
|
}
|