/* * Copyright (c) 1998, 2022, Oracle and/or its affiliates. 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) {
methodSignature_init(request->methodSignature, &cursor); while (methodSignature_nextArgumentExists(&cursor, &argumentTag)) { if ( argIndex > request->argumentCount ) { break;
} if (isReferenceTag(argumentTag)) { /* 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++;
}
}
#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;
methodSignature_init(request->methodSignature, &cursor);
argument = request->arguments; while ( methodSignature_nextArgumentExists(&cursor, &argumentTag) &&
argIndex < request->argumentCount ) { if ( isReferenceTag(argumentTag) ) {
argument->l = argRefs[argIndex];
}
argument++;
argIndex++;
}
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;
}
/* * Delete global argument references from the request which got put there before a * invoke request was carried out. See fillInvokeRequest().
*/ staticvoid
deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
{ void *cursor = NULL;
jint argIndex = 0;
jbyte argumentTag = 0;
jvalue *argument = request->arguments;
methodSignature_init(request->methodSignature, &cursor);
if (request->clazz != NULL) {
tossGlobalRef(env, &(request->clazz));
} if (request->instance != NULL) {
tossGlobalRef(env, &(request->instance));
} /* Delete global argument references */ while (methodSignature_nextArgumentExists(&cursor, &argumentTag) &&
argIndex < request->argumentCount) { if (isReferenceTag(argumentTag)) { if (argument->l != NULL) {
tossGlobalRef(env, &(argument->l));
}
}
argument++;
argIndex++;
}
}
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;
}
/* * Squirrel away the method signature
*/
JDI_ASSERT_MSG(request->methodSignature == NULL, "Request methodSignature not null");
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;
}
/* * Check that method is in the specified clazz or one of its super classes. * We have to enforce this check at the JDWP layer because the JNI layer * has different requirements.
*/ static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method)
{
jclass containing_class = NULL;
jvmtiError error;
error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
(gdata->jvmti, method, &containing_class); if (error != JVMTI_ERROR_NONE) { return JVMTI_ERROR_NONE; /* Bad jmethodID ? This will be handled elsewhere */
}
if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) { return JVMTI_ERROR_NONE;
}
// If not the same class then check that containing_class is a superclass of // clazz (not a superinterface). if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) &&
referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) { return JVMTI_ERROR_NONE;
} return JVMTI_ERROR_INVALID_METHODID;
}
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();
}
}
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 = methodSignature_returnTag(request->methodSignature);
}
id = request->id;
exc = request->exception;
request->exception = NULL;
returnValue = request->returnValue;
request->returnValue.l = NULL;
/* Release return value and exception references, but delay the release
* until after the return packet was sent. */
jbyte returnType = methodSignature_returnTag(request->methodSignature);
mustReleaseReturnValue = request->invokeType == INVOKE_CONSTRUCTOR ||
isReferenceTag(returnType);
}
/* * At this time, there's no need to retain global references on * arguments since the reply is processed. No one will deal with * this request ID anymore, so we must call deleteGlobalArgumentRefs(). * * We cannot delete saved exception or return value references * since otherwise a deleted handle would escape when writing * the response to the stream. Instead, we clean those refs up * after writing the respone.
*/
deleteGlobalArgumentRefs(env, request);
JDI_ASSERT_MSG(request->methodSignature != NULL, "methodSignature is NULL");
jvmtiDeallocate(request->methodSignature);
request->methodSignature = NULL;
/* From now on, do not access the request structure anymore * for this request id, because once we give up the invokerLock it may * be immediately reused by a new invoke request.
*/
request = NULL;
/* * 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); /* * Delete potentially saved global references for return value * and exception. This must be done before sending the reply or * these objects will briefly be viewable by the debugger as live * when they shouldn't be.
*/ if (mustReleaseReturnValue && returnValue.l != NULL) {
tossGlobalRef(env, &returnValue.l);
} if (exc != NULL) {
tossGlobalRef(env, &exc);
}
outStream_sendReply(&out);
outStream_destroy(&out);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.