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