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