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