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 static jvmtiError
215 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
216 jbyte invokeType, jbyte options, jint id,
217 jthread thread, jclass clazz, jmethodID method,
218 jobject instance,
219 jvalue *arguments, jint argumentCount)
220 {
221 jvmtiError error;
222 if (!request->available) {
223 /*
224 * Thread is not at a point where it can invoke.
225 */
226 return AGENT_ERROR_INVALID_THREAD;
227 }
228 if (request->pending) {
229 /*
230 * Pending invoke
231 */
232 return AGENT_ERROR_ALREADY_INVOKING;
233 }
305 arguments, argumentCount);
306 }
307 debugMonitorExit(invokerLock);
308
309 if (error == JVMTI_ERROR_NONE) {
310 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
311 /* true means it is okay to unblock the commandLoop thread */
312 (void)threadControl_resumeThread(thread, JNI_TRUE);
313 } else {
314 (void)threadControl_resumeAll();
315 }
316 }
317
318 return error;
319 }
320
321 static void
322 invokeConstructor(JNIEnv *env, InvokeRequest *request)
323 {
324 jobject object;
325 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
326 request->method,
327 request->arguments);
328 request->returnValue.l = NULL;
329 if (object != NULL) {
330 saveGlobalRef(env, object, &(request->returnValue.l));
331 }
332 }
333
334 static void
335 invokeStatic(JNIEnv *env, InvokeRequest *request)
336 {
337 switch(returnTypeTag(request->methodSignature)) {
338 case JDWP_TAG(OBJECT):
339 case JDWP_TAG(ARRAY): {
340 jobject object;
341 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
342 request->clazz,
343 request->method,
344 request->arguments);
345 request->returnValue.l = NULL;
346 if (object != NULL) {
347 saveGlobalRef(env, object, &(request->returnValue.l));
348 }
349 break;
350 }
351
352
353 case JDWP_TAG(BYTE):
354 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
355 request->clazz,
356 request->method,
357 request->arguments);
358 break;
359
360 case JDWP_TAG(CHAR):
409 case JDWP_TAG(VOID):
410 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
411 request->clazz,
412 request->method,
413 request->arguments);
414 break;
415
416 default:
417 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
418 break;
419 }
420 }
421
422 static void
423 invokeVirtual(JNIEnv *env, InvokeRequest *request)
424 {
425 switch(returnTypeTag(request->methodSignature)) {
426 case JDWP_TAG(OBJECT):
427 case JDWP_TAG(ARRAY): {
428 jobject object;
429 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
430 request->instance,
431 request->method,
432 request->arguments);
433 request->returnValue.l = NULL;
434 if (object != NULL) {
435 saveGlobalRef(env, object, &(request->returnValue.l));
436 }
437 break;
438 }
439
440 case JDWP_TAG(BYTE):
441 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
442 request->instance,
443 request->method,
444 request->arguments);
445 break;
446
447 case JDWP_TAG(CHAR):
448 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
496 case JDWP_TAG(VOID):
497 JNI_FUNC_PTR(env,CallVoidMethodA)(env,
498 request->instance,
499 request->method,
500 request->arguments);
501 break;
502
503 default:
504 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
505 break;
506 }
507 }
508
509 static void
510 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
511 {
512 switch(returnTypeTag(request->methodSignature)) {
513 case JDWP_TAG(OBJECT):
514 case JDWP_TAG(ARRAY): {
515 jobject object;
516 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
517 request->instance,
518 request->clazz,
519 request->method,
520 request->arguments);
521 request->returnValue.l = NULL;
522 if (object != NULL) {
523 saveGlobalRef(env, object, &(request->returnValue.l));
524 }
525 break;
526 }
527
528 case JDWP_TAG(BYTE):
529 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
530 request->instance,
531 request->clazz,
532 request->method,
533 request->arguments);
534 break;
535
592 case JDWP_TAG(VOID):
593 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
594 request->instance,
595 request->clazz,
596 request->method,
597 request->arguments);
598 break;
599
600 default:
601 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
602 break;
603 }
604 }
605
606 jboolean
607 invoker_doInvoke(jthread thread)
608 {
609 JNIEnv *env;
610 jboolean startNow;
611 InvokeRequest *request;
612
613 JDI_ASSERT(thread);
614
615 debugMonitorEnter(invokerLock);
616
617 request = threadControl_getInvokeRequest(thread);
618 if (request == NULL) {
619 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
620 }
621
622 request->available = JNI_FALSE;
623 startNow = request->pending && !request->started;
624
625 if (startNow) {
626 request->started = JNI_TRUE;
627 }
628 debugMonitorExit(invokerLock);
629
630 if (!startNow) {
631 return JNI_FALSE;
632 }
633
634 env = getEnv();
635
636 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */
637
638 jobject exception;
639
640 JNI_FUNC_PTR(env,ExceptionClear)(env);
641
642 switch (request->invokeType) {
643 case INVOKE_CONSTRUCTOR:
644 invokeConstructor(env, request);
645 break;
646 case INVOKE_STATIC:
647 invokeStatic(env, request);
648 break;
649 case INVOKE_INSTANCE:
650 if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
651 invokeNonvirtual(env, request);
652 } else {
653 invokeVirtual(env, request);
654 }
655 break;
656 default:
657 JDI_ASSERT(JNI_FALSE);
658 }
659 request->exception = NULL;
660 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
661 if (exception != NULL) {
662 JNI_FUNC_PTR(env,ExceptionClear)(env);
663 saveGlobalRef(env, exception, &(request->exception));
664 }
665
666 } END_WITH_LOCAL_REFS(env);
667
668 return JNI_TRUE;
669 }
670
708 (void)threadControl_suspendThread(thread, JNI_FALSE);
709 } else {
710 (void)threadControl_suspendAll();
711 }
712
713 if (request->invokeType == INVOKE_CONSTRUCTOR) {
714 /*
715 * Although constructors technically have a return type of
716 * void, we return the object created.
717 */
718 tag = specificTypeKey(env, request->returnValue.l);
719 } else {
720 tag = returnTypeTag(request->methodSignature);
721 }
722 id = request->id;
723 exc = request->exception;
724 returnValue = request->returnValue;
725 }
726
727 /*
728 * Give up the lock before I/O operation
729 */
730 debugMonitorExit(invokerLock);
731 eventHandler_unlock();
732
733
734 if (!detached) {
735 outStream_initReply(&out, id);
736 (void)outStream_writeValue(env, &out, tag, returnValue);
737 (void)outStream_writeObjectTag(env, &out, exc);
738 (void)outStream_writeObjectRef(env, &out, exc);
739 outStream_sendReply(&out);
740 }
741 }
742
743 jboolean
744 invoker_isEnabled(jthread thread)
745 {
746 InvokeRequest *request;
747 jboolean isEnabled;
748
749 JDI_ASSERT(thread);
750 debugMonitorEnter(invokerLock);
751 request = threadControl_getInvokeRequest(thread);
752 if (request == NULL) {
753 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
754 }
755 isEnabled = request->available;
756 debugMonitorExit(invokerLock);
757 return isEnabled;
758 }
759
760 void
|
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
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
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 }
337 arguments, argumentCount);
338 }
339 debugMonitorExit(invokerLock);
340
341 if (error == JVMTI_ERROR_NONE) {
342 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
343 /* true means it is okay to unblock the commandLoop thread */
344 (void)threadControl_resumeThread(thread, JNI_TRUE);
345 } else {
346 (void)threadControl_resumeAll();
347 }
348 }
349
350 return error;
351 }
352
353 static void
354 invokeConstructor(JNIEnv *env, InvokeRequest *request)
355 {
356 jobject object;
357
358 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
359 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
360 request->method,
361 request->arguments);
362 request->returnValue.l = NULL;
363 if (object != NULL) {
364 saveGlobalRef(env, object, &(request->returnValue.l));
365 }
366 }
367
368 static void
369 invokeStatic(JNIEnv *env, InvokeRequest *request)
370 {
371 switch(returnTypeTag(request->methodSignature)) {
372 case JDWP_TAG(OBJECT):
373 case JDWP_TAG(ARRAY): {
374 jobject object;
375 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
376 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
377 request->clazz,
378 request->method,
379 request->arguments);
380 request->returnValue.l = NULL;
381 if (object != NULL) {
382 saveGlobalRef(env, object, &(request->returnValue.l));
383 }
384 break;
385 }
386
387
388 case JDWP_TAG(BYTE):
389 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
390 request->clazz,
391 request->method,
392 request->arguments);
393 break;
394
395 case JDWP_TAG(CHAR):
444 case JDWP_TAG(VOID):
445 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
446 request->clazz,
447 request->method,
448 request->arguments);
449 break;
450
451 default:
452 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
453 break;
454 }
455 }
456
457 static void
458 invokeVirtual(JNIEnv *env, InvokeRequest *request)
459 {
460 switch(returnTypeTag(request->methodSignature)) {
461 case JDWP_TAG(OBJECT):
462 case JDWP_TAG(ARRAY): {
463 jobject object;
464 JDI_ASSERT_MSG(request->instance, "Request instance null");
465 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
466 request->instance,
467 request->method,
468 request->arguments);
469 request->returnValue.l = NULL;
470 if (object != NULL) {
471 saveGlobalRef(env, object, &(request->returnValue.l));
472 }
473 break;
474 }
475
476 case JDWP_TAG(BYTE):
477 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
478 request->instance,
479 request->method,
480 request->arguments);
481 break;
482
483 case JDWP_TAG(CHAR):
484 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
532 case JDWP_TAG(VOID):
533 JNI_FUNC_PTR(env,CallVoidMethodA)(env,
534 request->instance,
535 request->method,
536 request->arguments);
537 break;
538
539 default:
540 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
541 break;
542 }
543 }
544
545 static void
546 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
547 {
548 switch(returnTypeTag(request->methodSignature)) {
549 case JDWP_TAG(OBJECT):
550 case JDWP_TAG(ARRAY): {
551 jobject object;
552 JDI_ASSERT_MSG(request->clazz, "Request clazz null");
553 JDI_ASSERT_MSG(request->instance, "Request instance null");
554 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
555 request->instance,
556 request->clazz,
557 request->method,
558 request->arguments);
559 request->returnValue.l = NULL;
560 if (object != NULL) {
561 saveGlobalRef(env, object, &(request->returnValue.l));
562 }
563 break;
564 }
565
566 case JDWP_TAG(BYTE):
567 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
568 request->instance,
569 request->clazz,
570 request->method,
571 request->arguments);
572 break;
573
630 case JDWP_TAG(VOID):
631 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
632 request->instance,
633 request->clazz,
634 request->method,
635 request->arguments);
636 break;
637
638 default:
639 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
640 break;
641 }
642 }
643
644 jboolean
645 invoker_doInvoke(jthread thread)
646 {
647 JNIEnv *env;
648 jboolean startNow;
649 InvokeRequest *request;
650 jbyte options;
651 jbyte invokeType;
652
653 JDI_ASSERT(thread);
654
655 debugMonitorEnter(invokerLock);
656
657 request = threadControl_getInvokeRequest(thread);
658 if (request == NULL) {
659 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
660 }
661
662 request->available = JNI_FALSE;
663 startNow = request->pending && !request->started;
664
665 if (startNow) {
666 request->started = JNI_TRUE;
667 }
668 options = request->options;
669 invokeType = request->invokeType;
670
671 debugMonitorExit(invokerLock);
672
673 if (!startNow) {
674 return JNI_FALSE;
675 }
676
677 env = getEnv();
678
679 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */
680
681 jobject exception;
682
683 JNI_FUNC_PTR(env,ExceptionClear)(env);
684
685 switch (invokeType) {
686 case INVOKE_CONSTRUCTOR:
687 invokeConstructor(env, request);
688 break;
689 case INVOKE_STATIC:
690 invokeStatic(env, request);
691 break;
692 case INVOKE_INSTANCE:
693 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
694 invokeNonvirtual(env, request);
695 } else {
696 invokeVirtual(env, request);
697 }
698 break;
699 default:
700 JDI_ASSERT(JNI_FALSE);
701 }
702 request->exception = NULL;
703 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
704 if (exception != NULL) {
705 JNI_FUNC_PTR(env,ExceptionClear)(env);
706 saveGlobalRef(env, exception, &(request->exception));
707 }
708
709 } END_WITH_LOCAL_REFS(env);
710
711 return JNI_TRUE;
712 }
713
751 (void)threadControl_suspendThread(thread, JNI_FALSE);
752 } else {
753 (void)threadControl_suspendAll();
754 }
755
756 if (request->invokeType == INVOKE_CONSTRUCTOR) {
757 /*
758 * Although constructors technically have a return type of
759 * void, we return the object created.
760 */
761 tag = specificTypeKey(env, request->returnValue.l);
762 } else {
763 tag = returnTypeTag(request->methodSignature);
764 }
765 id = request->id;
766 exc = request->exception;
767 returnValue = request->returnValue;
768 }
769
770 /*
771 * At this time, there's no need to retain global references on
772 * arguments since the reply is processed. No one will deal with
773 * this request ID anymore, so we must call deleteGlobalArgumentRefs().
774 *
775 * We cannot delete saved exception or return value references
776 * since otherwise a deleted handle would escape when writing
777 * the response to the stream. Instead, we clean those refs up
778 * after writing the respone.
779 */
780 deleteGlobalArgumentRefs(env, request);
781
782 /*
783 * Give up the lock before I/O operation
784 */
785 debugMonitorExit(invokerLock);
786 eventHandler_unlock();
787
788 if (!detached) {
789 outStream_initReply(&out, id);
790 (void)outStream_writeValue(env, &out, tag, returnValue);
791 (void)outStream_writeObjectTag(env, &out, exc);
792 (void)outStream_writeObjectRef(env, &out, exc);
793 outStream_sendReply(&out);
794 }
795
796 /*
797 * Delete potentially saved global references of return value
798 * and exception
799 */
800 eventHandler_lock(); // for proper lock order
801 debugMonitorEnter(invokerLock);
802 /* Delete potentially saved return value */
803 if ((request->invokeType == INVOKE_CONSTRUCTOR) ||
804 (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) ||
805 (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) {
806 if (request->returnValue.l != NULL) {
807 tossGlobalRef(env, &(request->returnValue.l));
808 }
809 }
810 /* Delete potentially saved exception */
811 if (request->exception != NULL) {
812 tossGlobalRef(env, &(request->exception));
813 }
814 debugMonitorExit(invokerLock);
815 eventHandler_unlock();
816 }
817
818 jboolean
819 invoker_isEnabled(jthread thread)
820 {
821 InvokeRequest *request;
822 jboolean isEnabled;
823
824 JDI_ASSERT(thread);
825 debugMonitorEnter(invokerLock);
826 request = threadControl_getInvokeRequest(thread);
827 if (request == NULL) {
828 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
829 }
830 isEnabled = request->available;
831 debugMonitorExit(invokerLock);
832 return isEnabled;
833 }
834
835 void
|