001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.cldchi.jvm;
028:
029: public class DebuggerInvoke {
030:
031: private static final int T_BOOLEAN = 4;
032: private static final int T_CHAR = 5;
033: private static final int T_FLOAT = 6;
034: private static final int T_DOUBLE = 7;
035: private static final int T_BYTE = 8;
036: private static final int T_SHORT = 9;
037: private static final int T_INT = 10;
038: private static final int T_LONG = 11;
039: private static final int T_OBJECT = 12;
040: private static final int T_ARRAY = 13;
041: private static final int T_VOID = 14;
042:
043: /**
044: * This method is used to synchronously invoke a method on
045: * behalf of a debugger and then return the method return value back
046: * to the debugger. The reason for this sync method is the
047: * non-synchronous nature of EntryActivations in the VM. Picture this,
048: * some event happens in the VM, like a breakpoint, which gets sent to
049: * the debugger. The debugger decides to invoke a Method. The return
050: * packet to the debugger for that invoke can't be sent until the Method
051: * returns and we send the return value (or exception object!) back to
052: * the debugger. So, all threads are suspended in the VM, we have
053: * a Method in hand and the debugger has picked a thread to execute this
054: * Method. We create an entry activation for that Method with all the
055: * args passed in by debugger. Then we create another entry activattion
056: * for this method. This allows us to synchronously call the Method
057: * requested, catch any exceptions and then call back down into the VM
058: * to send the reply packet. The return code in the VM will strip off
059: * these method calls from the thread stack so the thread will be back
060: * in the state it was before we started this whole invoke thing. We
061: * use two different return call methods based on what type of caller
062: * was on the stack when we started the whole invoke process. This is
063: * because there are two entry points into the VM; shared_call_vm and
064: * shared_call_vm_oop. (Don't care about shared_call_vm_exception). We
065: * need to make sure that the original call into the VM returns properly
066: * including any return values (object or otherwise) stored on the stack
067: * or in the EntryFrame or ThreadDesc.
068: *
069: * @param entry really an EntryActivation object from the VM
070: *
071: * @param transport a Transport object from the VM
072: *
073: * @param id debugger request id used to generate outgoing reply packet
074: *
075: * @param options invoke options from debugger
076: *
077: * @param return_type return type of Method being invoked
078: *
079: * @param is_obj_return if original caller of VM was shared_call_vm_oop
080: *
081: */
082:
083: private static void debuggerInvoke(Object entry, Object transport,
084: int id, int options, int return_type, int is_obj_return) {
085: try {
086: Object ret_obj = null;
087: switch (return_type) {
088: case T_VOID:
089: invokeV(entry);
090: break;
091: case T_OBJECT: {
092: Object[] ret = new Object[1];
093: Object o = invokeL(entry);
094: ret[0] = o;
095: ret_obj = ret;
096: break;
097: }
098:
099: case T_BOOLEAN:
100: case T_BYTE:
101: case T_SHORT:
102: case T_CHAR:
103: case T_INT: {
104: int[] ret = new int[1];
105: switch (return_type) {
106: case T_BOOLEAN:
107: boolean b = invokeZ(entry);
108: ret[0] = b ? 1 : 0;
109: break;
110: case T_BYTE:
111: ret[0] = (int) invokeB(entry);
112: break;
113: case T_SHORT:
114: ret[0] = (int) invokeS(entry);
115: break;
116: case T_CHAR:
117: ret[0] = (int) invokeC(entry);
118: break;
119: case T_INT:
120: ret[0] = invokeI(entry);
121: break;
122: }
123: ret_obj = ret;
124: break;
125: }
126: case T_LONG: {
127: long[] ret = new long[1];
128: ret[0] = invokeJ(entry);
129: ret_obj = ret;
130: break;
131: }
132: case T_DOUBLE: {
133: double[] ret = new double[1];
134: ret[0] = invokeD(entry);
135: ret_obj = ret;
136: break;
137: }
138: case T_FLOAT: {
139: float[] ret = new float[1];
140: ret[0] = invokeF(entry);
141: ret_obj = ret;
142: break;
143: }
144: }
145: if (is_obj_return == 1) {
146: debuggerInvokeReturnObj(ret_obj, null, transport, id,
147: options, return_type);
148: } else {
149: debuggerInvokeReturn(ret_obj, null, transport, id,
150: options, return_type);
151: }
152: } catch (Throwable t) {
153: // we send the exception object to the debugger via the native call
154: if (is_obj_return == 1) {
155: debuggerInvokeReturnObj(null, t, transport, id,
156: options, return_type);
157: } else {
158: debuggerInvokeReturn(null, t, transport, id, options,
159: return_type);
160: }
161: }
162: }
163:
164: /**
165: * This method is used by the java debugger code to signal the
166: * synchronous end of a method invoke
167: */
168:
169: private native static long debuggerInvokeReturn(Object ret,
170: Object exception, Object transport, int id, int options,
171: int return_type);
172:
173: /**
174: * You might think "Oh, I could combine this two methods into one
175: * and pass an arg to distinguish them". Don't! This one returns
176: * Object so that it enters the VM via shared_call_vm_oop. When
177: * we strip the frames off the stack in ObjectReferenceImpl::invoke_return
178: * we need to make sure we return the original return value that was
179: * stored in the EntryFrame back to the original caller.
180: */
181: private native static Object debuggerInvokeReturnObj(Object ret,
182: Object exception, Object transport, int id, int options,
183: int return_type);
184:
185: private static native void invokeV(Object entry);
186:
187: private static native boolean invokeZ(Object entry);
188:
189: private static native char invokeC(Object entry);
190:
191: private static native float invokeF(Object entry);
192:
193: private static native double invokeD(Object entry);
194:
195: private static native byte invokeB(Object entry);
196:
197: private static native short invokeS(Object entry);
198:
199: private static native int invokeI(Object entry);
200:
201: private static native long invokeJ(Object entry);
202:
203: private static native Object invokeL(Object entry);
204:
205: }
|