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 }
303 arguments, argumentCount);
304 }
305 debugMonitorExit(invokerLock);
306
307 if (error == JVMTI_ERROR_NONE) {
308 if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
309 /* true means it is okay to unblock the commandLoop thread */
310 (void)threadControl_resumeThread(thread, JNI_TRUE);
311 } else {
312 (void)threadControl_resumeAll();
313 }
314 }
315
316 return error;
317 }
318
319 static void
320 invokeConstructor(JNIEnv *env, InvokeRequest *request)
321 {
322 jobject object;
323 object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
324 request->method,
325 request->arguments);
326 request->returnValue.l = NULL;
327 if (object != NULL) {
328 saveGlobalRef(env, object, &(request->returnValue.l));
329 }
330 }
331
332 static void
333 invokeStatic(JNIEnv *env, InvokeRequest *request)
334 {
335 switch(returnTypeTag(request->methodSignature)) {
336 case JDWP_TAG(OBJECT):
337 case JDWP_TAG(ARRAY): {
338 jobject object;
339 object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
340 request->clazz,
341 request->method,
342 request->arguments);
343 request->returnValue.l = NULL;
344 if (object != NULL) {
345 saveGlobalRef(env, object, &(request->returnValue.l));
346 }
347 break;
348 }
349
350
351 case JDWP_TAG(BYTE):
352 request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
353 request->clazz,
354 request->method,
355 request->arguments);
356 break;
357
358 case JDWP_TAG(CHAR):
407 case JDWP_TAG(VOID):
408 JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
409 request->clazz,
410 request->method,
411 request->arguments);
412 break;
413
414 default:
415 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
416 break;
417 }
418 }
419
420 static void
421 invokeVirtual(JNIEnv *env, InvokeRequest *request)
422 {
423 switch(returnTypeTag(request->methodSignature)) {
424 case JDWP_TAG(OBJECT):
425 case JDWP_TAG(ARRAY): {
426 jobject object;
427 object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
428 request->instance,
429 request->method,
430 request->arguments);
431 request->returnValue.l = NULL;
432 if (object != NULL) {
433 saveGlobalRef(env, object, &(request->returnValue.l));
434 }
435 break;
436 }
437
438 case JDWP_TAG(BYTE):
439 request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
440 request->instance,
441 request->method,
442 request->arguments);
443 break;
444
445 case JDWP_TAG(CHAR):
446 request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
494 case JDWP_TAG(VOID):
495 JNI_FUNC_PTR(env,CallVoidMethodA)(env,
496 request->instance,
497 request->method,
498 request->arguments);
499 break;
500
501 default:
502 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
503 break;
504 }
505 }
506
507 static void
508 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
509 {
510 switch(returnTypeTag(request->methodSignature)) {
511 case JDWP_TAG(OBJECT):
512 case JDWP_TAG(ARRAY): {
513 jobject object;
514 object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
515 request->instance,
516 request->clazz,
517 request->method,
518 request->arguments);
519 request->returnValue.l = NULL;
520 if (object != NULL) {
521 saveGlobalRef(env, object, &(request->returnValue.l));
522 }
523 break;
524 }
525
526 case JDWP_TAG(BYTE):
527 request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
528 request->instance,
529 request->clazz,
530 request->method,
531 request->arguments);
532 break;
533
590 case JDWP_TAG(VOID):
591 JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
592 request->instance,
593 request->clazz,
594 request->method,
595 request->arguments);
596 break;
597
598 default:
599 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
600 break;
601 }
602 }
603
604 jboolean
605 invoker_doInvoke(jthread thread)
606 {
607 JNIEnv *env;
608 jboolean startNow;
609 InvokeRequest *request;
610
611 JDI_ASSERT(thread);
612
613 debugMonitorEnter(invokerLock);
614
615 request = threadControl_getInvokeRequest(thread);
616 if (request == NULL) {
617 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
618 }
619
620 request->available = JNI_FALSE;
621 startNow = request->pending && !request->started;
622
623 if (startNow) {
624 request->started = JNI_TRUE;
625 }
626 debugMonitorExit(invokerLock);
627
628 if (!startNow) {
629 return JNI_FALSE;
630 }
631
632 env = getEnv();
633
634 WITH_LOCAL_REFS(env, 2) { /* 1 for obj return values, 1 for exception */
635
636 jobject exception;
637
638 JNI_FUNC_PTR(env,ExceptionClear)(env);
639
640 switch (request->invokeType) {
641 case INVOKE_CONSTRUCTOR:
642 invokeConstructor(env, request);
643 break;
644 case INVOKE_STATIC:
645 invokeStatic(env, request);
646 break;
647 case INVOKE_INSTANCE:
648 if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
649 invokeNonvirtual(env, request);
650 } else {
651 invokeVirtual(env, request);
652 }
653 break;
654 default:
655 JDI_ASSERT(JNI_FALSE);
656 }
657 request->exception = NULL;
658 exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
659 if (exception != NULL) {
660 JNI_FUNC_PTR(env,ExceptionClear)(env);
661 saveGlobalRef(env, exception, &(request->exception));
662 }
663
664 } END_WITH_LOCAL_REFS(env);
665
666 return JNI_TRUE;
667 }
668
706 (void)threadControl_suspendThread(thread, JNI_FALSE);
707 } else {
708 (void)threadControl_suspendAll();
709 }
710
711 if (request->invokeType == INVOKE_CONSTRUCTOR) {
712 /*
713 * Although constructors technically have a return type of
714 * void, we return the object created.
715 */
716 tag = specificTypeKey(env, request->returnValue.l);
717 } else {
718 tag = returnTypeTag(request->methodSignature);
719 }
720 id = request->id;
721 exc = request->exception;
722 returnValue = request->returnValue;
723 }
724
725 /*
726 * Give up the lock before I/O operation
727 */
728 debugMonitorExit(invokerLock);
729 eventHandler_unlock();
730
731
732 if (!detached) {
733 outStream_initReply(&out, id);
734 (void)outStream_writeValue(env, &out, tag, returnValue);
735 (void)outStream_writeObjectTag(env, &out, exc);
736 (void)outStream_writeObjectRef(env, &out, exc);
737 outStream_sendReply(&out);
738 }
739 }
740
741 jboolean
742 invoker_isPending(jthread thread)
743 {
744 InvokeRequest *request;
745
746 JDI_ASSERT(thread);
747 request = threadControl_getInvokeRequest(thread);
748 if (request == NULL) {
749 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
750 }
751 return request->pending;
752 }
753
754 jboolean
755 invoker_isEnabled(jthread thread)
756 {
757 InvokeRequest *request;
758
|
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
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
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
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 }
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
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
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):
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
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,
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
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
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
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
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
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
843 invoker_isEnabled(jthread thread)
844 {
845 InvokeRequest *request;
846
|