/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.cldchi.jvm; public class DebuggerInvoke { private static final int T_BOOLEAN = 4; private static final int T_CHAR = 5; private static final int T_FLOAT = 6; private static final int T_DOUBLE = 7; private static final int T_BYTE = 8; private static final int T_SHORT = 9; private static final int T_INT = 10; private static final int T_LONG = 11; private static final int T_OBJECT = 12; private static final int T_ARRAY = 13; private static final int T_VOID = 14; /** * This method is used to synchronously invoke a method on * behalf of a debugger and then return the method return value back * to the debugger. The reason for this sync method is the * non-synchronous nature of EntryActivations in the VM. Picture this, * some event happens in the VM, like a breakpoint, which gets sent to * the debugger. The debugger decides to invoke a Method. The return * packet to the debugger for that invoke can't be sent until the Method * returns and we send the return value (or exception object!) back to * the debugger. So, all threads are suspended in the VM, we have * a Method in hand and the debugger has picked a thread to execute this * Method. We create an entry activation for that Method with all the * args passed in by debugger. Then we create another entry activattion * for this method. This allows us to synchronously call the Method * requested, catch any exceptions and then call back down into the VM * to send the reply packet. The return code in the VM will strip off * these method calls from the thread stack so the thread will be back * in the state it was before we started this whole invoke thing. We * use two different return call methods based on what type of caller * was on the stack when we started the whole invoke process. This is * because there are two entry points into the VM; shared_call_vm and * shared_call_vm_oop. (Don't care about shared_call_vm_exception). We * need to make sure that the original call into the VM returns properly * including any return values (object or otherwise) stored on the stack * or in the EntryFrame or ThreadDesc. * * @param entry really an EntryActivation object from the VM * * @param transport a Transport object from the VM * * @param id debugger request id used to generate outgoing reply packet * * @param options invoke options from debugger * * @param return_type return type of Method being invoked * * @param is_obj_return if original caller of VM was shared_call_vm_oop * */ private static void debuggerInvoke(Object entry, Object transport, int id, int options, int return_type, int is_obj_return) { try { Object ret_obj = null; switch (return_type) { case T_VOID: invokeV(entry); break; case T_OBJECT: { Object[] ret = new Object[1]; Object o = invokeL(entry); ret[0] = o; ret_obj = ret; break; } case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_CHAR: case T_INT: { int[] ret = new int[1]; switch (return_type) { case T_BOOLEAN: boolean b = invokeZ(entry); ret[0] = b ? 1 : 0; break; case T_BYTE: ret[0] = (int)invokeB(entry); break; case T_SHORT: ret[0] = (int)invokeS(entry); break; case T_CHAR: ret[0] = (int)invokeC(entry); break; case T_INT: ret[0] = invokeI(entry); break; } ret_obj = ret; break; } case T_LONG: { long[] ret = new long[1]; ret[0] = invokeJ(entry); ret_obj = ret; break; } case T_DOUBLE: { double[] ret = new double[1]; ret[0] = invokeD(entry); ret_obj = ret; break; } case T_FLOAT: { float[] ret = new float[1]; ret[0] = invokeF(entry); ret_obj = ret; break; } } if (is_obj_return == 1) { debuggerInvokeReturnObj(ret_obj, null, transport, id, options, return_type); } else { debuggerInvokeReturn(ret_obj, null, transport, id, options, return_type); } } catch (Throwable t) { // we send the exception object to the debugger via the native call if (is_obj_return == 1) { debuggerInvokeReturnObj(null, t, transport, id, options, return_type); } else { debuggerInvokeReturn(null, t, transport, id, options, return_type); } } } /** * This method is used by the java debugger code to signal the * synchronous end of a method invoke */ private native static long debuggerInvokeReturn(Object ret, Object exception, Object transport, int id, int options, int return_type); /** * You might think "Oh, I could combine this two methods into one * and pass an arg to distinguish them". Don't! This one returns * Object so that it enters the VM via shared_call_vm_oop. When * we strip the frames off the stack in ObjectReferenceImpl::invoke_return * we need to make sure we return the original return value that was * stored in the EntryFrame back to the original caller. */ private native static Object debuggerInvokeReturnObj(Object ret, Object exception, Object transport, int id, int options, int return_type); private static native void invokeV(Object entry); private static native boolean invokeZ(Object entry); private static native char invokeC(Object entry); private static native float invokeF(Object entry); private static native double invokeD(Object entry); private static native byte invokeB(Object entry); private static native short invokeS(Object entry); private static native int invokeI(Object entry); private static native long invokeJ(Object entry); private static native Object invokeL(Object entry); }