1 /*
2 * Copyright (c) 1998, 2017, 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 global argument references from the request which got put there before a
216 * invoke request was carried out. See fillInvokeRequest().
217 */
218 static void
deleteGlobalArgumentRefs(JNIEnv * env,InvokeRequest * request)219 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
220 {
221 void *cursor;
222 jint argIndex = 0;
223 jvalue *argument = request->arguments;
224 jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
225
226 if (request->clazz != NULL) {
227 tossGlobalRef(env, &(request->clazz));
228 }
229 if (request->instance != NULL) {
230 tossGlobalRef(env, &(request->instance));
231 }
232 /* Delete global argument references */
233 while (argIndex < request->argumentCount) {
234 if ((argumentTag == JDWP_TAG(OBJECT)) ||
235 (argumentTag == JDWP_TAG(ARRAY))) {
236 if (argument->l != NULL) {
237 tossGlobalRef(env, &(argument->l));
238 }
239 }
240 argument++;
241 argIndex++;
242 argumentTag = nextArgumentTypeTag(&cursor);
243 }
244 }
245
246 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)247 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
248 jbyte invokeType, jbyte options, jint id,
249 jthread thread, jclass clazz, jmethodID method,
250 jobject instance,
251 jvalue *arguments, jint argumentCount)
252 {
253 jvmtiError error;
254 if (!request->available) {
255 /*
256 * Thread is not at a point where it can invoke.
257 */
258 return AGENT_ERROR_INVALID_THREAD;
259 }
260 if (request->pending) {
261 /*
262 * Pending invoke
263 */
264 return AGENT_ERROR_ALREADY_INVOKING;
265 }
266
267 request->invokeType = invokeType;
268 request->options = options;
269 request->detached = JNI_FALSE;
270 request->id = id;
271 request->clazz = clazz;
272 request->method = method;
273 request->instance = instance;
274 request->arguments = arguments;
275 request->arguments = arguments;
276 request->argumentCount = argumentCount;
277
278 request->returnValue.j = 0;
279 request->exception = 0;
280
281 /*
282 * Squirrel away the method signature
283 */
284 error = methodSignature(method, NULL, &request->methodSignature, NULL);
285 if (error != JVMTI_ERROR_NONE) {
286 return error;
287 }
288
289 /*
290 * The given references for class and instance are not guaranteed
291 * to be around long enough for invocation, so create new ones
292 * here.
293 */
294 error = createGlobalRefs(env, request);
295 if (error != JVMTI_ERROR_NONE) {
296 jvmtiDeallocate(request->methodSignature);
297 return error;
298 }
299
300 request->pending = JNI_TRUE;
301 request->available = JNI_FALSE;
302 return JVMTI_ERROR_NONE;
303 }
304
305 void
invoker_enableInvokeRequests(jthread thread)306 invoker_enableInvokeRequests(jthread thread)
307 {
308 InvokeRequest *request;
309
310 JDI_ASSERT(thread);
311
312 debugMonitorEnter(invokerLock);
313 request = threadControl_getInvokeRequest(thread);
314 if (request == NULL) {
315 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
316 }
317
318 request->available = JNI_TRUE;
319 debugMonitorExit(invokerLock);
320 }
321
322 /*
323 * Check that method is in the specified clazz or one of its super classes.
324 * We have to enforce this check at the JDWP layer because the JNI layer
325 * has different requirements.
326 */
check_methodClass(JNIEnv * env,jclass clazz,jmethodID method)327 static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method)
328 {
329 jclass containing_class = NULL;
330 jvmtiError error;
331
332 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
333 (gdata->jvmti, method, &containing_class);
334 if (error != JVMTI_ERROR_NONE) {
335 return JVMTI_ERROR_NONE; /* Bad jmethodID ? This will be handled elsewhere */
336 }
337
338 if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) {
339 return JVMTI_ERROR_NONE;
340 }
341
342 // If not the same class then check that containing_class is a superclass of
343 // clazz (not a superinterface).
344 if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) &&
345 referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) {
346 return JVMTI_ERROR_NONE;
347 }
348 return JVMTI_ERROR_INVALID_METHODID;
349 }
350
351 jvmtiError
invoker_requestInvoke(jbyte invokeType,jbyte options,jint id,jthread thread,jclass clazz,jmethodID method,jobject instance,jvalue * arguments,jint argumentCount)352 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
353 jthread thread, jclass clazz, jmethodID method,
354 jobject instance,
355 jvalue *arguments, jint argumentCount)
356 {
357 JNIEnv *env = getEnv();
358 InvokeRequest *request;
359 jvmtiError error = JVMTI_ERROR_NONE;
360
361 if (invokeType == INVOKE_STATIC) {
362 error = check_methodClass(env, clazz, method);
363 if (error != JVMTI_ERROR_NONE) {
364 return error;
365 }
366 }
367
368 debugMonitorEnter(invokerLock);
369 request = threadControl_getInvokeRequest(thread);
370 if (request != NULL) {
371 error = fillInvokeRequest(env, request, invokeType, options, id,
372 thread, clazz, method, instance,
373 arguments, argumentCount);
374 }
375 debugMonitorExit(invokerLock);
376
377 if (error == JVMTI_ERROR_NONE) {
378 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
379 /* true means it is okay to unblock the commandLoop thread */
380 (void)threadControl_resumeThread(thread, JNI_TRUE);
381 } else {
382 (void)threadControl_resumeAll();
383 }
384 }
385
386 return error;
387 }
388
389 static void
invokeConstructor(JNIEnv * env,InvokeRequest * request)390 invokeConstructor(JNIEnv *env, InvokeRequest *request)
391 {
392 jobject object;
393
394 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
395 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
396 request->method,
397 request->arguments);
398 request->returnValue.l = NULL;
399 if (object != NULL) {
400 saveGlobalRef(env, object, &(request->returnValue.l));
401 }
402 }
403
404 static void
invokeStatic(JNIEnv * env,InvokeRequest * request)405 invokeStatic(JNIEnv *env, InvokeRequest *request)
406 {
407 switch(returnTypeTag(request->methodSignature)) {
408 case JDWP_TAG(OBJECT):
409 case JDWP_TAG(ARRAY): {
410 jobject object;
411 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
412 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
413 request->clazz,
414 request->method,
415 request->arguments);
416 request->returnValue.l = NULL;
417 if (object != NULL) {
418 saveGlobalRef(env, object, &(request->returnValue.l));
419 }
420 break;
421 }
422
423
424 case JDWP_TAG(BYTE):
425 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
426 request->clazz,
427 request->method,
428 request->arguments);
429 break;
430
431 case JDWP_TAG(CHAR):
432 request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env,
433 request->clazz,
434 request->method,
435 request->arguments);
436 break;
437
438 case JDWP_TAG(FLOAT):
439 request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env,
440 request->clazz,
441 request->method,
442 request->arguments);
443 break;
444
445 case JDWP_TAG(DOUBLE):
446 request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env,
447 request->clazz,
448 request->method,
449 request->arguments);
450 break;
451
452 case JDWP_TAG(INT):
453 request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env,
454 request->clazz,
455 request->method,
456 request->arguments);
457 break;
458
459 case JDWP_TAG(LONG):
460 request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env,
461 request->clazz,
462 request->method,
463 request->arguments);
464 break;
465
466 case JDWP_TAG(SHORT):
467 request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env,
468 request->clazz,
469 request->method,
470 request->arguments);
471 break;
472
473 case JDWP_TAG(BOOLEAN):
474 request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env,
475 request->clazz,
476 request->method,
477 request->arguments);
478 break;
479
480 case JDWP_TAG(VOID):
481 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
482 request->clazz,
483 request->method,
484 request->arguments);
485 break;
486
487 default:
488 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
489 break;
490 }
491 }
492
493 static void
invokeVirtual(JNIEnv * env,InvokeRequest * request)494 invokeVirtual(JNIEnv *env, InvokeRequest *request)
495 {
496 switch(returnTypeTag(request->methodSignature)) {
497 case JDWP_TAG(OBJECT):
498 case JDWP_TAG(ARRAY): {
499 jobject object;
500 JDI_ASSERT_MSG(request->instance, "Request instance null");
501 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
502 request->instance,
503 request->method,
504 request->arguments);
505 request->returnValue.l = NULL;
506 if (object != NULL) {
507 saveGlobalRef(env, object, &(request->returnValue.l));
508 }
509 break;
510 }
511
512 case JDWP_TAG(BYTE):
513 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
514 request->instance,
515 request->method,
516 request->arguments);
517 break;
518
519 case JDWP_TAG(CHAR):
520 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
521 request->instance,
522 request->method,
523 request->arguments);
524 break;
525
526 case JDWP_TAG(FLOAT):
527 request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env,
528 request->instance,
529 request->method,
530 request->arguments);
531 break;
532
533 case JDWP_TAG(DOUBLE):
534 request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env,
535 request->instance,
536 request->method,
537 request->arguments);
538 break;
539
540 case JDWP_TAG(INT):
541 request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env,
542 request->instance,
543 request->method,
544 request->arguments);
545 break;
546
547 case JDWP_TAG(LONG):
548 request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env,
549 request->instance,
550 request->method,
551 request->arguments);
552 break;
553
554 case JDWP_TAG(SHORT):
555 request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env,
556 request->instance,
557 request->method,
558 request->arguments);
559 break;
560
561 case JDWP_TAG(BOOLEAN):
562 request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env,
563 request->instance,
564 request->method,
565 request->arguments);
566 break;
567
568 case JDWP_TAG(VOID):
569 JNI_FUNC_PTR(env,CallVoidMethodA)(env,
570 request->instance,
571 request->method,
572 request->arguments);
573 break;
574
575 default:
576 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
577 break;
578 }
579 }
580
581 static void
invokeNonvirtual(JNIEnv * env,InvokeRequest * request)582 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
583 {
584 switch(returnTypeTag(request->methodSignature)) {
585 case JDWP_TAG(OBJECT):
586 case JDWP_TAG(ARRAY): {
587 jobject object;
588 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
589 JDI_ASSERT_MSG(request->instance, "Request instance null");
590 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
591 request->instance,
592 request->clazz,
593 request->method,
594 request->arguments);
595 request->returnValue.l = NULL;
596 if (object != NULL) {
597 saveGlobalRef(env, object, &(request->returnValue.l));
598 }
599 break;
600 }
601
602 case JDWP_TAG(BYTE):
603 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
604 request->instance,
605 request->clazz,
606 request->method,
607 request->arguments);
608 break;
609
610 case JDWP_TAG(CHAR):
611 request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env,
612 request->instance,
613 request->clazz,
614 request->method,
615 request->arguments);
616 break;
617
618 case JDWP_TAG(FLOAT):
619 request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env,
620 request->instance,
621 request->clazz,
622 request->method,
623 request->arguments);
624 break;
625
626 case JDWP_TAG(DOUBLE):
627 request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env,
628 request->instance,
629 request->clazz,
630 request->method,
631 request->arguments);
632 break;
633
634 case JDWP_TAG(INT):
635 request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env,
636 request->instance,
637 request->clazz,
638 request->method,
639 request->arguments);
640 break;
641
642 case JDWP_TAG(LONG):
643 request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env,
644 request->instance,
645 request->clazz,
646 request->method,
647 request->arguments);
648 break;
649
650 case JDWP_TAG(SHORT):
651 request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env,
652 request->instance,
653 request->clazz,
654 request->method,
655 request->arguments);
656 break;
657
658 case JDWP_TAG(BOOLEAN):
659 request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env,
660 request->instance,
661 request->clazz,
662 request->method,
663 request->arguments);
664 break;
665
666 case JDWP_TAG(VOID):
667 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
668 request->instance,
669 request->clazz,
670 request->method,
671 request->arguments);
672 break;
673
674 default:
675 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
676 break;
677 }
678 }
679
680 jboolean
invoker_doInvoke(jthread thread)681 invoker_doInvoke(jthread thread)
682 {
683 JNIEnv *env;
684 jboolean startNow;
685 InvokeRequest *request;
686 jbyte options;
687 jbyte invokeType;
688
689 JDI_ASSERT(thread);
690
691 debugMonitorEnter(invokerLock);
692
693 request = threadControl_getInvokeRequest(thread);
694 if (request == NULL) {
695 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
696 }
697
698 request->available = JNI_FALSE;
699 startNow = request->pending && !request->started;
700
701 if (startNow) {
702 request->started = JNI_TRUE;
703 }
704 options = request->options;
705 invokeType = request->invokeType;
706
707 debugMonitorExit(invokerLock);
708
709 if (!startNow) {
710 return JNI_FALSE;
711 }
712
713 env = getEnv();
714
715 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */
716
717 jobject exception;
718
719 JNI_FUNC_PTR(env,ExceptionClear)(env);
720
721 switch (invokeType) {
722 case INVOKE_CONSTRUCTOR:
723 invokeConstructor(env, request);
724 break;
725 case INVOKE_STATIC:
726 invokeStatic(env, request);
727 break;
728 case INVOKE_INSTANCE:
729 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
730 invokeNonvirtual(env, request);
731 } else {
732 invokeVirtual(env, request);
733 }
734 break;
735 default:
736 JDI_ASSERT(JNI_FALSE);
737 }
738 request->exception = NULL;
739 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
740 if (exception != NULL) {
741 JNI_FUNC_PTR(env,ExceptionClear)(env);
742 saveGlobalRef(env, exception, &(request->exception));
743 }
744
745 } END_WITH_LOCAL_REFS(env);
746
747 return JNI_TRUE;
748 }
749
750 void
invoker_completeInvokeRequest(jthread thread)751 invoker_completeInvokeRequest(jthread thread)
752 {
753 JNIEnv *env = getEnv();
754 PacketOutputStream out;
755 jbyte tag;
756 jobject exc;
757 jvalue returnValue;
758 jint id;
759 InvokeRequest *request;
760 jboolean detached;
761 jboolean mustReleaseReturnValue = JNI_FALSE;
762
763 JDI_ASSERT(thread);
764
765 /* Prevent gcc errors on uninitialized variables. */
766 tag = 0;
767 exc = NULL;
768 id = 0;
769
770 eventHandler_lock(); /* for proper lock order */
771 debugMonitorEnter(invokerLock);
772
773 request = threadControl_getInvokeRequest(thread);
774 if (request == NULL) {
775 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
776 }
777
778 JDI_ASSERT(request->pending);
779 JDI_ASSERT(request->started);
780
781 request->pending = JNI_FALSE;
782 request->started = JNI_FALSE;
783 request->available = JNI_TRUE; /* For next time around */
784
785 detached = request->detached;
786 if (!detached) {
787 if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) {
788 (void)threadControl_suspendThread(thread, JNI_FALSE);
789 } else {
790 (void)threadControl_suspendAll();
791 }
792
793 if (request->invokeType == INVOKE_CONSTRUCTOR) {
794 /*
795 * Although constructors technically have a return type of
796 * void, we return the object created.
797 */
798 tag = specificTypeKey(env, request->returnValue.l);
799 } else {
800 tag = returnTypeTag(request->methodSignature);
801 }
802 id = request->id;
803 exc = request->exception;
804 returnValue = request->returnValue;
805
806 /* Release return value and exception references, but delay the release
807 * until after the return packet was sent. */
808 mustReleaseReturnValue = request->invokeType == INVOKE_CONSTRUCTOR ||
809 returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT) ||
810 returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY);
811 }
812
813 /*
814 * At this time, there's no need to retain global references on
815 * arguments since the reply is processed. No one will deal with
816 * this request ID anymore, so we must call deleteGlobalArgumentRefs().
817 *
818 * We cannot delete saved exception or return value references
819 * since otherwise a deleted handle would escape when writing
820 * the response to the stream. Instead, we clean those refs up
821 * after writing the respone.
822 */
823 deleteGlobalArgumentRefs(env, request);
824
825 /* From now on, do not access the request structure anymore
826 * for this request id, because once we give up the invokerLock it may
827 * be immediately reused by a new invoke request.
828 */
829 request = NULL;
830
831 /*
832 * Give up the lock before I/O operation
833 */
834 debugMonitorExit(invokerLock);
835 eventHandler_unlock();
836
837 if (!detached) {
838 outStream_initReply(&out, id);
839 (void)outStream_writeValue(env, &out, tag, returnValue);
840 (void)outStream_writeObjectTag(env, &out, exc);
841 (void)outStream_writeObjectRef(env, &out, exc);
842 outStream_sendReply(&out);
843 }
844
845 /*
846 * Delete potentially saved global references of return value
847 * and exception
848 */
849 eventHandler_lock(); // for proper lock order
850 debugMonitorEnter(invokerLock);
851 if (mustReleaseReturnValue && returnValue.l != NULL) {
852 tossGlobalRef(env, &returnValue.l);
853 }
854 if (exc != NULL) {
855 tossGlobalRef(env, &exc);
856 }
857 debugMonitorExit(invokerLock);
858 eventHandler_unlock();
859 }
860
861 jboolean
invoker_isEnabled(jthread thread)862 invoker_isEnabled(jthread thread)
863 {
864 InvokeRequest *request;
865 jboolean isEnabled;
866
867 JDI_ASSERT(thread);
868 debugMonitorEnter(invokerLock);
869 request = threadControl_getInvokeRequest(thread);
870 if (request == NULL) {
871 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
872 }
873 isEnabled = request->available;
874 debugMonitorExit(invokerLock);
875 return isEnabled;
876 }
877
878 void
invoker_detach(InvokeRequest * request)879 invoker_detach(InvokeRequest *request)
880 {
881 JDI_ASSERT(request);
882 debugMonitorEnter(invokerLock);
883 request->detached = JNI_TRUE;
884 debugMonitorExit(invokerLock);
885 }
886