|
Message
From: cvs at opencores.org<cvs@o...>
Date: Fri Jan 18 23:31:34 CET 2008
Subject: [cvs-checkins] MODIFIED: jop ...
Date: 00/08/01 18:23:31 Modified: jop/java/target/src/test/debug JopDebugKernel.java Log: - Changes to add support for get/set operations on instance fields. - Changed the way the debug IO streams are created. - Removed some useless comments - Added some methods to access object handle internal fields - Added some methods to access class structure internal fields - Other changes Methods changed: 118: public static final void breakpoint() 731: private static void setDebugStreams(InputStream in, OutputStream out) Methods added: 1114: private static int getInstanceSizeFromClass(int classReference) 1119: private static int getPointerToStaticPrimitiveFields(int classReference) 1125: private static int getPointerToSuperclass(int classReference) 1139: private static int getClassPointerFromObjectHandle(int objectHandle) 1162: private static int getInstanceField(int objectHandle, int fieldIndex) 1215: private static void setInstanceField(int objectHandle, int fieldIndex, 1216: int fieldValue) 1261: private static void clearFlagForInstanceFieldAccess() 1271: private static void setErrorCodeForInstanceFieldAccess(int errorCode) 1281: private static int getErrorCodeForInstanceFieldAccess() 1293: private static boolean isSuccessfulLastInstanceFieldAccess() 1637: private static void handleGetInstanceVariable() throws IOException 1714: private static void handleSetInstanceVariable() throws IOException 1789: private static final int getObjectPointer(int objectHandle) 1804: private static final int getObjectSize(int objectHandle) 1819: private static final int getMethodTablePointerOrArrayLength(int objectHandle) 1834: private static final boolean isArrayType(int objectHandle) 2642: private static final void printObjectHandle(int handle) Revision Changes Path 1.8 jop/java/target/src/test/debug/JopDebugKernel.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/test/debug/JopDebugKernel.java.diff?r1=1.7&r2=1.8 (In the diff below, changes in quantity of whitespace are not shown.) Index: JopDebugKernel.java =================================================================== RCS file: /cvsroot/paulo/jop/java/target/src/test/debug/JopDebugKernel.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -b -r1.7 -r1.8 --- JopDebugKernel.java 19 Dec 2007 20:39:52 -0000 1.7 +++ JopDebugKernel.java 18 Jan 2008 22:31:33 -0000 1.8 @@ -27,8 +27,11 @@ import java.io.InputStream; import java.io.OutputStream; +import org.apache.bcel.Constants; + import debug.constants.TagConstants; import com.jopdesign.sys.Const; +import com.jopdesign.sys.GC; import com.jopdesign.sys.Native; import debug.constants.CommandConstants; @@ -80,6 +83,10 @@ // a variable to hold the frame pointer of the breakpoint method private static int breakpointFramePointer; + // an internal flag to inform error codes during object access. + // used to avoid memory allocation when creating exceptions. + private static int errorCodeForInstanceFieldAccess; + // internal flag to turn on/off tracing messages
//private static boolean shouldPrintInternalMessages = false;
private static boolean shouldPrintInternalMessages = true;
@@ -220,6 +227,22 @@
continue;
}
+ // get a field from an object
+ if((commandset == 9) && (command == 2))
+ {
+ debugPrintln("GetValues (2)");
+ handleGetInstanceVariable();
+ continue;
+ }
+
+ // set a field into an object
+ if((commandset == 9) && (command == 3))
+ {
+ debugPrintln("SetValues (3)");
+ handleSetInstanceVariable();
+ continue;
+ }
+
// resume execution. Finish this method and continue.
if((commandset == 11) && (command == 3))
{
@@ -722,7 +745,7 @@
}
/**
- * This method can be used in the future to set the streams which will be
+ * This method can be used in the future, to set the streams which will be
* used to communicate with the JOP machine.
*
* @param in
@@ -730,9 +753,24 @@
*/
private static void setDebugStreams(InputStream in, OutputStream out)
{
+ if(in instanceof DataInputStream)
+ {
+ inputStream = (DataInputStream) in;
+ }
+ else
+ {
inputStream = new DataInputStream(in);
+ }
+
+ if(out instanceof DataOutputStream)
+ {
+ outputStream = (DataOutputStream) out;
+ }
+ else
+ {
outputStream = new DataOutputStream(out);
}
+ }
private static int getCPLocalsArgsFromMP(int mp)
{
@@ -1063,27 +1101,6 @@
}
/**
- * Get the framePointer at the given index.
- * The depth of the first frame (for the main method) is zero.
- * Methods called inside "main" will have depth = 1
- * and so on.
- *
- * @param framePointer
- * @return
- */
-// public static final int getFramePointerAt(int framePointer, int index)
-// {
-// int count = getStackDepth();
-// while(isFirstFrame(framePointer) == false && (index < count))
-// {
-// count--;
-// framePointer = getNextFramePointer(framePointer);
-// }
-//
-// return framePointer;
-// }
-
- /**
* Return the current stack depth.
*
* @return
@@ -1094,35 +1111,188 @@
return getStackDepth(framePointer);
}
- private static int getInstanceSize(int object)
+ private static int getInstanceSizeFromClass(int classReference)
{
- int classReference = getClassReference(object);
return Native.rdMem(classReference);
}
- private static int getClassReference(int object)
+ private static int getPointerToStaticPrimitiveFields(int classReference)
+ {
+ classReference++;
+ return Native.rdMem(classReference);
+ }
+
+ private static int getPointerToSuperclass(int classReference)
+ {
+ classReference+=3;
+ return Native.rdMem(classReference);
+ }
+
+ /**
+ * Return the class pointer from an object.
+ * Be careful: if a handle to an array is passed, this method will
+ * return zero. Hence, DON't USE IT WITH ARRAYS!!! it just DOES NOT WORK.
+ *
+ * @param objectHandle
+ * @return
+ */
+ private static int getClassPointerFromObjectHandle(int objectHandle)
+ {
+ int classPointer = 0;
+ if(isArrayType(objectHandle) == false)
+ {
+ synchronized(GC.getMutex())
+ {
+ classPointer = getMethodTablePointerOrArrayLength(objectHandle);
+ // fix the offset to point to the class structure (instance size)
+ classPointer -= 5;
+ }
+ }
+
+ return classPointer;
+ }
+
+ /**
+ * Get the value of one instance field.
+ *
+ * @param objectHandle
+ * @param fieldIndex
+ * @return
+ */
+ private static int getInstanceField(int objectHandle, int fieldIndex)
+ {
+ int size;
+ int value = 0;
+ int objectPointer;
+
+ synchronized(GC.getMutex())
+ {
+ // for development only
+ printObjectHandle(objectHandle);
+
+ // clear the error flag
+ clearFlagForInstanceFieldAccess();
+
+ // get the object size
+ size = getObjectSize(objectHandle);
+
+ debugPrint(" object size: ");
+ debugPrintln(size);
+
+ // check if the field index makes sense. Access only if it's a valid one.
+ if(fieldIndex >= 0 && fieldIndex < size)
+ {
+ // get the object pointer
+ objectPointer = getObjectPointer(objectHandle);
+
+ //use it to access the object content
+ value = Native.rdMem(objectPointer + fieldIndex);
+ }
+ else
+ {
+ // set an error code to inform that this operation failed.
+ setErrorCodeForInstanceFieldAccess(ErrorConstants.ERROR_INVALID_FIELDID);
+
+ debugPrint(" Invalid index: ");
+ debugPrintln(fieldIndex);
+
+ debugPrint(" Num. instance locals is: ");
+ debugPrintln(size);
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Set the value of one instance field.
+ *
+ * @param objectHandle
+ * @param fieldIndex
+ * @param fieldValue
+ * @return
+ */
+ private static void setInstanceField(int objectHandle, int fieldIndex,
+ int fieldValue)
+ {
+ int size;
+ int objectPointer;
+
+ synchronized(GC.getMutex())
{
- int classreference = 0;
+ // for development only
+ printObjectHandle(objectHandle);
- // return one byte and read the pointer to the virtual method table
- object --;
- classreference = Native.rdMem(object);
+ // clear the error flag
+ clearFlagForInstanceFieldAccess();
+
+ // get the object size
+ size = getObjectSize(objectHandle);
+
+ debugPrint(" object size: ");
+ debugPrintln(size);
+
+ // check if the field index makes sense. Access only if it's a valid one.
+ if(fieldIndex >= 0 && fieldIndex < size)
+ {
+ // get the object pointer
+ objectPointer = getObjectPointer(objectHandle);
+
+ //use it to access the object content
+ Native.wrMem(fieldValue, objectPointer + fieldIndex);
+ }
+ else
+ {
+ // set an error code to inform that this operation failed.
+ setErrorCodeForInstanceFieldAccess(ErrorConstants.ERROR_INVALID_FIELDID);
+
+ debugPrint(" Invalid index: ");
+ debugPrintln(fieldIndex);
+
+ debugPrint(" Num. instance locals is: ");
+ debugPrintln(size);
+ }
+ }
+ }
- // adjust to point to the "instance size" field
- classreference--;
- classreference--;
+ /**
+ * Clear the error flag. Setup for next access.
+ */
+ private static void clearFlagForInstanceFieldAccess()
+ {
+ errorCodeForInstanceFieldAccess = 0;
+ }
- return classreference;
+ /**
+ * Set an error code to inform that something went wrong.
+ *
+ * @param errorCode
+ */
+ private static void setErrorCodeForInstanceFieldAccess(int errorCode)
+ {
+ errorCodeForInstanceFieldAccess = errorCode;
}
- private static int getConstantPoolFromClassReference(int classReference)
+ /**
+ * Return the error code, if any.
+ *
+ * @return
+ */
+ private static int getErrorCodeForInstanceFieldAccess()
{
- // get reference to the first method. There will always be some,
- // due to generated/synthetic methods such as the default constructur
- int methodReference = Native.rdMem(classReference + 2);
- int constantPoolReference = getCPFromMP(methodReference);
+ return errorCodeForInstanceFieldAccess;
+ }
- return constantPoolReference;
+ /**
+ * Check if the last operation of "instance field access"
+ * was successful or not. If the error code is zero, then
+ * report success.
+ *
+ * @return
+ */
+ private static boolean isSuccessfulLastInstanceFieldAccess()
+ {
+ return (errorCodeForInstanceFieldAccess == 0);
}
/**
@@ -1460,6 +1630,218 @@
}
/**
+ * Handle a "Get instance variable" command.
+ *
+ * @throws IOException
+ */
+ private static void handleGetInstanceVariable() throws IOException
+ {
+ int objectHandle;
+ int counter;
+ int numFields;
+ int fieldIndex;
+ int fieldValue;
+
+ // read the object handle
+ objectHandle = debugChannel.readIntValue();
+
+ // What happens if the GC is working and change the pointers
+ // before or during an access? Let's stay on the safe size.
+ // Lock the GC while manipulating objects directly.
+ synchronized(GC.getMutex())
+ {
+ // check if the reference type is a valid one.
+ if(GC.isValidObjectHandle(objectHandle) == false)
+ {
+ debugPrint("Failure: invalid object handle.");
+ debugPrint(objectHandle);
+ debugPrintln();
+
+ // send a packet with an error code and return.
+ debugChannel.sendReplyWithErrorCode(ErrorConstants.ERROR_INVALID_OBJECT);
+ return;
+ }
+
+ // read the number of fields to be accessed.
+ numFields = debugChannel.readIntValue();
+
+ // prepare the reply packet
+ debugChannel.prepareInstanceValuesPacket(numFields);
+
+ // fill in the packet with all information requested
+ for(counter = 0; counter < numFields; counter++)
+ {
+ fieldIndex = debugChannel.readIntValue();
+ fieldValue = getInstanceField(objectHandle, fieldIndex);
+
+ // check if an error happened during field access.
+ // if so, stop the loop and send an error packet.
+ if(isSuccessfulLastInstanceFieldAccess() == false)
+ {
+ debugPrint("Failure accessing field # ");
+ debugPrint(counter);
+ debugPrint(". field index: ");
+ debugPrint(fieldIndex);
+ debugPrintln();
+
+ break;
+ }
+
+ debugChannel.writeInstanceFieldValue(fieldValue);
+ }
+ }
+ // end of synchronized block. Now the GC can work freely.
+
+ // check the error flag. If there's an error, send an error code.
+ // otherwise, all data is correct. Send it to the server.
+ if(isSuccessfulLastInstanceFieldAccess() == false)
+ {
+ // send a packet with an error code.
+ debugChannel.sendReplyWithErrorCode(getErrorCodeForInstanceFieldAccess());
+ }
+ else
+ {
+ // great! packet ready. Send it to the server.
+ debugChannel.sendInstanceFieldValuesReply();
+ }
+ }
+
+ /**
+ * Handle a "Set instance variable" command.
+ *
+ * @throws IOException
+ */
+ private static void handleSetInstanceVariable() throws IOException
+ {
+ int objectHandle;
+ int counter;
+ int numFields;
+ int fieldIndex;
+ int fieldValue;
+
+ // read the object handle
+ objectHandle = debugChannel.readIntValue();
+
+ // What happens if the GC is working and change the pointers
+ // before or during an access? Let's stay on the safe size.
+ // Lock the GC while manipulating objects directly.
+ synchronized(GC.getMutex())
+ {
+ // check if the reference type is a valid one.
+ if(GC.isValidObjectHandle(objectHandle) == false)
+ {
+ debugPrint("Failure: invalid object handle.");
+ debugPrint(objectHandle);
+ debugPrintln();
+
+ // send a packet with an error code and return.
+ debugChannel.sendReplyWithErrorCode(ErrorConstants.ERROR_INVALID_OBJECT);
+ return;
+ }
+
+ // read the number of fields to be accessed.
+ numFields = debugChannel.readIntValue();
+
+ // fill in the packet with all information requested
+ for(counter = 0; counter < numFields; counter++)
+ {
+ fieldIndex = debugChannel.readIntValue();
+ fieldValue = debugChannel.readIntValue();
+ setInstanceField(objectHandle, fieldIndex, fieldValue);
+
+ // check if an error happened during field access.
+ // if so, stop the loop and send an error packet.
+ if(isSuccessfulLastInstanceFieldAccess() == false)
+ {
+ debugPrint("Failure accessing field # ");
+ debugPrint(counter);
+ debugPrint(". field index: ");
+ debugPrint(fieldIndex);
+ debugPrint(". new field value: ");
+ debugPrint(fieldValue);
+ debugPrintln();
+
+ break;
+ }
+ }
+ }
+ // end of synchronized block. Now the GC can work freely.
+
+ // check the error flag. If there's an error, send an error code.
+ // otherwise, all data is correct. Send it to the server.
+ if(isSuccessfulLastInstanceFieldAccess() == false)
+ {
+ // send a packet with an error code.
+ debugChannel.sendReplyWithErrorCode(getErrorCodeForInstanceFieldAccess());
+ }
+ else
+ {
+ // great! all operations were done. Send an ack to the server.
+ debugChannel.sendReply();
+ }
+ }
+
+ /**
+ * Return the actual object pointer
+ * @param objectHandle
+ * @return
+ */
+ private static final int getObjectPointer(int objectHandle)
+ {
+ // let's synchronize on the GC to avoid concurrency problems.
+ synchronized(GC.getMutex())
+ {
+ return Native.rdMem(objectHandle + GC.OFF_PTR);
+ }
+ }
+
+ /**
+ * Return the instance size.
+ *
+ * @param handle
+ * @return
+ */
+ private static final int getObjectSize(int objectHandle)
+ {
+ // let's synchronize on the GC to avoid concurrency problems.
+ synchronized(GC.getMutex())
+ {
+ return Native.rdMem(objectHandle + GC.OFF_SIZE);
+ }
+ }
+
+ /**
+ * Return the method table pointer (or array length if it's an array).
+ *
+ * @param handle
+ * @return
+ */
+ private static final int getMethodTablePointerOrArrayLength(int objectHandle)
+ {
+ // let's synchronize on the GC to avoid concurrency problems.
+ synchronized(GC.getMutex())
+ {
+ return Native.rdMem(objectHandle + GC.OFF_MTAB_ALEN);
+ }
+ }
+
+ /**
+ * Check if the handle control an array object.
+ *
+ * @param handle
+ * @return
+ */
+ private static final boolean isArrayType(int objectHandle)
+ {
+ // let's synchronize on the GC to avoid concurrency problems.
+ synchronized(GC.getMutex())
+ {
+ //return (Native.rdMem(objectHandle + GC.OFF_TYPE) == GC.IS_REFARR);
+ return (Native.rdMem(objectHandle + GC.OFF_TYPE) == Constants.T_ARRAY);
+ }
+ }
+
+ /**
* Test to check if some types of packets are being properly
* created.
* @throws IOException
@@ -2251,4 +2633,90 @@
{
return shouldPrintInternalMessages;
}
+
+ /**
+ * Print information about one object handle.
+ *
+ * @param handle
+ */
+ private static final void printObjectHandle(int handle)
+ {
+// * According to GC class, the handle contains following data:
+// * 0 pointer to the object in the heap or 0 when the handle is free
+// * 1 pointer to the method table or length of an array
+// * 2 size - could be in class info
+// * 3 type info: object, primitve array or ref array
+// * 4 pointer to next handle of same type (used or free)
+// * 5 gray list
+// * 6 space marker - either toSpace or fromSpace
+
+ int data, type;
+
+ // let's synchronize on the GC to avoid concurrency problems.
+ synchronized(GC.getMutex())
+ {
+ System.out.print("Handle content: ");
+
+ for(data = 0; data < 8; data ++)
+ {
+ int value = Native.rdMem(handle + data);
+ EmbeddedOutputStream.printIntHex(value, System.out);
+ debugPrint(" ");
+ }
+
+ System.out.println();
+
+ data = Native.rdMem(handle + GC.OFF_PTR);
+ type = Native.rdMem(handle + GC.OFF_TYPE);
+
+ if(data == 0)
+ {
+ System.out.println("Free handle: ");
+ System.out.println(handle);
+ }
+ else
+ {
+ System.out.print("Object pointer: ");
+ System.out.println(data);
+ }
+
+ data = Native.rdMem(handle + GC.OFF_MTAB_ALEN);
+ if(type == GC.IS_OBJ)
+ {
+ System.out.print("Method table: ");
+ System.out.println(data);
+ }
+ else
+ {
+ System.out.print("Array length: ");
+ System.out.println(data);
+ }
+
+ // this is the last access to the handle content.
+ // close synchronization block and release GC lock.
+ data = Native.rdMem(handle + GC.OFF_SIZE);
+ }
+
+ System.out.print("Instance size: ");
+ System.out.println(data);
+
+ System.out.print("Type: ");
+ System.out.print(type);
+ System.out.print(" ");
+
+ if(type == GC.IS_OBJ)
+ {
+ System.out.print("Type: Object (not an array) - ");
+ System.out.println(type);
+ }
+ if(type == GC.IS_REFARR)
+ {
+ System.out.println("Type: Array");
+ System.out.println(type);
+ }
+
+ // for now, don't print the remaining fields. Not yet necessary.
+ // if more fields were added, remember to include on the sync block above.
+ System.out.println("");
+ }
}
|
 |