aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2007-05-18 18:33:46 +0000
committerKeith Seitz <keiths@redhat.com>2007-05-18 18:33:46 +0000
commit95dec624ccc2505d8ee9cb31202e8d1b3984dd36 (patch)
tree4fd1aab161a233135bd95527b116e1d6c32d7a32
parent7795cc15121cf30cc1f5717257f1866fcbd9c9ff (diff)
merge w/gcj trunk for JDWP/JVMTI
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/redhat/gcc-4_1-jdwp-merge-branch@124829 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libjava/ChangeLog101
-rw-r--r--libjava/Makefile.in40
-rw-r--r--libjava/boehm.cc11
-rw-r--r--libjava/classpath/ChangeLog21
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/Jdwp.java98
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/Event.java39
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/EventManager.java39
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java4
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java18
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java12
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java56
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java57
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java79
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java13
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java14
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java25
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java30
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java34
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java31
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java54
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java44
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java107
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java16
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java37
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/Location.java14
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java13
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java76
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/NullObject.java50
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/Value.java301
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java8
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java92
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/CharValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/IntValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/LongValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java92
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/StringValue.java100
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/Value.java155
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java247
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java82
-rw-r--r--libjava/gnu/classpath/jdwp/VMFrame.java36
-rw-r--r--libjava/gnu/classpath/jdwp/VMIdManager.java10
-rw-r--r--libjava/gnu/classpath/jdwp/VMMethod.java13
-rw-r--r--libjava/gnu/classpath/jdwp/VMVirtualMachine.java123
-rw-r--r--libjava/gnu/classpath/jdwp/natVMFrame.cc324
-rw-r--r--libjava/gnu/classpath/jdwp/natVMMethod.cc134
-rw-r--r--libjava/gnu/classpath/jdwp/natVMVirtualMachine.cc875
-rw-r--r--libjava/gnu/gcj/jvmti/BreakpointManager.java10
-rw-r--r--libjava/gnu/gcj/jvmti/natBreakpoint.cc19
-rw-r--r--libjava/headers.txt8
-rw-r--r--libjava/include/boehm-gc.h4
-rw-r--r--libjava/include/java-interp.h161
-rw-r--r--libjava/include/java-stack.h7
-rw-r--r--libjava/include/jvmti-int.h11
-rw-r--r--libjava/include/jvmti_md.h10
-rw-r--r--libjava/include/no-gc.h4
-rw-r--r--libjava/include/win32-threads.h1
-rw-r--r--libjava/interpret-run.cc294
-rw-r--r--libjava/interpret.cc348
-rw-r--r--libjava/java/lang/Class.h7
-rw-r--r--libjava/java/lang/Thread.java3
-rw-r--r--libjava/java/lang/natClass.cc20
-rw-r--r--libjava/java/lang/natThread.cc11
-rw-r--r--libjava/jni.cc5
-rw-r--r--libjava/jvmti.cc798
-rw-r--r--libjava/link.cc140
-rw-r--r--libjava/nogc.cc6
-rw-r--r--libjava/prims.cc188
-rw-r--r--libjava/sources.am35
-rw-r--r--libjava/stacktrace.cc10
77 files changed, 5888 insertions, 923 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 1f6a4d52397..4e5a5afa613 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,104 @@
+2007-05-18 Keith Seitz <keiths@redhat.com>
+
+ Merged from trunk:
+
+ 2007-05-17 Kyle Galloway <kgallowa@redhat.com>
+ * classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
+ (executeMethods): Remove cast to ClassReferenceTypeId.
+ * classpath/lib/gnu/classpath/jdwp/processor/
+ ReferenceTypeCommandSet.class: Rebuilt.
+
+ 2007-05-17 Kyle Galloway <kgallowa@redhat.com>
+ * gnu/classpath/jdwp/natVMMethod.cc (getModifiers): Check for native
+ classes and mark methods as native appropriately.
+
+ 2007-05-17 Kyle Galloway <kgallowa@redhat.com>
+ * gnu/classpath/jdwp/VMFrame.java (<init>): Add parameter for "this"
+ pointer.
+ * gnu/classpath/jdwp/VMFrame.h: Regenerated.
+ * classpath/lib/gnu/classpath/jdwp/VMFrame.class: Rebuilt.
+ * gnu/classpath/jdwp/natVMVirtualMachine.cc (getFrame): Use new
+ VMFrame constructor.
+
+ 2007-05-16 Keith Seitz <keiths@redhat.com>
+ * include/java-interp.h (breakpoint_at): Declare.
+ * interpret.cc (breakpoint_at): New function.
+ * gnu/classpath/jdwp/VMVirtualMachine.java (_event_list):
+ New member.
+ * gnu/classpath/jdwp/natVMVirtualMachine.cc (initialize):
+ Initialize _event_list.
+ (handle_single_step): If there is a breakpoint at the
+ location at which we are stopping, do not send the notification.
+ Instead add the event to a list of events that occur at this
+ location.
+ (jdwpBreakpointCB): If the event list is not empty, send
+ whatever events are in it and the breakpoint event in a single
+ notification.
+ Mark parameter jni_env as MAYBE_UNUSED.
+ * classpath/lib/gnu/classpath/jdwp/VMVirtualMachine.class:
+ Regenerated.
+ * gnu/classpath/jdwp/VMVirtualMachine.h: Regenerated.
+
+ 2007-05-15 Keith Seitz <keiths@redhat.com>
+ * interpret.cc (STOREA): Rewrite using temporary variable to
+ avoid double-macro expansion side-effects.
+ (STOREI): Likewise.
+ (STOREF): Likewise.
+ (STOREL)[SIZEOF_VOID_P == 8]: Likewise.
+ (STORED)[SIZEOF_VOID_P == 8]: Likewise.
+ (STOREL)[SIZEOF_VOID_P != 8]: Likewise.
+ (STORED)[SIZEOF_VOID_P != 8]: Likewise.
+ (POKEI): Likewise.
+
+ 2007-05-07 Keith Seitz <keiths@redhat.com>
+ * classpath/lib/gnu/classpath/jdwp/Jdwp.class: Regenerate.
+ * classpath/lib/gnu/classpath/jdwp/Jdwp$1.class: Regenerate.
+ * classpath/lib/gnu/classpath/jdwp/event/Event.class:
+ Regenerate.
+ * classpath/lib/gnu/classpath/jdwp/transport/JdwpConnection.class:
+ Regenerate.
+ * gnu/classpath/jdwp/Jdwp.h: Regenerate.
+ * gnu/classpath/jdwp/event/Event.h: Regenerate.
+ * gnu/classpath/jdwp/transport/JdwpConnection.h: Regenerate.
+
+ 2007-05-04 Kyle Galloway <kgallowa@redhat.com>
+ * gnu/classpath/jdwp/natVMVirtualMachine.cc (getClassMethod): Change
+ to use JVMTI.
+
+ 2007-05-03 Keith Seitz <keiths@redhat.com>
+ * interpret.cc: Don't include ExceptionEvent.h.
+ * gnu/gcj/jvmti/natExceptionEvent.cc: Remove.
+ * Makefile.am (nat_source_files): Remove natExceptionEvent.cc.
+ * Makefile.in: Regenerated.
+
+ 2007-05-03 Keith Seitz <keiths@redhat.com>
+ * include/jvmti-int.h (_Jv_ReportJVMTIExceptionThrow):
+ Declare.
+ * interpret.cc (_Jv_ReportJVMTIExceptionThrow): New function.
+ (find_catch_location): New function.
+ (REPORT_EXCEPTION): New macro.
+ (throw_internal_error): Use REPORT_EXCEPTION.
+ (throw_incompatible_class_change_error): Likewise.
+ (throw_null_pointer_exception): Likewise.
+ (throw_class_format_error): Likewise.
+ * interpret-run.cc (INTERP_REPORT_EXCEPTION)[DEBUG]: Set
+ to REPORT_EXCEPTION.
+ (INTERP_REPORT_EXCEPTION)[!DEBUG]: Make nop.
+ (insn_new): Use INTERP_REPORT_EXCEPTION.
+ (insn_athrow): Likewise.
+ Remove previous JVMTI exception notifications.
+ Add JVMTI ExceptionCatch notificatin.
+ * jni.cc (_Jv_PopSystemFrame): Notify JVMTI clients of
+ exception throw.
+ * gnu/gcj/jvmti/ExceptionEvent.java: Removed.
+ * gnu/gcj/jvmti/ExceptionEvent.h: Removed.
+ * classpath/lib/gnu/gcj/jvmti/ExceptionEvent.class: Removed.
+ * gnu/classpath/jdwp/natVMVirtualMachine.cc
+ (jdwpExceptionCB): New function.
+ (jdwpVMInitCB): Set Exception event handler and enable.
+ * sources.am: Regenerated.
+ * Makefile.in: Regenerated.
+
2007-05-03 Thomas Fitzsimmons <fitzsim@redhat.com>
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=237304
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index 60fd06f35bc..0d1ef376b81 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -156,9 +156,10 @@ am__DEPENDENCIES_1 = gnu/awt.lo gnu/awt/j2d.lo gnu/classpath.lo \
gnu/classpath/jdwp/exception.lo gnu/classpath/jdwp/id.lo \
gnu/classpath/jdwp/processor.lo \
gnu/classpath/jdwp/transport.lo gnu/classpath/jdwp/util.lo \
- gnu/gcj.lo gnu/gcj/convert.lo gnu/gcj/io.lo gnu/gcj/jvmti.lo \
- gnu/gcj/runtime.lo gnu/gcj/util.lo gnu/java/awt.lo \
- gnu/java/awt/color.lo gnu/java/awt/dnd.lo gnu/java/awt/font.lo \
+ gnu/classpath/jdwp/value.lo gnu/gcj.lo gnu/gcj/convert.lo \
+ gnu/gcj/io.lo gnu/gcj/jvmti.lo gnu/gcj/runtime.lo \
+ gnu/gcj/util.lo gnu/java/awt.lo gnu/java/awt/color.lo \
+ gnu/java/awt/dnd.lo gnu/java/awt/font.lo \
gnu/java/awt/font/autofit.lo gnu/java/awt/font/opentype.lo \
gnu/java/awt/font/opentype/truetype.lo gnu/java/awt/image.lo \
gnu/java/awt/java2d.lo gnu/java/awt/peer.lo \
@@ -1188,15 +1189,19 @@ classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java
gnu_classpath_jdwp_event_filters_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_event_filters_source_files)))
gnu_classpath_jdwp_exception_source_files = \
+classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java \
classpath/gnu/classpath/jdwp/exception/InvalidClassException.java \
classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java \
classpath/gnu/classpath/jdwp/exception/InvalidCountException.java \
classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java \
classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java \
classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java \
classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java \
classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java \
classpath/gnu/classpath/jdwp/exception/InvalidStringException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidTagException.java \
classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java \
classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java \
classpath/gnu/classpath/jdwp/exception/JdwpException.java \
@@ -1204,6 +1209,7 @@ classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java \
classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java \
classpath/gnu/classpath/jdwp/exception/NativeMethodException.java \
classpath/gnu/classpath/jdwp/exception/NotImplementedException.java \
+classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java \
classpath/gnu/classpath/jdwp/exception/VmDeadException.java
gnu_classpath_jdwp_exception_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_exception_source_files)))
@@ -1215,6 +1221,7 @@ classpath/gnu/classpath/jdwp/id/ClassObjectId.java \
classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/JdwpId.java \
+classpath/gnu/classpath/jdwp/id/NullObjectId.java \
classpath/gnu/classpath/jdwp/id/ObjectId.java \
classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/StringId.java \
@@ -1259,11 +1266,30 @@ classpath/gnu/classpath/jdwp/util/JdwpString.java \
classpath/gnu/classpath/jdwp/util/LineTable.java \
classpath/gnu/classpath/jdwp/util/Location.java \
classpath/gnu/classpath/jdwp/util/MethodResult.java \
+classpath/gnu/classpath/jdwp/util/MonitorInfo.java \
+classpath/gnu/classpath/jdwp/util/NullObject.java \
classpath/gnu/classpath/jdwp/util/Signature.java \
classpath/gnu/classpath/jdwp/util/Value.java \
classpath/gnu/classpath/jdwp/util/VariableTable.java
gnu_classpath_jdwp_util_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_util_source_files)))
+gnu_classpath_jdwp_value_source_files = \
+classpath/gnu/classpath/jdwp/value/ArrayValue.java \
+classpath/gnu/classpath/jdwp/value/BooleanValue.java \
+classpath/gnu/classpath/jdwp/value/ByteValue.java \
+classpath/gnu/classpath/jdwp/value/CharValue.java \
+classpath/gnu/classpath/jdwp/value/DoubleValue.java \
+classpath/gnu/classpath/jdwp/value/FloatValue.java \
+classpath/gnu/classpath/jdwp/value/IntValue.java \
+classpath/gnu/classpath/jdwp/value/LongValue.java \
+classpath/gnu/classpath/jdwp/value/ObjectValue.java \
+classpath/gnu/classpath/jdwp/value/ShortValue.java \
+classpath/gnu/classpath/jdwp/value/StringValue.java \
+classpath/gnu/classpath/jdwp/value/Value.java \
+classpath/gnu/classpath/jdwp/value/ValueFactory.java \
+classpath/gnu/classpath/jdwp/value/VoidValue.java
+
+gnu_classpath_jdwp_value_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_value_source_files)))
gnu_gcj_source_files = \
gnu/gcj/Core.java \
gnu/gcj/RawData.java \
@@ -7184,6 +7210,7 @@ all_packages_source_files = \
gnu/classpath/jdwp/processor.list \
gnu/classpath/jdwp/transport.list \
gnu/classpath/jdwp/util.list \
+ gnu/classpath/jdwp/value.list \
gnu/gcj.list \
gnu/gcj/convert.list \
gnu/gcj/io.list \
@@ -7428,6 +7455,7 @@ ordinary_header_files = \
$(gnu_classpath_jdwp_processor_header_files) \
$(gnu_classpath_jdwp_transport_header_files) \
$(gnu_classpath_jdwp_util_header_files) \
+ $(gnu_classpath_jdwp_value_header_files) \
$(gnu_gcj_header_files) \
$(gnu_gcj_convert_header_files) \
$(gnu_gcj_io_header_files) \
@@ -10004,6 +10032,12 @@ gnu/classpath/jdwp/util.list: $(gnu_classpath_jdwp_util_source_files)
-include gnu/classpath/jdwp/util.deps
+gnu/classpath/jdwp/value.list: $(gnu_classpath_jdwp_value_source_files)
+ @$(mkinstalldirs) $(dir $@)
+ echo $(srcdir)/classpath/lib/gnu/classpath/jdwp/value/*.class > gnu/classpath/jdwp/value.list
+
+-include gnu/classpath/jdwp/value.deps
+
gnu/gcj.list: $(gnu_gcj_source_files)
@$(mkinstalldirs) $(dir $@)
echo $(srcdir)/classpath/lib/gnu/gcj/*.class > gnu/gcj.list
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 66860dd50da..3aa0acba987 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -722,6 +722,17 @@ _Jv_ResumeThread (_Jv_Thread_t *thread)
#endif
}
+int
+_Jv_IsThreadSuspended (_Jv_Thread_t *thread)
+{
+#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+ && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
+ return GC_is_thread_suspended (_Jv_GetPlatformThreadID (thread));
+#else
+ return 0;
+#endif
+}
+
void
_Jv_GCAttachThread ()
{
diff --git a/libjava/classpath/ChangeLog b/libjava/classpath/ChangeLog
index 59e8953c7e5..3238e05e439 100644
--- a/libjava/classpath/ChangeLog
+++ b/libjava/classpath/ChangeLog
@@ -1,3 +1,24 @@
+2007-05-18 Keith Seitz <keiths@redhat.com>
+
+ Merged from trunk:
+
+ 2007-05-07 Keith Seitz <keiths@redhat.com>
+ * gnu/classpath/jdwp/Jdwp.java (notify): Rewrite to call
+ new array-based method.
+ (notify): New function.
+ (sendEvent): Rewrite to use sendEvents.
+ (sendEvents): New method.
+ * gnu/classpath/jdwp/event/Event.java (toPacket): Make static.
+ Change parameters to use arrays for events and requests.
+ Add suspendPolicy parameter.
+ Move per-event data transformation to...
+ (_toData): ... here.
+ * gnu/classpath/jdwp/transport/JdwpConnection.java
+ (sendEvent): Renamed to ...
+ (sendEvents): ... this.
+ Change parameters to use arrays for events and requests.
+ Add suspendPolicy parameter.
+
2007-05-03 Andrew Haley <aph@redhat.com>
* gnu/javax/management/Server.java (Server): Record the delegate.
diff --git a/libjava/classpath/gnu/classpath/jdwp/Jdwp.java b/libjava/classpath/gnu/classpath/jdwp/Jdwp.java
index e63a9a353dd..1d2329255cb 100644
--- a/libjava/classpath/gnu/classpath/jdwp/Jdwp.java
+++ b/libjava/classpath/gnu/classpath/jdwp/Jdwp.java
@@ -1,5 +1,5 @@
/* Jdwp.java -- Virtual machine to JDWP back-end programming interface
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -51,6 +51,7 @@ import gnu.classpath.jdwp.transport.TransportFactory;
import java.io.IOException;
import java.security.AccessController;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -207,23 +208,21 @@ public class Jdwp
* The event is filtered through the event manager before being
* sent.
*
- * FIXME: Probably need logic to send multiple events
* @param event the event to report
*/
- public static void notify (Event event)
+ public static void notify(Event event)
{
- Jdwp jdwp = getDefault ();
+ Jdwp jdwp = getDefault();
if (jdwp != null)
{
- EventManager em = EventManager.getDefault ();
- EventRequest request = em.getEventRequest (event);
- if (request != null)
+ EventManager em = EventManager.getDefault();
+ EventRequest[] requests = em.getEventRequests(event);
+ for (int i = 0; i < requests.length; ++i)
{
try
{
- System.out.println ("Jdwp.notify: sending event " + event);
- sendEvent (request, event);
- jdwp._enforceSuspendPolicy (request.getSuspendPolicy ());
+ sendEvent(requests[i], event);
+ jdwp._enforceSuspendPolicy(requests[i].getSuspendPolicy());
}
catch (Exception e)
{
@@ -236,6 +235,62 @@ public class Jdwp
}
/**
+ * Notify the debugger of "co-located" events. This method should
+ * not be called if debugging is not active (but it would not
+ * cause any harm). Places where event notifications occur
+ * should check isDebugging before doing anything.
+ *
+ * The events are filtered through the event manager before being
+ * sent.
+ *
+ * @param events the events to report
+ */
+ public static void notify(Event[] events)
+ {
+ Jdwp jdwp = getDefault();
+
+ if (jdwp != null)
+ {
+ byte suspendPolicy = JdwpConstants.SuspendPolicy.NONE;
+ EventManager em = EventManager.getDefault();
+ ArrayList allEvents = new ArrayList ();
+ ArrayList allRequests = new ArrayList ();
+ for (int i = 0; i < events.length; ++i)
+ {
+ EventRequest[] r = em.getEventRequests(events[i]);
+ for (int j = 0; j < r.length; ++j)
+ {
+ /* This is hacky, but it's not clear whether this
+ can really happen, and if it does, what should
+ occur. */
+ allEvents.add (events[i]);
+ allRequests.add (r[j]);
+
+ // Perhaps this is overkill?
+ if (r[j].getSuspendPolicy() > suspendPolicy)
+ suspendPolicy = r[j].getSuspendPolicy();
+ }
+ }
+
+ try
+ {
+ Event[] e = new Event[allEvents.size()];
+ allEvents.toArray(e);
+ EventRequest[] r = new EventRequest[allRequests.size()];
+ allRequests.toArray(r);
+ sendEvents(r, e, suspendPolicy);
+ jdwp._enforceSuspendPolicy(suspendPolicy);
+ }
+ catch (Exception e)
+ {
+ /* Really not much we can do. For now, just print out
+ a warning to the user. */
+ System.out.println ("Jdwp.notify: caught exception: " + e);
+ }
+ }
+ }
+
+ /**
* Sends the event to the debugger.
*
* This method bypasses the event manager's filtering.
@@ -247,13 +302,30 @@ public class Jdwp
public static void sendEvent (EventRequest request, Event event)
throws IOException
{
- Jdwp jdwp = getDefault ();
+ sendEvents (new EventRequest[] { request }, new Event[] { event },
+ request.getSuspendPolicy());
+ }
+
+ /**
+ * Sends the events to the debugger.
+ *
+ * This method bypasses the event manager's filtering.
+ *
+ * @param requests list of debugger requests for the events
+ * @param events the events to send
+ * @param suspendPolicy the suspendPolicy enforced by the VM
+ * @throws IOException if a communications failure occurs
+ */
+ public static void sendEvents (EventRequest[] requests, Event[] events,
+ byte suspendPolicy)
+ throws IOException
+ {
+ Jdwp jdwp = getDefault();
if (jdwp != null)
{
- // !! May need to implement send queue?
synchronized (jdwp._connection)
{
- jdwp._connection.sendEvent (request, event);
+ jdwp._connection.sendEvents (requests, events, suspendPolicy);
}
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/event/Event.java b/libjava/classpath/gnu/classpath/jdwp/event/Event.java
index e91108a61a8..c89b25cb93b 100644
--- a/libjava/classpath/gnu/classpath/jdwp/event/Event.java
+++ b/libjava/classpath/gnu/classpath/jdwp/event/Event.java
@@ -1,5 +1,5 @@
/* Event.java -- a base class for all event types
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -135,25 +135,30 @@ public abstract class Event
public abstract Object getParameter (int type);
/**
- * Converts this event into to a JDWP packet
+ * Converts the events into to a single JDWP Event.COMPOSITE packet
*
* @param dos the stream to which to write data
- * @param request the request the wanted this notification
+ * @param events the events to package into the packet
+ * @param requests the corresponding event requests
+ * @param suspendPolicy the suspend policy enforced by the VM
* @returns a <code>JdwpPacket</code> of the events
*/
- public JdwpPacket toPacket (DataOutputStream dos, EventRequest request)
+ public static JdwpPacket toPacket (DataOutputStream dos,
+ Event[] events,
+ EventRequest[] requests,
+ byte suspendPolicy)
{
JdwpPacket pkt;
try
{
- dos.writeByte (request.getSuspendPolicy ());
- dos.writeInt (1);
- dos.writeByte (_eventKind);
- dos.writeInt (request.getId ());
- _writeData (dos);
-
- pkt = new JdwpCommandPacket (JdwpConstants.CommandSet.Event.CS_VALUE,
- JdwpConstants.CommandSet.Event.COMPOSITE);
+ dos.writeByte (suspendPolicy);
+ dos.writeInt (events.length);
+ for (int i = 0; i < events.length; ++i)
+ _toData (dos, events[i], requests[i]);
+
+ pkt
+ = new JdwpCommandPacket (JdwpConstants.CommandSet.Event.CS_VALUE,
+ JdwpConstants.CommandSet.Event.COMPOSITE);
}
catch (IOException ioe)
{
@@ -162,4 +167,14 @@ public abstract class Event
return pkt;
}
+
+ // Helper function for toPacket
+ private static void _toData (DataOutputStream dos, Event event,
+ EventRequest request)
+ throws IOException
+ {
+ dos.writeByte (event._eventKind);
+ dos.writeInt (request.getId ());
+ event._writeData (dos);
+ }
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java b/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java
index 54a7b08312d..aa3d5d6292c 100644
--- a/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java
+++ b/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java
@@ -1,5 +1,5 @@
/* EventManager.java -- event management and notification infrastructure
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -39,10 +39,12 @@ exception statement from your version. */
package gnu.classpath.jdwp.event;
+import gnu.classpath.jdwp.Jdwp;
import gnu.classpath.jdwp.VMVirtualMachine;
import gnu.classpath.jdwp.exception.InvalidEventTypeException;
import gnu.classpath.jdwp.exception.JdwpException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
@@ -130,9 +132,10 @@ public class EventManager
// only two: VM_INIT, VM_DEATH
try
{
+ byte sp = (Jdwp.suspendOnStartup()
+ ? EventRequest.SUSPEND_THREAD : EventRequest.SUSPEND_NONE);
requestEvent (new EventRequest (0,
- EventRequest.EVENT_VM_INIT,
- EventRequest.SUSPEND_NONE));
+ EventRequest.EVENT_VM_INIT, sp));
requestEvent (new EventRequest (0,
EventRequest.EVENT_VM_DEATH,
EventRequest.SUSPEND_NONE));
@@ -144,39 +147,39 @@ public class EventManager
}
/**
- * Returns a request for the given event. This method will only
+ * Returns all requests for the given event. This method will only
* be used if the <code>EventManager</code> is handling event filtering.
*
* @param event the event
- * @return request that was interested in this event
+ * @return requests that are interested in this event
* or <code>null</code> if none (and event should not be sent)
* @throws IllegalArgumentException for invalid event kind
*/
- public EventRequest getEventRequest (Event event)
+ public EventRequest[] getEventRequests(Event event)
{
- EventRequest interestedRequest = null;
+ ArrayList interestedEvents = new ArrayList();
Hashtable requests;
- Byte kind = new Byte (event.getEventKind ());
- requests = (Hashtable) _requests.get (kind);
+ Byte kind = new Byte(event.getEventKind());
+ requests = (Hashtable) _requests.get(kind);
if (requests == null)
{
// Did not get a valid event type
- throw new IllegalArgumentException ("invalid event kind: " + kind);
+ throw new IllegalArgumentException("invalid event kind: " + kind);
}
- boolean match = false;
// Loop through the requests. Must look at ALL requests in order
// to evaluate all filters (think count filter).
- // TODO: What if multiple matches? Spec isn't so clear on this.
- Iterator rIter = requests.values().iterator ();
- while (rIter.hasNext ())
+ Iterator rIter = requests.values().iterator();
+ while (rIter.hasNext())
{
- EventRequest request = (EventRequest) rIter.next ();
- if (request.matches (event))
- interestedRequest = request;
+ EventRequest request = (EventRequest) rIter.next();
+ if (request.matches(event))
+ interestedEvents.add(request);
}
- return interestedRequest;
+ EventRequest[] r = new EventRequest[interestedEvents.size()];
+ interestedEvents.toArray(r);
+ return r;
}
/**
diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java
index f9c507dfb16..4eff4409e8e 100644
--- a/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java
+++ b/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java
@@ -1,6 +1,6 @@
/* ThreadStartEvent.java -- An event specifying that a new thread
has started in the virtual machine
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -75,7 +75,7 @@ public class ThreadStartEvent
* @param thread the thread ID in which event occurred
*/
public ThreadStartEvent (Thread thread) {
- super (JdwpConstants.EventKind.THREAD_END);
+ super (JdwpConstants.EventKind.THREAD_START);
_thread = thread;
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java
index 7190317a4ae..a3125371c5d 100644
--- a/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java
+++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java
@@ -1,5 +1,5 @@
/* LocationOnlyFilter.java -- filter on location
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -49,13 +49,6 @@ import gnu.classpath.jdwp.util.Location;
* May be used with breakpoint, field access, field modification, step,
* and exception event kinds.
*
- * This "filter" is not really a filter. It is simply a way to communicate
- * location information for supported events in a generic way to ease
- * the burden of special casing several things in
- * EventReqeustCommandSet.executeSet.
- *
- * Consequently, this "filter" always matches any event.
- *
* @author Keith Seitz (keiths@redhat.com)
*/
public class LocationOnlyFilter
@@ -90,9 +83,12 @@ public class LocationOnlyFilter
*
* @param event the <code>Event</code> to scrutinize
*/
- public boolean matches (Event event)
+ public boolean matches(Event event)
{
- // This filter always matches. See comments in class javadoc.
- return true;
+ Location loc = (Location) event.getParameter(Event.EVENT_LOCATION);
+ if (loc != null)
+ return (getLocation().equals(loc));
+
+ return false;
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java
index 340546e887d..d18f6975ebf 100644
--- a/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java
+++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java
@@ -1,5 +1,5 @@
/* StepFilter.java -- a step filter
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -39,6 +39,7 @@ exception statement from your version. */
package gnu.classpath.jdwp.event.filters;
+import gnu.classpath.jdwp.JdwpConstants;
import gnu.classpath.jdwp.event.Event;
import gnu.classpath.jdwp.exception.InvalidThreadException;
import gnu.classpath.jdwp.id.ThreadId;
@@ -48,6 +49,12 @@ import gnu.classpath.jdwp.id.ThreadId;
* satisfy depth and size constraints. This modifier can only be used with
* step event kinds."
*
+ * This "filter" is not really a filter. It is simply a way to communicate
+ * stepping information in a convenient way between the JDWP backend and
+ * the virtual machine.
+ *
+ * Consequently, this "filter" always matches.
+ *
* @author Keith Seitz (keiths@redhat.com)
*/
public class StepFilter
@@ -115,7 +122,6 @@ public class StepFilter
*/
public boolean matches (Event event)
{
- // FIXME
- throw new RuntimeException ("StepFilter.matches not implemented");
+ return true;
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java b/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java
new file mode 100644
index 00000000000..5bf383f5841
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java
@@ -0,0 +1,56 @@
+/* AbsentInformationException.java -- information not present exception
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when the requested information is not available.
+ *
+ * @author Kyle Galloway (kgallowa@redhat.com)
+ */
+public class AbsentInformationException
+ extends JdwpException
+{
+ public AbsentInformationException(String str)
+ {
+ super(JdwpConstants.Error.ABSENT_INFORMATION, str);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java
new file mode 100644
index 00000000000..6d622a5e6f5
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java
@@ -0,0 +1,63 @@
+/* InvalidFrameException.java -- invalid jframeid
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when the debugger requests an invalid frame in the call
+ * stack.
+ *
+ * @author Kyle Galloway (kgallowa@redhat.com)
+ */
+public class InvalidFrameException
+ extends JdwpException
+{
+ public InvalidFrameException(long id)
+ {
+ super(JdwpConstants.Error.INVALID_FRAMEID,
+ "invalid frame id (" + id + ")");
+ }
+
+ public InvalidFrameException(String msg)
+ {
+ super(JdwpConstants.Error.INVALID_FRAMEID, msg);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java
new file mode 100644
index 00000000000..1827edab9a6
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java
@@ -0,0 +1,62 @@
+/* InvalidSlotException.java -- an invalid variable slot exception
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when an invalid Slot id is used by the debugger
+ * (i.e. when trying to access a variable slot which doesn't exist).
+ *
+ * @author Kyle Galloway (kgallowa@redhat.com)
+ */
+public class InvalidSlotException
+ extends JdwpException
+{
+ public InvalidSlotException(int slot)
+ {
+ super(JdwpConstants.Error.INVALID_SLOT, "invalid slot: " + slot);
+ }
+
+ public InvalidSlotException(String msg)
+ {
+ super(JdwpConstants.Error.INVALID_SLOT, msg);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java
new file mode 100644
index 00000000000..738b5e7348b
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java
@@ -0,0 +1,57 @@
+/* InvalidTagException.java -- an invalid type tag exception
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when an invalid tag is used by
+ * the debugger
+ *
+ * @author Kyle Galloway (kgallowa@redhat.com)
+ */
+public class InvalidTagException
+ extends JdwpException
+{
+ public InvalidTagException (byte tag)
+ {
+ super (JdwpConstants.Error.INVALID_TAG,
+ "invalid tag (" + tag + ")");
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java b/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java
new file mode 100644
index 00000000000..c6af65223d5
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java
@@ -0,0 +1,62 @@
+/* TypeMismatchException.java -- mismatched type of local variable
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception throw when attempting to access a local variable of the wrong
+ * type.
+ *
+ * @author Kyle Galloway (kgallowa@redhat.com)
+ */
+public class TypeMismatchException
+ extends JdwpException
+{
+ public TypeMismatchException(byte tag)
+ {
+ super(JdwpConstants.Error.TYPE_MISMATCH, "incorrect tag: " + tag);
+ }
+
+ public TypeMismatchException(String msg)
+ {
+ super(JdwpConstants.Error.TYPE_MISMATCH, msg);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java
new file mode 100644
index 00000000000..0e7b5e39cd8
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java
@@ -0,0 +1,79 @@
+/* NullObjectId.java -- special objectId for null values
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+import gnu.classpath.jdwp.util.NullObject;
+
+import java.lang.ref.SoftReference;
+
+/**
+ * This is a special case of an ObjectId. When a varaible slot contains
+ * null as its value, this is a valid value despite the fact that it does
+ * not reference an object. To represent this, this will always be the id
+ * of the NullObject (0).
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public class NullObjectId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = NullObject.class;
+
+ /**
+ * Constructs a new <code>NullObjectId</code>
+ */
+ public NullObjectId()
+ {
+ super();
+ setId((long) 0);
+ _reference = new SoftReference<NullObject>(new NullObject());
+ try
+ {
+ disableCollection();
+ }
+ catch(InvalidObjectException ex)
+ {
+ //This will not happen
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java
index a9dc6cc815f..0da0154d9d2 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java
@@ -1,6 +1,6 @@
/* ArrayReferenceCommandSet.java -- class to implement the Array
Reference Command Set
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -46,7 +46,8 @@ import gnu.classpath.jdwp.exception.JdwpException;
import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
import gnu.classpath.jdwp.exception.NotImplementedException;
import gnu.classpath.jdwp.id.ObjectId;
-import gnu.classpath.jdwp.util.Value;
+import gnu.classpath.jdwp.value.Value;
+import gnu.classpath.jdwp.value.ValueFactory;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -150,11 +151,11 @@ public class ArrayReferenceCommandSet
// tagged
for (int i = first; i < first + length; i++)
{
- Object value = Array.get(array, i);
+ Value val = ValueFactory.createFromObject(Array.get(array, i), clazz);
if (clazz.isPrimitive())
- Value.writeUntaggedValue(os, value);
+ val.writeUntagged(os);
else
- Value.writeTaggedValue(os, value);
+ val.writeTagged(os);
}
}
@@ -168,7 +169,7 @@ public class ArrayReferenceCommandSet
Class type = array.getClass().getComponentType();
for (int i = first; i < first + length; i++)
{
- Object value = Value.getUntaggedObj(bb, type);
+ Object value = Value.getUntaggedObject(bb, type);
Array.set(array, i, value);
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java
index a3a7ca05e59..b29b5710f91 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java
@@ -1,6 +1,6 @@
/* ClassTypeCommandSet.java -- class to implement the ClassType
Command Set
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -49,7 +49,8 @@ import gnu.classpath.jdwp.exception.NotImplementedException;
import gnu.classpath.jdwp.id.ObjectId;
import gnu.classpath.jdwp.id.ReferenceTypeId;
import gnu.classpath.jdwp.util.MethodResult;
-import gnu.classpath.jdwp.util.Value;
+import gnu.classpath.jdwp.value.Value;
+import gnu.classpath.jdwp.value.ValueFactory;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -128,7 +129,7 @@ public class ClassTypeCommandSet
{
ObjectId fieldId = idMan.readObjectId(bb);
Field field = (Field) (fieldId.getObject());
- Object value = Value.getUntaggedObj(bb, field.getType());
+ Object value = Value.getUntaggedObject(bb, field.getType());
try
{
field.setAccessible(true); // Might be a private field
@@ -154,7 +155,8 @@ public class ClassTypeCommandSet
Exception exception = mr.getThrownException();
ObjectId eId = idMan.getObjectId(exception);
- Value.writeTaggedValue(os, value);
+ Value val = ValueFactory.createFromObject(value, mr.getResultType());
+ val.writeTagged(os);
eId.writeTagged(os);
}
@@ -192,7 +194,7 @@ public class ClassTypeCommandSet
for (int i = 0; i < args; i++)
{
- values[i] = Value.getObj(bb);
+ values[i] = Value.getTaggedObject(bb);
}
int invokeOpts = bb.getInt();
@@ -207,6 +209,8 @@ public class ClassTypeCommandSet
MethodResult mr = VMVirtualMachine.executeMethod(null, thread,
clazz, method,
values, false);
+ mr.setResultType(method.getReturnType());
+
if (suspend)
VMVirtualMachine.resumeAllThreads ();
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java
index 59cfb94d39b..d7ebbc3a358 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java
@@ -1,6 +1,6 @@
/* EventRequestCommandSet.java -- class to implement the EventRequest Command
Set
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -40,6 +40,7 @@ exception statement from your version. */
package gnu.classpath.jdwp.processor;
import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.VMVirtualMachine;
import gnu.classpath.jdwp.event.EventManager;
import gnu.classpath.jdwp.event.EventRequest;
import gnu.classpath.jdwp.event.filters.ClassExcludeFilter;
@@ -113,6 +114,28 @@ public class EventRequestCommandSet
byte suspendPolicy = bb.get();
int modifiers = bb.getInt();
+ switch (eventKind)
+ {
+ case JdwpConstants.EventKind.FIELD_ACCESS:
+ if (!VMVirtualMachine.canWatchFieldAccess)
+ {
+ String msg = "watching field accesses is not supported";
+ throw new NotImplementedException(msg);
+ }
+ break;
+
+ case JdwpConstants.EventKind.FIELD_MODIFICATION:
+ if (!VMVirtualMachine.canWatchFieldModification)
+ {
+ String msg = "watching field modifications is not supported";
+ throw new NotImplementedException(msg);
+ }
+ break;
+
+ default:
+ // okay
+ }
+
EventRequest eventReq = new EventRequest(eventKind, suspendPolicy);
IEventFilter filter = null;
ReferenceTypeId refId;
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java
index dcfe7a6fc84..4d1bf709800 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java
@@ -1,5 +1,5 @@
/* MethodCommandSet.java -- class to implement the Method Command Set
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -40,10 +40,11 @@ package gnu.classpath.jdwp.processor;
import gnu.classpath.jdwp.JdwpConstants;
import gnu.classpath.jdwp.VMMethod;
+import gnu.classpath.jdwp.VMVirtualMachine;
import gnu.classpath.jdwp.exception.JdwpException;
import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
import gnu.classpath.jdwp.exception.NotImplementedException;
-import gnu.classpath.jdwp.id.ClassReferenceTypeId;
+import gnu.classpath.jdwp.id.ReferenceTypeId;
import gnu.classpath.jdwp.util.LineTable;
import gnu.classpath.jdwp.util.VariableTable;
@@ -99,8 +100,7 @@ public class MethodCommandSet
private void executeLineTable(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ClassReferenceTypeId refId
- = (ClassReferenceTypeId) idMan.readReferenceTypeId(bb);
+ ReferenceTypeId refId = idMan.readReferenceTypeId(bb);
Class clazz = refId.getType();
VMMethod method = VMMethod.readId(clazz, bb);
@@ -111,8 +111,7 @@ public class MethodCommandSet
private void executeVariableTable(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ClassReferenceTypeId refId
- = (ClassReferenceTypeId) idMan.readReferenceTypeId(bb);
+ ReferenceTypeId refId = idMan.readReferenceTypeId(bb);
Class clazz = refId.getType();
VMMethod method = VMMethod.readId(clazz, bb);
@@ -121,11 +120,20 @@ public class MethodCommandSet
}
private void executeByteCodes(ByteBuffer bb, DataOutputStream os)
- throws JdwpException
+ throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException("Command ByteCodes not implemented.");
+ if (!VMVirtualMachine.canGetBytecodes)
+ {
+ String msg = "getting bytecodes is unsupported";
+ throw new NotImplementedException(msg);
+ }
+
+ ReferenceTypeId id = idMan.readReferenceTypeId(bb);
+ Class klass = id.getType();
+ VMMethod method = VMMethod.readId(klass, bb);
+ byte[] bytecode = VMVirtualMachine.getBytecodes(method);
+ os.writeInt(bytecode.length);
+ os.write(bytecode);
}
private void executeIsObsolete(ByteBuffer bb, DataOutputStream os)
@@ -143,7 +151,7 @@ public class MethodCommandSet
{
// We don't have generics yet
throw new NotImplementedException(
- "Command SourceDebugExtension not implemented.");
+ "Command VariableTableWithGeneric not implemented.");
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java
index ef421ea5b28..ed83fd2f94b 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java
@@ -1,6 +1,6 @@
/* ObjectReferenceCommandSet.java -- class to implement the ObjectReference
Command Set
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -47,8 +47,10 @@ import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
import gnu.classpath.jdwp.exception.NotImplementedException;
import gnu.classpath.jdwp.id.ObjectId;
import gnu.classpath.jdwp.id.ReferenceTypeId;
-import gnu.classpath.jdwp.util.Value;
import gnu.classpath.jdwp.util.MethodResult;
+import gnu.classpath.jdwp.util.MonitorInfo;
+import gnu.classpath.jdwp.value.Value;
+import gnu.classpath.jdwp.value.ValueFactory;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -137,7 +139,9 @@ public class ObjectReferenceCommandSet
{
field.setAccessible(true); // Might be a private field
Object value = field.get(obj);
- Value.writeTaggedValue(os, value);
+ Value val = ValueFactory.createFromObject(value,
+ field.getType());
+ val.writeTagged(os);
}
catch (IllegalArgumentException ex)
{
@@ -163,7 +167,7 @@ public class ObjectReferenceCommandSet
for (int i = 0; i < numFields; i++)
{
Field field = (Field) idMan.readObjectId(bb).getObject();
- Object value = Value.getUntaggedObj(bb, field.getType());
+ Object value = Value.getUntaggedObject(bb, field.getType());
try
{
field.setAccessible(true); // Might be a private field
@@ -183,13 +187,18 @@ public class ObjectReferenceCommandSet
}
private void executeMonitorInfo(ByteBuffer bb, DataOutputStream os)
- throws JdwpException
+ throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException(
- "Command ExecuteMonitorInfo not implemented.");
+ if (!VMVirtualMachine.canGetMonitorInfo)
+ {
+ String msg = "getting monitor info not supported";
+ throw new NotImplementedException(msg);
+ }
+ ObjectId oid = idMan.readObjectId(bb);
+ Object obj = oid.getObject();
+ MonitorInfo info = VMVirtualMachine.getMonitorInfo(obj);
+ info.write(os);
}
private void executeInvokeMethod(ByteBuffer bb, DataOutputStream os)
@@ -212,7 +221,7 @@ public class ObjectReferenceCommandSet
for (int i = 0; i < args; i++)
{
- values[i] = Value.getObj(bb);
+ values[i] = Value.getTaggedObject(bb);
}
int invokeOptions = bb.getInt();
@@ -232,11 +241,14 @@ public class ObjectReferenceCommandSet
MethodResult mr = VMVirtualMachine.executeMethod(obj, thread,
clazz, method,
values, nonVirtual);
+ mr.setResultType (method.getReturnType());
+
Object value = mr.getReturnedValue();
Exception exception = mr.getThrownException();
ObjectId eId = idMan.getObjectId(exception);
- Value.writeTaggedValue(os, value);
+ Value val = ValueFactory.createFromObject(value, mr.getResultType());
+ val.writeTagged(os);
eId.writeTagged(os);
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
index b76143f92c9..c9b329869d7 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
@@ -1,6 +1,6 @@
/* ReferenceTypeCommandSet.java -- class to implement the ReferenceType
Command Set
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -51,7 +51,8 @@ import gnu.classpath.jdwp.id.ObjectId;
import gnu.classpath.jdwp.id.ReferenceTypeId;
import gnu.classpath.jdwp.util.JdwpString;
import gnu.classpath.jdwp.util.Signature;
-import gnu.classpath.jdwp.util.Value;
+import gnu.classpath.jdwp.value.Value;
+import gnu.classpath.jdwp.value.ValueFactory;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -182,8 +183,7 @@ public class ReferenceTypeCommandSet
private void executeMethods(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ClassReferenceTypeId refId
- = (ClassReferenceTypeId) idMan.readReferenceTypeId(bb);
+ ReferenceTypeId refId = idMan.readReferenceTypeId(bb);
Class clazz = refId.getType();
VMMethod[] methods = VMVirtualMachine.getAllClassMethods(clazz);
@@ -220,7 +220,9 @@ public class ReferenceTypeCommandSet
{
field.setAccessible(true); // Might be a private field
Object value = field.get(null);
- Value.writeTaggedValue(os, value);
+ Value val = ValueFactory.createFromObject(value,
+ field.getType());
+ val.writeTagged(os);
}
catch (IllegalArgumentException ex)
{
@@ -303,10 +305,15 @@ public class ReferenceTypeCommandSet
private void executeSourceDebugExtension(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException(
- "Command SourceDebugExtension not implemented.");
+ if (!VMVirtualMachine.canGetSourceDebugExtension)
+ {
+ String msg = "source debug extension is not supported";
+ throw new NotImplementedException(msg);
+ }
+
+ ReferenceTypeId id = idMan.readReferenceTypeId(bb);
+ String ext = VMVirtualMachine.getSourceDebugExtension (id.getType());
+ JdwpString.writeString(os, ext);
}
private void executeSignatureWithGeneric(ByteBuffer bb, DataOutputStream os)
@@ -314,7 +321,7 @@ public class ReferenceTypeCommandSet
{
// We don't have generics yet
throw new NotImplementedException(
- "Command SourceDebugExtension not implemented.");
+ "Command SignatureWithGeneric not implemented.");
}
private void executeFieldWithGeneric(ByteBuffer bb, DataOutputStream os)
@@ -322,7 +329,7 @@ public class ReferenceTypeCommandSet
{
// We don't have generics yet
throw new NotImplementedException(
- "Command SourceDebugExtension not implemented.");
+ "Command executeFieldWithGeneric not implemented.");
}
private void executeMethodsWithGeneric(ByteBuffer bb, DataOutputStream os)
@@ -330,6 +337,6 @@ public class ReferenceTypeCommandSet
{
// We don't have generics yet
throw new NotImplementedException(
- "Command SourceDebugExtension not implemented.");
+ "Command executeMethodsWithGeneric not implemented.");
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java
index 7890a8e4b1b..2d90e8064ae 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java
@@ -1,5 +1,5 @@
/* StackFrameCommandSet.java -- class to implement the StackFrame Command Set
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -45,8 +45,10 @@ import gnu.classpath.jdwp.VMVirtualMachine;
import gnu.classpath.jdwp.exception.JdwpException;
import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
import gnu.classpath.jdwp.exception.NotImplementedException;
-import gnu.classpath.jdwp.id.ObjectId;
-import gnu.classpath.jdwp.util.Value;
+import gnu.classpath.jdwp.id.ThreadId;
+import gnu.classpath.jdwp.value.ObjectValue;
+import gnu.classpath.jdwp.value.Value;
+import gnu.classpath.jdwp.value.ValueFactory;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -98,8 +100,8 @@ public class StackFrameCommandSet
private void executeGetValues(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ObjectId tId = idMan.readObjectId(bb);
- Thread thread = (Thread) tId.getObject();
+ ThreadId tId = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tId.getThread();
// Although Frames look like other ids they are not. First they are not
// ObjectIds since they don't exist in the users code. Storing them as an
@@ -107,31 +109,33 @@ public class StackFrameCommandSet
// has a reference to them. Furthermore they are not ReferenceTypeIds since
// these are held permanently and we want these to be held only as long as
// the Thread is suspended.
- VMFrame frame = VMVirtualMachine.getFrame(thread, bb);
+ long frameID = bb.getLong();
+ VMFrame frame = VMVirtualMachine.getFrame(thread, frameID);
int slots = bb.getInt();
os.writeInt(slots); // Looks pointless but this is the protocol
for (int i = 0; i < slots; i++)
{
int slot = bb.getInt();
byte sig = bb.get();
- Object val = frame.getValue(slot);
- Value.writeTaggedValue(os, val);
+ Value val = frame.getValue(slot, sig);
+ val.writeTagged(os);
}
}
private void executeSetValues(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ObjectId tId = idMan.readObjectId(bb);
- Thread thread = (Thread) tId.getObject();
+ ThreadId tId = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tId.getThread();
- VMFrame frame = VMVirtualMachine.getFrame(thread, bb);
+ long frameID = bb.getLong();
+ VMFrame frame = VMVirtualMachine.getFrame(thread, frameID);
int slots = bb.getInt();
for (int i = 0; i < slots; i++)
{
int slot = bb.getInt();
- Object value = Value.getObj(bb);
+ Value value = ValueFactory.createFromTagged(bb);
frame.setValue(slot, value);
}
}
@@ -139,20 +143,28 @@ public class StackFrameCommandSet
private void executeThisObject(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- ObjectId tId = idMan.readObjectId(bb);
- Thread thread = (Thread) tId.getObject();
+ ThreadId tId = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tId.getThread();
- VMFrame frame = VMVirtualMachine.getFrame(thread, bb);
+ long frameID = bb.getLong();
+ VMFrame frame = VMVirtualMachine.getFrame(thread, frameID);
- Object thisObject = frame.getObject();
- Value.writeTaggedValue(os, thisObject);
+ ObjectValue objVal = new ObjectValue(frame.getObject());
+ objVal.writeTagged(os);
}
private void executePopFrames(ByteBuffer bb, DataOutputStream os)
- throws JdwpException
+ throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException("Command PopFrames not implemented.");
+ if (!VMVirtualMachine.canPopFrames)
+ {
+ String msg = "popping frames is unsupported";
+ throw new NotImplementedException(msg);
+ }
+
+ ThreadId tid = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tid.getThread();
+ long fid = bb.getLong();
+ VMVirtualMachine.popFrames(thread, fid);
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java
index fd7fa743e7a..6fbcf698f8f 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java
@@ -1,5 +1,5 @@
/* ThreadReferenceCommandSet.java -- class to implement the ThreadReference
- Command Set Copyright (C) 2005 Free Software Foundation
+ Command Set Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -142,7 +142,7 @@ public class ThreadReferenceCommandSet
{
ThreadId tid = (ThreadId) idMan.readObjectId(bb);
Thread thread = tid.getThread();
- VMVirtualMachine.suspendThread(thread);
+ VMVirtualMachine.resumeThread(thread);
}
private void executeStatus(ByteBuffer bb, DataOutputStream os)
@@ -198,22 +198,42 @@ public class ThreadReferenceCommandSet
}
private void executeOwnedMonitors(ByteBuffer bb, DataOutputStream os)
- throws JdwpException
+ throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException(
- "Command OwnedMonitors not implemented.");
+ if (!VMVirtualMachine.canGetOwnedMonitorInfo)
+ {
+ String msg = "getting owned monitors is not supported";
+ throw new NotImplementedException(msg);
+ }
+
+ ThreadId tid = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tid.getThread();
+ Object[] monitors = VMVirtualMachine.getOwnedMonitors(thread);
+
+ os.write(monitors.length);
+ for (int i = 0; i < monitors.length; ++i)
+ {
+ ObjectId id = idMan.getObjectId(monitors[i]);
+ id.writeTagged(os);
+ }
}
private void executeCurrentContendedMonitor(ByteBuffer bb,
DataOutputStream os)
- throws JdwpException
+ throws JdwpException, IOException
{
- // This command is optional, determined by VirtualMachines CapabilitiesNew
- // so we'll leave it till later to implement
- throw new NotImplementedException(
- "Command CurrentContentedMonitors not implemented.");
+ if (!VMVirtualMachine.canGetCurrentContendedMonitor)
+ {
+ String msg = "getting current contended monitor is not supported";
+ throw new NotImplementedException(msg);
+ }
+
+ ThreadId tid = (ThreadId) idMan.readObjectId(bb);
+ Thread thread = tid.getThread();
+
+ Object monitor = VMVirtualMachine.getCurrentContendedMonitor(thread);
+ ObjectId id = idMan.getObjectId(monitor);
+ id.writeTagged(os);
}
private void executeStop(ByteBuffer bb, DataOutputStream os)
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java
index a7edb287a56..e2703908ba2 100644
--- a/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java
@@ -1,6 +1,6 @@
/* VirtualMachineCommandSet.java -- class to implement the VirtualMachine
Command Set
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -54,6 +54,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
@@ -179,7 +180,8 @@ public class VirtualMachineCommandSet
ArrayList allMatchingClasses = new ArrayList();
// This will be an Iterator over all loaded Classes
- Iterator iter = VMVirtualMachine.getAllLoadedClasses();
+ Collection classes = VMVirtualMachine.getAllLoadedClasses();
+ Iterator iter = classes.iterator ();
while (iter.hasNext())
{
@@ -203,22 +205,11 @@ public class VirtualMachineCommandSet
private void executeAllClasses(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- // Disable garbage collection while we're collecting the info on loaded
- // classes so we some classes don't get collected between the time we get
- // the count and the time we get the list
- //VMVirtualMachine.disableGarbageCollection();
+ Collection classes = VMVirtualMachine.getAllLoadedClasses();
+ os.writeInt(classes.size ());
- int classCount = VMVirtualMachine.getAllLoadedClassesCount();
- os.writeInt(classCount);
-
- // This will be an Iterator over all loaded Classes
- Iterator iter = VMVirtualMachine.getAllLoadedClasses();
- //VMVirtualMachine.enableGarbageCollection();
- int count = 0;
-
- // Note it's possible classes were created since out classCount so make
- // sure we don't write more classes than we told the debugger
- while (iter.hasNext() && count++ < classCount)
+ Iterator iter = classes.iterator ();
+ while (iter.hasNext())
{
Class clazz = (Class) iter.next();
ReferenceTypeId id = idMan.getReferenceTypeId(clazz);
@@ -340,14 +331,13 @@ public class VirtualMachineCommandSet
private void executeCapabilities(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- // Store these somewhere?
- os.writeBoolean(false); // canWatchFieldModification
- os.writeBoolean(false); // canWatchFieldAccess
- os.writeBoolean(false); // canGetBytecodes
- os.writeBoolean(false); // canGetSyntheticAttribute
- os.writeBoolean(false); // canGetOwnedMonitorInfo
- os.writeBoolean(false); // canGetCurrentContendedMonitor
- os.writeBoolean(false); // canGetMonitorInfo
+ os.writeBoolean(VMVirtualMachine.canWatchFieldModification);
+ os.writeBoolean(VMVirtualMachine.canWatchFieldAccess);
+ os.writeBoolean(VMVirtualMachine.canGetBytecodes);
+ os.writeBoolean(VMVirtualMachine.canGetSyntheticAttribute);
+ os.writeBoolean(VMVirtualMachine.canGetOwnedMonitorInfo);
+ os.writeBoolean(VMVirtualMachine.canGetCurrentContendedMonitor);
+ os.writeBoolean(VMVirtualMachine.canGetMonitorInfo);
}
private void executeClassPaths(ByteBuffer bb, DataOutputStream os)
@@ -401,43 +391,60 @@ public class VirtualMachineCommandSet
private void executeCapabilitiesNew(ByteBuffer bb, DataOutputStream os)
throws JdwpException, IOException
{
- // Store these somewhere?
final int CAPABILITIES_NEW_SIZE = 32;
- os.writeBoolean(false); // canWatchFieldModification
- os.writeBoolean(false); // canWatchFieldAccess
- os.writeBoolean(false); // canGetBytecodes
- os.writeBoolean(false); // canGetSyntheticAttribute
- os.writeBoolean(false); // canGetOwnedMonitorInfo
- os.writeBoolean(false); // canGetCurrentContendedMonitor
- os.writeBoolean(false); // canGetMonitorInfo
- os.writeBoolean(false); // canRedefineClasses
- os.writeBoolean(false); // canAddMethod
- os.writeBoolean(false); // canUnrestrictedlyRedefineClasses
- os.writeBoolean(false); // canPopFrames
- os.writeBoolean(false); // canUseInstanceFilters
- os.writeBoolean(false); // canGetSourceDebugExtension
- os.writeBoolean(false); // canRequestVMDeathEvent
- os.writeBoolean(false); // canSetDefaultStratum
+
+ executeCapabilities(bb, os);
+ os.writeBoolean(VMVirtualMachine.canRedefineClasses);
+ os.writeBoolean(VMVirtualMachine.canAddMethod);
+ os.writeBoolean(VMVirtualMachine.canUnrestrictedlyRedefineClasses);
+ os.writeBoolean(VMVirtualMachine.canPopFrames);
+ os.writeBoolean(VMVirtualMachine.canUseInstanceFilters);
+ os.writeBoolean(VMVirtualMachine.canGetSourceDebugExtension);
+ os.writeBoolean(VMVirtualMachine.canRequestVMDeathEvent);
+ os.writeBoolean(VMVirtualMachine.canSetDefaultStratum);
for (int i = 15; i < CAPABILITIES_NEW_SIZE; i++)
- // Future capabilities
- // currently unused
- os.writeBoolean(false); // Set to false
+ {
+ // Future capabilities (currently unused)
+ os.writeBoolean(false);
+ }
}
private void executeRedefineClasses(ByteBuffer bb, DataOutputStream os)
throws JdwpException
{
- // Optional command, don't implement
- throw new NotImplementedException(
- "Command VirtualMachine.RedefineClasses not implemented");
+ if (!VMVirtualMachine.canRedefineClasses)
+ {
+ String msg = "redefinition of classes is not supported";
+ throw new NotImplementedException(msg);
+ }
+
+ int classes = bb.getInt();
+ Class[] types = new Class[classes];
+ byte[][] bytecodes = new byte[classes][];
+ for (int i = 0; i < classes; ++i)
+ {
+ ReferenceTypeId id = idMan.readReferenceTypeId(bb);
+ int classfile = bb.getInt();
+ byte[] bytecode = new byte[classfile];
+ bb.get(bytecode);
+ types[i] = id.getType();
+ bytecodes[i] = bytecode;
+ }
+
+ VMVirtualMachine.redefineClasses (types, bytecodes);
}
private void executeSetDefaultStratum(ByteBuffer bb, DataOutputStream os)
throws JdwpException
{
- // Optional command, don't implement
- throw new NotImplementedException(
- "Command VirtualMachine.SetDefaultStratum not implemented");
+ if (!VMVirtualMachine.canSetDefaultStratum)
+ {
+ String msg = "setting the default stratum is not supported";
+ throw new NotImplementedException(msg);
+ }
+
+ String stratum = JdwpString.readString(bb);
+ VMVirtualMachine.setDefaultStratum(stratum);
}
private void executeAllClassesWithGeneric(ByteBuffer bb, DataOutputStream os)
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java
index 82a2380bb7b..44158aa26ec 100644
--- a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java
@@ -1,5 +1,5 @@
/* JdwpConnection.java -- A JDWP-speaking connection
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -267,13 +267,17 @@ public class JdwpConnection
}
/**
- * Send an event notification to the debugger
+ * Send an event notification to the debugger. Note that this
+ * method will only send out one notification: all the events
+ * are passed in a single Event.COMPOSITE packet.
*
- * @param request the debugger request that wanted this event
- * @param event the event
+ * @param requests debugger requests for events
+ * @param events the events to send
+ * @param suspendPolicy the suspend policy enforced by the VM
* @throws IOException
*/
- public void sendEvent (EventRequest request, Event event)
+ public void sendEvents(EventRequest[] requests, Event[] events,
+ byte suspendPolicy)
throws IOException
{
JdwpPacket pkt;
@@ -281,7 +285,7 @@ public class JdwpConnection
synchronized (_bytes)
{
_bytes.reset ();
- pkt = event.toPacket (_doStream, request);
+ pkt = Event.toPacket (_doStream, events, requests, suspendPolicy);
pkt.setData (_bytes.toByteArray ());
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java
index 49d9e1f3bf6..3b0a8e7fe12 100644
--- a/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java
@@ -1,5 +1,5 @@
/* SocketTransport.java -- a socket transport
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -89,27 +89,36 @@ class SocketTransport
* @param properties the properties of the JDWP session
* @throws TransportException for any configury errors
*/
- public void configure (HashMap properties)
+ public void configure(HashMap properties)
throws TransportException
{
- // Get address [form: "hostname:port"]
- String p = (String) properties.get (_PROPERTY_ADDRESS);
+ // Get server [form: "y" or "n"]
+ String p = (String) properties.get(_PROPERTY_SERVER);
if (p != null)
{
- String[] s = p.split (":");
- if (s.length == 2)
- {
- _host = s[0];
- _port = Integer.parseInt (s[1]);
- }
+ if (p.toLowerCase().equals("y"))
+ _server = true;
}
- // Get server [form: "y" or "n"]
- p = (String) properties.get (_PROPERTY_SERVER);
+ // Get address [form: "hostname:port"]
+ p = (String) properties.get(_PROPERTY_ADDRESS);
if (p != null)
{
- if (p.toLowerCase().equals ("y"))
- _server = true;
+ String[] s = p.split(":");
+ if (s.length == 1)
+ {
+ // Port number only. Assume "localhost"
+ _port = Integer.parseInt(s[0]);
+ _host = "localhost";
+ }
+ else
+ {
+ if (s[0].length() == 0)
+ _host = "localhost";
+ else
+ _host = s[0];
+ _port = Integer.parseInt(s[1]);
+ }
}
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/Location.java b/libjava/classpath/gnu/classpath/jdwp/util/Location.java
index 89e81e563a1..ff045a5eccc 100644
--- a/libjava/classpath/gnu/classpath/jdwp/util/Location.java
+++ b/libjava/classpath/gnu/classpath/jdwp/util/Location.java
@@ -1,5 +1,5 @@
/* Location.java -- class to read/write JDWP locations
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -153,4 +153,16 @@ public class Location
{
return method.toString () + "." + index;
}
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof Location)
+ {
+ Location l = (Location) obj;
+ return (getMethod().equals(l.getMethod())
+ && getIndex() == l.getIndex());
+ }
+
+ return false;
+ }
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java b/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java
index a9c1b330579..190511de83f 100644
--- a/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java
+++ b/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java
@@ -52,6 +52,9 @@ public class MethodResult
// Any Exception that was thrown by the executing method
private Exception thrownException;
+
+ // The type of this result
+ private Class resType;
public Object getReturnedValue()
{
@@ -73,4 +76,14 @@ public class MethodResult
this.thrownException = thrownException;
}
+ public Class getResultType()
+ {
+ return resType;
+ }
+
+ public void setResultType(Class type)
+ {
+ resType = type;
+ }
+
}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java b/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java
new file mode 100644
index 00000000000..f28eabf834e
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java
@@ -0,0 +1,76 @@
+/* MonitorInfo.java -- class used to return monitor information
+ for JDWP.
+
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.util;
+
+import gnu.classpath.jdwp.VMIdManager;
+import gnu.classpath.jdwp.id.ObjectId;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * This class is used to pass monitor information between
+ * the JDWP back-end and the virtual machine.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class MonitorInfo
+{
+ public int entryCount;
+ public Thread owner;
+ public Thread[] waiters;
+
+ public void write(DataOutputStream os)
+ throws IOException
+ {
+ VMIdManager idm = VMIdManager.getDefault();
+ ObjectId id = idm.getObjectId(owner);
+ id.write(os);
+ os.write(entryCount);
+ os.write(waiters.length);
+ for (int i = 0; i < waiters.length; ++i)
+ {
+ id = idm.getObjectId(waiters[i]);
+ id.write(os);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java b/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java
new file mode 100644
index 00000000000..ec762fc2fbf
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java
@@ -0,0 +1,50 @@
+/* NullObject.java -- placeholder for null values
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.util;
+
+/**
+ * This is a placeholder for null. There are several places in JDWP where null
+ * is a valid value (i.e. when geting the value of a variable slot that
+ * contains a null reference at that time). This class distinguishes between
+ * these "meaningful" null values and invalid null pointers.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public class NullObject
+{
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/Value.java b/libjava/classpath/gnu/classpath/jdwp/util/Value.java
index 414c4a33b82..e69de29bb2d 100644
--- a/libjava/classpath/gnu/classpath/jdwp/util/Value.java
+++ b/libjava/classpath/gnu/classpath/jdwp/util/Value.java
@@ -1,301 +0,0 @@
-/* Value.java -- class to read/write JDWP tagged and untagged values
- Copyright (C) 2005, 2006, Free Software Foundation
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath 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 for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.classpath.jdwp.util;
-
-import gnu.classpath.jdwp.JdwpConstants;
-import gnu.classpath.jdwp.VMIdManager;
-import gnu.classpath.jdwp.exception.InvalidFieldException;
-import gnu.classpath.jdwp.exception.JdwpException;
-import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
-import gnu.classpath.jdwp.exception.NotImplementedException;
-import gnu.classpath.jdwp.id.ObjectId;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * A class to read/write JDWP tagged and untagged values.
- *
- * @author Aaron Luchko <aluchko@redhat.com>
- */
-public class Value
-{
- /**
- * Will write the given object as an untagged value to the DataOutputStream.
- *
- * @param os write the value here
- * @param obj the Object to write
- * @throws IOException
- * @throws InvalidFieldException
- */
- public static void writeUntaggedValue(DataOutputStream os, Object obj)
- throws JdwpException, IOException
- {
- writeValue(os, obj, false);
- }
-
- /**
- * Will write the given object as a tagged value to the DataOutputStream.
- *
- * @param os write the value here
- * @param obj the Object to write
- * @throws IOException
- * @throws InvalidFieldException
- */
- public static void writeTaggedValue(DataOutputStream os, Object obj)
- throws JdwpException, IOException
- {
- writeValue(os, obj, true);
- }
-
- /**
- * Will write the given object as either a value or an untagged value to the
- * DataOutputStream.
- *
- * @param os write the value here
- * @param obj the Object to write
- * @param tagged true if the value is tagged, false otherwise
- * @throws IOException
- * @throws InvalidFieldException
- */
- private static void writeValue(DataOutputStream os, Object obj,
- boolean tagged)
- throws IOException, JdwpException
- {
- Class clazz = obj.getClass();
- if (clazz.isPrimitive())
- {
- if (clazz == byte.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.BYTE);
- os.writeByte(((Byte) obj).byteValue());
- }
- else if (clazz == char.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.CHAR);
- os.writeChar(((Character) obj).charValue());
- }
- else if (clazz == float.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.FLOAT);
- os.writeFloat(((Float) obj).floatValue());
- }
- else if (clazz == double.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.DOUBLE);
- os.writeDouble(((Double) obj).doubleValue());
- }
- else if (clazz == int.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.BYTE);
- os.writeInt(((Integer) obj).intValue());
- }
- else if (clazz == long.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.LONG);
- os.writeLong(((Long) obj).longValue());
- }
- else if (clazz == short.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.SHORT);
- os.writeInt(((Short) obj).shortValue());
- }
- else if (clazz == void.class)
- { // A 'void' has no data
- if (tagged)
- os.writeByte(JdwpConstants.Tag.VOID);
- }
- else if (clazz == boolean.class)
- {
- if (tagged)
- os.writeByte(JdwpConstants.Tag.BOOLEAN);
- os.writeBoolean(((Boolean) obj).booleanValue());
- }
- else
- { // This shouldn't be possible
- throw new JdwpInternalErrorException(
- "Field has invalid primitive!");
- }
- }
- else
- {
- // Object is an Object, not a primitive type wrapped in an object
- // Write the appropriate tag
- if (tagged)
- {
- if (clazz.isArray())
- os.writeByte(JdwpConstants.Tag.ARRAY);
- else if (obj instanceof String)
- os.writeByte(JdwpConstants.Tag.STRING);
- else if (obj instanceof Thread)
- os.writeByte(JdwpConstants.Tag.THREAD);
- else if (obj instanceof ThreadGroup)
- os.writeByte(JdwpConstants.Tag.THREAD_GROUP);
- else if (obj instanceof ClassLoader)
- os.writeByte(JdwpConstants.Tag.CLASS_LOADER);
- else if (obj instanceof Class)
- os.writeByte(JdwpConstants.Tag.CLASS_OBJECT);
- else
- os.writeByte(JdwpConstants.Tag.OBJECT);
- }
- ObjectId oid = VMIdManager.getDefault().getObjectId(obj);
- oid.write(os);
- }
- }
-
- /**
- * Reads the appropriate object for the tagged value contained in the
- * ByteBuffer.
- *
- * @param bb contains the Object
- * @return The Object referenced by the value
- * @throws JdwpException
- * @throws IOException
- */
- public static Object getObj(ByteBuffer bb)
- throws JdwpException, IOException
- {
- return getUntaggedObj(bb, bb.get());
- }
-
- /**
- * Reads an object of the given Class from the untagged value contained
- * in the ByteBuffer.
- *
- * @param bb contains the Object
- * @param type corresponds to the TAG of value to be read
- * @return the resultant object
- * @throws JdwpException
- * @throws IOException
- */
- public static Object getUntaggedObj(ByteBuffer bb, Class type)
- throws JdwpException, IOException
- {
- if (type.isPrimitive())
- {
- if (type == byte.class)
- return new Byte(bb.get());
- else if (type == char.class)
- return new Character(bb.getChar());
- else if (type == float.class)
- return new Float(bb.getFloat());
- else if (type == double.class)
- return new Double(bb.getDouble());
- else if (type == int.class)
- return new Integer(bb.getInt());
- else if (type == long.class)
- return new Long(bb.getLong());
- else if (type == short.class)
- return new Short(bb.getShort());
- else if (type == boolean.class)
- return Boolean.valueOf(bb.get() != 0);
- else if (type == void.class)
- return new byte[0];
- else
- { // This shouldn't be possible
- throw new JdwpInternalErrorException(
- "Field has invalid primitive!");
- }
- }
- else
- {
- // Field is an object
- ObjectId oid = VMIdManager.getDefault().readObjectId(bb);
- return oid.getObject();
- }
- }
-
- /**
- * Reads the an object of the given Class from the untagged value contained
- * in the ByteBuffer.
- *
- * @param bb contains the Object
- * @param tag TAG of the Value to be read
- * @return the object
- * @throws JdwpException
- * @throws IOException
- */
- public static Object getUntaggedObj(ByteBuffer bb, byte tag)
- throws JdwpException, IOException
- {
- switch (tag)
- {
- case JdwpConstants.Tag.BYTE:
- return new Byte(bb.get());
- case JdwpConstants.Tag.CHAR:
- return new Character(bb.getChar());
- case JdwpConstants.Tag.FLOAT:
- return new Float(bb.getFloat());
- case JdwpConstants.Tag.DOUBLE:
- return new Double(bb.getDouble());
- case JdwpConstants.Tag.INT:
- return new Integer(bb.getInt());
- case JdwpConstants.Tag.LONG:
- return new Long(bb.getLong());
- case JdwpConstants.Tag.SHORT:
- return new Short(bb.getShort());
- case JdwpConstants.Tag.VOID:
- return new byte[0];
- case JdwpConstants.Tag.BOOLEAN:
- return (bb.get() == 0) ? new Boolean(false) : new Boolean(true);
- case JdwpConstants.Tag.STRING:
- return JdwpString.readString(bb);
- case JdwpConstants.Tag.ARRAY:
- case JdwpConstants.Tag.THREAD:
- case JdwpConstants.Tag.OBJECT:
- case JdwpConstants.Tag.THREAD_GROUP:
- case JdwpConstants.Tag.CLASS_LOADER:
- case JdwpConstants.Tag.CLASS_OBJECT:
- // All these cases are ObjectIds
- ObjectId oid = VMIdManager.getDefault().readObjectId(bb);
- return oid.getObject();
- default:
- throw new NotImplementedException("Tag " + tag
- + " is not implemented.");
- }
- }
-}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java b/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java
index 22d8c7dd621..f30c2158100 100644
--- a/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java
+++ b/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java
@@ -50,9 +50,9 @@ import java.io.IOException;
public class VariableTable
{
- private final long argCnt;
+ private final int argCnt;
- private final long slots;
+ private final int slots;
private final long[] lineCI;
@@ -95,8 +95,8 @@ public class VariableTable
*/
public void write(DataOutputStream os) throws IOException
{
- os.writeLong(argCnt);
- os.writeLong(slots);
+ os.writeInt(argCnt);
+ os.writeInt(slots);
for (int i = 0; i < slots; i++)
{
os.writeLong(lineCI[i]);
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java
new file mode 100644
index 00000000000..c5e00a019d9
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java
@@ -0,0 +1,92 @@
+/* ArrayValue.java -- JDWP wrapper class for an Object value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.VMIdManager;
+import gnu.classpath.jdwp.id.ObjectId;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an Array value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public class ArrayValue
+ extends Value
+{
+ // The Array wrapped by this class represented as a Object
+ Object _value;
+
+ /**
+ * Create a new ArrayValue from an Object
+ *
+ * @param value the Object to wrap
+ */
+ public ArrayValue(Object value)
+ {
+ super(JdwpConstants.Tag.ARRAY);
+ _value = value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return _value;
+ }
+
+ /**
+ * Write the wrapped object to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ ObjectId oid = VMIdManager.getDefault().getObjectId(_value);
+ oid.write(os);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java b/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java
new file mode 100644
index 00000000000..42bb806fadb
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java
@@ -0,0 +1,100 @@
+/* BooleanValue.java -- JDWP wrapper class for a boolean value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an boolean value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class BooleanValue
+ extends Value
+{
+ // The boolean wrapped by this class
+ boolean _value;
+
+ /**
+ * Create a new BooleanValue from an boolean
+ *
+ * @param value the boolean to wrap
+ */
+ public BooleanValue(boolean value)
+ {
+ super(JdwpConstants.Tag.BOOLEAN);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public boolean getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Boolean(_value);
+ }
+
+ /**
+ * Write the wrapped boolean to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeBoolean(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java
new file mode 100644
index 00000000000..204fe86b0e8
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java
@@ -0,0 +1,99 @@
+/* ByteValue.java -- JDWP wrapper class for a byte value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an byte value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class ByteValue
+ extends Value
+{
+ // The byte wrapped by this class
+ byte _value;
+
+ /**
+ * Create a new ByteValue from an byte
+ *
+ * @param value the byte to wrap
+ */
+ public ByteValue(byte value)
+ {
+ super(JdwpConstants.Tag.BYTE);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public byte getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Byte(_value);
+ }
+
+ /**
+ * Write the wrapped byte to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeByte(_value);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java b/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java
new file mode 100644
index 00000000000..f68fc88d156
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java
@@ -0,0 +1,100 @@
+/* CharValue.java -- JDWP wrapper class for a char value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an char value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class CharValue
+ extends Value
+{
+ // The char wrapped by this class
+ char _value;
+
+ /**
+ * Create a new CharValue from an char
+ *
+ * @param value the char to wrap
+ */
+ public CharValue(char value)
+ {
+ super(JdwpConstants.Tag.CHAR);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public char getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Character(_value);
+ }
+
+ /**
+ * Write the wrapped char to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeChar(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java b/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java
new file mode 100644
index 00000000000..45923c4dac4
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java
@@ -0,0 +1,100 @@
+/* DoubleValue.java -- JDWP wrapper class for a double value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an double value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class DoubleValue
+ extends Value
+{
+ // The double wrapped by this class
+ double _value;
+
+ /**
+ * Create a new DoubleValue from an double
+ *
+ * @param value the double to wrap
+ */
+ public DoubleValue(double value)
+ {
+ super(JdwpConstants.Tag.DOUBLE);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public double getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Double(_value);
+ }
+
+ /**
+ * Write the wrapped double to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeDouble(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java b/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java
new file mode 100644
index 00000000000..970f77c07b4
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java
@@ -0,0 +1,100 @@
+/* FloatValue.java -- JDWP wrapper class for a float value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+afloat with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an float value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class FloatValue
+ extends Value
+{
+ // The float wrapped by this class
+ float _value;
+
+ /**
+ * Create a new FloatValue from an float
+ *
+ * @param value the float to wrap
+ */
+ public FloatValue(float value)
+ {
+ super(JdwpConstants.Tag.FLOAT);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public float getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Float(_value);
+ }
+
+ /**
+ * Write the wrapped float to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeFloat(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java b/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java
new file mode 100644
index 00000000000..27868754f7f
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java
@@ -0,0 +1,100 @@
+/* IntValue.java -- JDWP wrapper class for an int value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an int value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class IntValue
+ extends Value
+{
+ // The int wrapped by this class
+ int _value;
+
+ /**
+ * Create a new IntValue from an int
+ *
+ * @param value the int to wrap
+ */
+ public IntValue(int value)
+ {
+ super(JdwpConstants.Tag.INT);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public int getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Integer(_value);
+ }
+
+ /**
+ * Write the wrapped int to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeInt(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java b/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java
new file mode 100644
index 00000000000..0ebe0e9f98a
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java
@@ -0,0 +1,100 @@
+/* LongValue.java -- JDWP wrapper class for a long value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an long value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class LongValue
+ extends Value
+{
+ // The long wrapped by this class
+ long _value;
+
+ /**
+ * Create a new LongValue from an long
+ *
+ * @param value the long to wrap
+ */
+ public LongValue(long value)
+ {
+ super(JdwpConstants.Tag.LONG);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public long getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Long(_value);
+ }
+
+ /**
+ * Write the wrapped long to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeLong(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java
new file mode 100644
index 00000000000..7ec9beb5f93
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java
@@ -0,0 +1,92 @@
+/* ObjectValue.java -- JDWP wrapper class for an Object value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.VMIdManager;
+import gnu.classpath.jdwp.id.ObjectId;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an Object value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class ObjectValue
+ extends Value
+{
+ // The Object wrapped by this class
+ Object _value;
+
+ /**
+ * Create a new ObjectValue from an Object
+ *
+ * @param value the Object to wrap
+ */
+ public ObjectValue(Object value)
+ {
+ super(JdwpConstants.Tag.OBJECT);
+ _value = value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return _value;
+ }
+
+ /**
+ * Write the wrapped object to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ ObjectId oid = VMIdManager.getDefault().getObjectId(_value);
+ oid.write(os);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java
new file mode 100644
index 00000000000..cbde2269e6c
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java
@@ -0,0 +1,100 @@
+/* ShortValue.java -- JDWP wrapper class for a short value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an short value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class ShortValue
+ extends Value
+{
+ // The short wrapped by this class
+ short _value;
+
+ /**
+ * Create a new ShortValue from a short
+ *
+ * @param value the short to wrap
+ */
+ public ShortValue(short value)
+ {
+ super(JdwpConstants.Tag.SHORT);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public short getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return new Short(_value);
+ }
+
+ /**
+ * Write the wrapped short to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ os.writeShort(_value);
+ }
+}
+
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java b/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java
new file mode 100644
index 00000000000..2371547efed
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java
@@ -0,0 +1,100 @@
+/* StringValue.java -- JDWP wrapper class for an String value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.util.JdwpString;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an String value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public final class StringValue
+ extends Value
+{
+ // The String wrapped by this class
+ String _value;
+
+ /**
+ * Create a new StringValue from an String
+ *
+ * @param value the String to wrap
+ */
+ public StringValue(String value)
+ {
+ super(JdwpConstants.Tag.OBJECT);
+ _value = value;
+ }
+
+ /**
+ * Get the value held in this Value
+ *
+ * @return the value represented by this Value object
+ */
+ public String getValue()
+ {
+ return _value;
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return _value;
+ }
+
+ /**
+ * Write the wrapped object to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ JdwpString.writeString(os, _value);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/Value.java b/libjava/classpath/gnu/classpath/jdwp/value/Value.java
new file mode 100644
index 00000000000..4ad8bec0703
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/Value.java
@@ -0,0 +1,155 @@
+/* Value.java -- base class of JDWP values
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.exception.InvalidClassException;
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+import gnu.classpath.jdwp.exception.InvalidTagException;
+import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Superclass for all JDWP Values.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public abstract class Value
+{
+ // A Tag representing the type of this value
+ private byte _tag;
+
+ /**
+ * Create a new value of type tag.
+ *
+ * @param tag the type of the value
+ */
+ protected Value(byte tag)
+ {
+ _tag = tag;
+ }
+
+ /**
+ * Get the tag for this Value
+ *
+ * @return the byte tag of this Value
+ */
+ public byte getTag()
+ {
+ return _tag;
+ }
+
+ /**
+ * Calls the dervied classes writeValue method to write its value to the
+ * DataOutputStream.
+ *
+ * @param os write the value here
+ * @throws IOException
+ */
+ public void writeUntagged(DataOutputStream os)
+ throws IOException
+ {
+ write(os);
+ }
+
+ /**
+ * Will write the given object as a tagged value to the DataOutputStream.
+ *
+ * @param os write the value here
+ * @param obj the Object to write
+ * @throws IOException
+ */
+ public void writeTagged(DataOutputStream os)
+ throws IOException
+ {
+ os.write (_tag);
+ write(os);
+ }
+
+ /**
+ * This method must write the value to the DataOutputStream in a manner
+ * appropriate for the type of the value.
+ *
+ * @param os DataOutputStream to write to
+ * @throws IOException
+ */
+ protected abstract void write(DataOutputStream os)
+ throws IOException;
+
+ /**
+ * Returns an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ protected abstract Object getObject();
+
+ /**
+ * Get an untagged object from the ByteBuffer
+ *
+ * @param bb the ByteBuffer to extract the value from
+ * @param type a Class representing the type
+ * @return an Object from the ByteBuffer of the type of the Class parameter
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ public static Object getUntaggedObject(ByteBuffer bb, Class type)
+ throws JdwpInternalErrorException, InvalidObjectException, InvalidClassException
+ {
+ Value val = ValueFactory.createFromUntagged(bb, type);
+ return val.getObject();
+ }
+
+ /**
+ * Get an untagged object from the ByteBuffer
+ *
+ * @param bb the ByteBuffer to extract the value from
+ * @param tag a byte tag representing the type
+ * @return an Object from the ByteBuffer of the type of the Class parameter
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ public static Object getTaggedObject(ByteBuffer bb)
+ throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException
+ {
+ Value val = ValueFactory.createFromTagged(bb);
+ return val.getObject();
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java b/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java
new file mode 100644
index 00000000000..8f1a8780eeb
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java
@@ -0,0 +1,247 @@
+/* ValueFactory.java -- factory to create JDWP Values
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.VMIdManager;
+import gnu.classpath.jdwp.exception.InvalidClassException;
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+import gnu.classpath.jdwp.exception.InvalidTagException;
+import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
+import gnu.classpath.jdwp.id.ObjectId;
+import gnu.classpath.jdwp.util.JdwpString;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A factory to create JDWP Values.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public class ValueFactory
+{
+ /**
+ * Creates a new Value of appropriate type for the value in the ByteBuffer
+ * by reading the tag byte from the front of the buffer.
+ *
+ * @param bb contains the Object
+ * @return A new Value of appropriate type
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ public static Value createFromTagged(ByteBuffer bb)
+ throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException
+ {
+ return create(bb, bb.get());
+ }
+
+ /**
+ * Creates a new Value of appropriate type for the value in the ByteBuffer
+ * by checking the type of the Class passed in.
+ *
+ * @param bb contains the Object
+ * @param type a Class representing the type of the value in the ByteBuffer
+ * @return A new Value of appropriate type
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ public static Value createFromUntagged(ByteBuffer bb, Class type)
+ throws JdwpInternalErrorException, InvalidObjectException, InvalidClassException
+ {
+ byte tag = getTagForClass(type);
+
+ try
+ {
+ return create(bb, tag);
+ }
+ catch (InvalidTagException ite)
+ {
+ throw new InvalidClassException(ite);
+ }
+ }
+
+ /**
+ * Creates a new Value of appropriate type for the value in the ByteBuffer.
+ *
+ * @param bb contains the Object
+ * @param tag a byte representing the type of the object
+ * @return A new Value of appropriate type
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ private static Value create(ByteBuffer bb, byte tag)
+ throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException
+ {
+ Value val = null;
+ switch(tag)
+ {
+ case JdwpConstants.Tag.BYTE:
+ val = new ByteValue(bb.get());
+ break;
+ case JdwpConstants.Tag.BOOLEAN:
+ val = new BooleanValue((bb.get() != 0));
+ break;
+ case JdwpConstants.Tag.CHAR:
+ val = new CharValue(bb.getChar());
+ break;
+ case JdwpConstants.Tag.SHORT:
+ val = new ShortValue(bb.getShort());
+ break;
+ case JdwpConstants.Tag.INT:
+ val = new IntValue(bb.getInt());
+ break;
+ case JdwpConstants.Tag.FLOAT:
+ val = new FloatValue(bb.getFloat());
+ break;
+ case JdwpConstants.Tag.LONG:
+ val = new LongValue(bb.getLong());
+ break;
+ case JdwpConstants.Tag.DOUBLE:
+ val = new DoubleValue(bb.getDouble());
+ break;
+ case JdwpConstants.Tag.VOID:
+ val = new VoidValue();
+ break;
+ case JdwpConstants.Tag.ARRAY:
+ case JdwpConstants.Tag.THREAD:
+ case JdwpConstants.Tag.OBJECT:
+ case JdwpConstants.Tag.THREAD_GROUP:
+ case JdwpConstants.Tag.CLASS_LOADER:
+ case JdwpConstants.Tag.CLASS_OBJECT:
+ ObjectId oid = VMIdManager.getDefault().readObjectId(bb);
+ val = new ObjectValue(oid.getObject());
+ break;
+ case JdwpConstants.Tag.STRING:
+ val = new StringValue(JdwpString.readString(bb));
+ break;
+ default:
+ throw new InvalidTagException(tag);
+ }
+
+ return val;
+ }
+
+ /**
+ * Creates a tag for the type of the class.
+ *
+ * @param klass the type to get a tag for
+ * @return a byte tag representing the class
+ * @throws JdwpInternalErrorException
+ * @throws InvalidObjectException
+ */
+ private static byte getTagForClass(Class klass)
+ throws JdwpInternalErrorException
+ {
+ byte tag;
+
+ if (klass.isPrimitive())
+ {
+ if (klass == byte.class)
+ tag = JdwpConstants.Tag.BYTE;
+ else if (klass == boolean.class)
+ tag = JdwpConstants.Tag.BOOLEAN;
+ else if (klass == char.class)
+ tag = JdwpConstants.Tag.CHAR;
+ else if (klass == short.class)
+ tag = JdwpConstants.Tag.SHORT;
+ else if (klass == int.class)
+ tag = JdwpConstants.Tag.INT;
+ else if (klass == float.class)
+ tag = JdwpConstants.Tag.FLOAT;
+ else if (klass == long.class)
+ tag = JdwpConstants.Tag.LONG;
+ else if (klass == double.class)
+ tag = JdwpConstants.Tag.DOUBLE;
+ else if (klass == void.class)
+ tag = JdwpConstants.Tag.VOID;
+ else
+ throw new JdwpInternalErrorException("Invalid primitive class");
+ }
+ else
+ {
+ tag = JdwpConstants.Tag.OBJECT;
+ }
+
+ return tag;
+ }
+
+ /**
+ * Create a value type for an Object of type determined by a Class. This is
+ * a special case where a value needs to be created, but the value to create
+ * it for is already in an object, not in a buffer.
+ *
+ * @param value the Object to convert to a Value
+ * @param type the Class type of the object
+ * @return a new Value representing this object
+ */
+ public static Value createFromObject(Object value, Class type)
+ {
+ Value val = null;
+
+ if (type.isPrimitive())
+ {
+ if (type == byte.class)
+ val = new ByteValue(((Byte) value).byteValue());
+ else if (type == boolean.class)
+ val = new BooleanValue(((Boolean) value).booleanValue());
+ else if (type == char.class)
+ val = new CharValue(((Character) value).charValue());
+ else if (type == short.class)
+ val = new ShortValue(((Short) value).shortValue());
+ else if (type == int.class)
+ val = new IntValue(((Integer) value).intValue());
+ else if (type == float.class)
+ val = new FloatValue(((Float) value).floatValue());
+ else if (type == long.class)
+ val = new LongValue(((Long) value).longValue());
+ else if (type == double.class)
+ val = new DoubleValue(((Double) value).doubleValue());
+ else if (type == void.class)
+ val = new VoidValue();
+ }
+ else
+ {
+ if (type.isAssignableFrom(String.class))
+ val = new StringValue ((String) value);
+ else
+ val = new ObjectValue(value);
+ }
+
+ return val;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java b/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java
new file mode 100644
index 00000000000..82cded92903
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java
@@ -0,0 +1,82 @@
+/* VoidValue.java -- JDWP wrapper class for a void value
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.jdwp.value;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Wrapper for an void value.
+ *
+ * @author Kyle Galloway <kgallowa@redhat.com>
+ */
+public class VoidValue
+ extends Value
+{
+ /**
+ * Create a new VoidValue.
+ */
+ public VoidValue ()
+ {
+ super(JdwpConstants.Tag.VOID);
+ }
+
+ /**
+ * Return an object representing this type
+ *
+ * @return an Object represntation of this value
+ */
+ @Override
+ protected Object getObject()
+ {
+ return null;
+ }
+
+ /**
+ * Write the wrapped void to the given DataOutputStream.
+ *
+ * @param os the output stream to write to
+ */
+ @Override
+ protected void write(DataOutputStream os)
+ throws IOException
+ {
+ }
+}
diff --git a/libjava/gnu/classpath/jdwp/VMFrame.java b/libjava/gnu/classpath/jdwp/VMFrame.java
index cd213025a72..de2640c85ff 100644
--- a/libjava/gnu/classpath/jdwp/VMFrame.java
+++ b/libjava/gnu/classpath/jdwp/VMFrame.java
@@ -1,5 +1,5 @@
/* VMFrame.java -- Reference implementation of VM hooks for JDWP Frame access.
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -40,6 +40,7 @@ exception statement from your version. */
package gnu.classpath.jdwp;
import gnu.classpath.jdwp.util.Location;
+import gnu.classpath.jdwp.value.Value;
/**
* Reference implementation of VM hooks for JDWP Frame access.
@@ -54,7 +55,10 @@ public class VMFrame
*/
public static final int SIZE = 8;
- // The object this frame resides in
+ // The thread this frame resides in
+ private Thread thread;
+
+ //The object of this frame
private Object obj;
// The current location of this frame
@@ -64,6 +68,22 @@ public class VMFrame
private long id;
/**
+ * Create a new VMFrame object.
+ *
+ * @param thr a Thread, the thread this frame is in
+ * @param frame_id a long, the jframeID of this frame
+ * @param frame_loc a Location, the location of this frame
+ */
+ public VMFrame(Thread thr, long frame_id, Location frame_loc,
+ Object frame_obj)
+ {
+ thread = thr;
+ id = frame_id;
+ loc = frame_loc;
+ obj = frame_obj;
+ }
+
+ /**
* Gets the current location of the frame.
*/
public Location getLocation()
@@ -76,14 +96,22 @@ public class VMFrame
*
* @param slot the slot containing the variable
*/
- public native Object getValue(int slot);
+ public native Value getValue(int slot, byte sig);
/**
* Assigns the given variable to the given value.
* @param slot The slot which contains the variable
* @param value The value to assign the variable to
*/
- public native void setValue(int slot, Object value);
+ public native void setValue(int slot, Value value);
+
+ /**
+ * Get the thread this frame is in.
+ */
+ public Thread getThread()
+ {
+ return thread;
+ }
/**
* Get the object which is represented by 'this' in the context of the frame,
diff --git a/libjava/gnu/classpath/jdwp/VMIdManager.java b/libjava/gnu/classpath/jdwp/VMIdManager.java
index 8d423e9b0d6..f787a8cdc7f 100644
--- a/libjava/gnu/classpath/jdwp/VMIdManager.java
+++ b/libjava/gnu/classpath/jdwp/VMIdManager.java
@@ -1,7 +1,7 @@
/* VMIdManager.java -- A reference/example implementation of a manager for
JDWP object/reference type IDs
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -337,6 +337,10 @@ public class VMIdManager
*/
public ObjectId getObjectId (Object theObject)
{
+ // Special case: null object.
+ if (theObject == null)
+ return new NullObjectId ();
+
ReferenceKey ref = new ReferenceKey (theObject, _refQueue);
ObjectId id = (ObjectId) _oidTable.get (ref);
if (id == null)
@@ -364,6 +368,10 @@ public class VMIdManager
public ObjectId get (long id)
throws InvalidObjectException
{
+ // Special case: null object id.
+ if (id == 0)
+ return new NullObjectId ();
+
ObjectId oid = (ObjectId) _idTable.get (new Long (id));
if (oid == null)
throw new InvalidObjectException (id);
diff --git a/libjava/gnu/classpath/jdwp/VMMethod.java b/libjava/gnu/classpath/jdwp/VMMethod.java
index d345bc1b515..6a2b04ecf97 100644
--- a/libjava/gnu/classpath/jdwp/VMMethod.java
+++ b/libjava/gnu/classpath/jdwp/VMMethod.java
@@ -1,5 +1,5 @@
/* VMMethod.java -- a method in a virtual machine
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -175,4 +175,15 @@ public class VMMethod
{
return VMVirtualMachine.getClassMethod(klass, bb.getLong());
}
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof VMMethod)
+ {
+ VMMethod m = (VMMethod) obj;
+ return (getId() == m.getId());
+ }
+
+ return false;
+ }
}
diff --git a/libjava/gnu/classpath/jdwp/VMVirtualMachine.java b/libjava/gnu/classpath/jdwp/VMVirtualMachine.java
index 5c4018fce13..91e9965d0e2 100644
--- a/libjava/gnu/classpath/jdwp/VMVirtualMachine.java
+++ b/libjava/gnu/classpath/jdwp/VMVirtualMachine.java
@@ -1,7 +1,7 @@
/* VMVirtualMachine.java -- A reference implementation of a JDWP virtual
machine
- Copyright (C) 2005, 2006 Free Software Foundation
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of GNU Classpath.
@@ -45,11 +45,13 @@ import gnu.classpath.jdwp.event.EventRequest;
import gnu.classpath.jdwp.exception.InvalidMethodException;
import gnu.classpath.jdwp.exception.JdwpException;
import gnu.classpath.jdwp.util.MethodResult;
+import gnu.classpath.jdwp.util.MonitorInfo;
+
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Hashtable;
-import java.util.Iterator;
/**
* A virtual machine according to JDWP.
@@ -58,9 +60,32 @@ import java.util.Iterator;
*/
public class VMVirtualMachine
{
+ // VM Capabilities
+ public static final boolean canWatchFieldModification = false;
+ public static final boolean canWatchFieldAccess = false;
+ public static final boolean canGetBytecodes = false;
+ public static final boolean canGetSyntheticAttribute = false;
+ public static final boolean canGetOwnedMonitorInfo = false;
+ public static final boolean canGetCurrentContendedMonitor = false;
+ public static final boolean canGetMonitorInfo = false;
+ public static final boolean canRedefineClasses = false;
+ public static final boolean canAddMethod = false;
+ public static final boolean canUnrestrictedlyRedefineClasses = false;
+ public static final boolean canPopFrames = false;
+ public static final boolean canUseInstanceFilters = false;
+ public static final boolean canGetSourceDebugExtension = false;
+ public static final boolean canRequestVMDeathEvent = false;
+ public static final boolean canSetDefaultStratum = false;
+
// Thread suspension table. Maps Thread to suspend count (Integer)
private static Hashtable _jdwp_suspend_counts;
+ // List of stepping threads: maps Thread -> stepping info
+ static Hashtable _stepping_threads;
+
+ // List of co-located JVMTI events
+ static ArrayList _event_list;
+
public static native void initialize ();
/**
@@ -176,15 +201,9 @@ public class VMVirtualMachine
throws JdwpException;
/**
- * Returns a count of the number of loaded classes in the VM
- */
- public static native int getAllLoadedClassesCount ()
- throws JdwpException;
-
- /**
- * Returns an iterator over all the loaded classes in the VM
+ * Returns a Collection of all classes loaded in the VM
*/
- public static native Iterator getAllLoadedClasses ()
+ public static native Collection getAllLoadedClasses ()
throws JdwpException;
/**
@@ -243,7 +262,7 @@ public class VMVirtualMachine
* @param bb buffer containing the frame's ID
* @return the desired frame
*/
- public static native VMFrame getFrame (Thread thread, ByteBuffer bb)
+ public static native VMFrame getFrame (Thread thread, long frameID)
throws JdwpException;
/**
@@ -332,4 +351,86 @@ public class VMVirtualMachine
*/
public static native void clearEvents (byte kind)
throws JdwpException;
+
+ /**
+ * Redefines the given types. VM must support canRedefineClasses
+ * capability (may also require canAddMethod and/or
+ * canUnrestrictedlyRedefineClasses capabilities)
+ *
+ * @param types the classes to redefine
+ * @param bytecodes the new bytecode definitions for the classes
+ */
+ public static native void redefineClasses(Class[] types, byte[][] bytecodes)
+ throws JdwpException;
+
+ /**
+ * Sets the default stratum. VM must support the
+ * canSetDefaultStratum capability.
+ *
+ * @param stratum the new default stratum or empty string to
+ * use the reference default
+ */
+ public static native void setDefaultStratum(String stratum)
+ throws JdwpException;
+
+ /**
+ * Returns the source debug extension. VM must support the
+ * canGetSourceDebugExtension capability.
+ *
+ * @param klass the class for which to return information
+ * @returns the source debug extension
+ */
+ public static native String getSourceDebugExtension(Class klass)
+ throws JdwpException;
+
+ /**
+ * Returns the bytecode for the given method. VM must support the
+ * canGetBytecodes capability.
+ *
+ * @param method the method for which to get bytecodes
+ * @returns the bytecodes
+ */
+ public static native byte[] getBytecodes(VMMethod method)
+ throws JdwpException;
+
+ /**
+ * Returns monitor information about an object. VM must support
+ * the canGetMonitorInformation capability.
+ *
+ * @param obj the object
+ * @returns monitor information (owner, entry count, waiters)
+ */
+ public static native MonitorInfo getMonitorInfo(Object obj)
+ throws JdwpException;
+
+ /**
+ * Returns a list of owned monitors. VM must support the
+ * canGetOwnedMonitorInfo capability.
+ *
+ * @param thread a thread
+ * @returns the list of monitors owned by this thread
+ */
+ public static native Object[] getOwnedMonitors(Thread thread)
+ throws JdwpException;
+
+ /**
+ * Returns the current contended monitor for a thread. VM must
+ * support canGetCurrentContendedMonitor capability.
+ *
+ * @param thread the thread
+ * @returns the contended monitor
+ */
+ public static native Object getCurrentContendedMonitor(Thread thread)
+ throws JdwpException;
+
+ /**
+ * Pop all frames up to and including the given frame. VM must
+ * support canPopFrames capability. It is the responsibility
+ * of the VM to check if the thread is suspended. If it is not,
+ * the VM should throw ThreadNotSuspendedException.
+ *
+ * @param thread the thread
+ * @param frame the frame ID
+ */
+ public static native void popFrames(Thread thread, long frameId);
}
diff --git a/libjava/gnu/classpath/jdwp/natVMFrame.cc b/libjava/gnu/classpath/jdwp/natVMFrame.cc
index de3b844f4a4..6f2d5233233 100644
--- a/libjava/gnu/classpath/jdwp/natVMFrame.cc
+++ b/libjava/gnu/classpath/jdwp/natVMFrame.cc
@@ -1,6 +1,6 @@
// natFrame.cc -- native support for VMFrame.java
-/* Copyright (C) 2006 Free Software Foundation
+/* Copyright (C) 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -8,19 +8,331 @@ This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
+#include <config.h>
#include <gcj/cni.h>
+#include <jvm.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
+
+#include <java-interp.h>
#include <gnu/classpath/jdwp/VMFrame.h>
+#include <gnu/classpath/jdwp/VMVirtualMachine.h>
+#include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
+#include <gnu/classpath/jdwp/exception/InvalidSlotException.h>
+#include <gnu/classpath/jdwp/exception/InvalidThreadException.h>
+#include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
+#include <gnu/classpath/jdwp/exception/TypeMismatchException.h>
+#include <gnu/classpath/jdwp/util/NullObject.h>
+#include <gnu/classpath/jdwp/value/ArrayValue.h>
+#include <gnu/classpath/jdwp/value/ByteValue.h>
+#include <gnu/classpath/jdwp/value/BooleanValue.h>
+#include <gnu/classpath/jdwp/value/CharValue.h>
+#include <gnu/classpath/jdwp/value/DoubleValue.h>
+#include <gnu/classpath/jdwp/value/FloatValue.h>
+#include <gnu/classpath/jdwp/value/IntValue.h>
+#include <gnu/classpath/jdwp/value/LongValue.h>
+#include <gnu/classpath/jdwp/value/ObjectValue.h>
+#include <gnu/classpath/jdwp/value/ShortValue.h>
+#include <gnu/classpath/jdwp/value/Value.h>
+#include <gnu/classpath/jdwp/value/VoidValue.h>
using namespace java::lang;
+using namespace gnu::classpath::jdwp;
+using namespace gnu::classpath::jdwp::exception;
+
-Object*
-gnu::classpath::jdwp::VMFrame::getValue (jint slot)
+// All the jvmti GetLocalXX and SetLocalXX functions return the same potential
+// errors, so this function handles them all and throws the appropriate JDWP
+// exception.
+static void
+checkJVMTIError (jvmtiEnv *env, jthread thread, jvmtiError jerr, jint slot,
+ jbyte sig)
{
- return 0;
+ if (jerr != JVMTI_ERROR_NONE)
+ {
+ char *error;
+ env->GetErrorName (jerr, &error);
+ String *msg = reinterpret_cast<String *> (JvNewStringUTF (error));
+ env->Deallocate ((unsigned char *) error);
+
+ if (jerr == JVMTI_ERROR_INVALID_THREAD)
+ throw new InvalidThreadException ((jlong) thread);
+ else if (jerr == JVMTI_ERROR_NO_MORE_FRAMES)
+ throw new InvalidFrameException (msg);
+ else if (jerr == JVMTI_ERROR_INVALID_SLOT)
+ throw new InvalidSlotException (slot);
+ else if (jerr == JVMTI_ERROR_TYPE_MISMATCH)
+ throw new TypeMismatchException (sig);
+ else
+ throw new JdwpInternalErrorException (msg);
+ }
}
-void
-gnu::classpath::jdwp::VMFrame::setValue (jint slot, Object* value)
+
+static jobject
+getObjectJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig)
+{
+ jobject value;
+ jvmtiError jerr = env->GetLocalObject (thread, depth, slot, &value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+
+ return value;
+}
+
+static void
+setObjectJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth,
+ jbyte sig, jobject value)
+{
+ if (value->getClass ()->isAssignableFrom (&util::NullObject::class$))
+ value = NULL;
+
+ jvmtiError jerr = env->SetLocalObject (thread, depth, slot, value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+}
+
+static jint
+getIntJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig)
+{
+ jint value;
+ jvmtiError jerr = env->GetLocalInt (thread, depth, slot, &value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+ return value;
+}
+
+static void
+setIntJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig,
+ jint value)
+{
+ jvmtiError jerr = env->SetLocalInt (thread, depth, slot, value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+}
+
+static jlong
+getLongJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig)
+{
+ jlong value;
+ jvmtiError jerr = env->GetLocalLong (thread, depth, slot, &value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+
+ return value;
+}
+
+static void
+setLongJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig,
+ jlong value)
+{
+ jvmtiError jerr = env->SetLocalLong (thread, depth, slot, value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+}
+
+static jfloat
+getFloatJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig)
+{
+ jfloat value;
+ jvmtiError jerr = env->GetLocalFloat (thread, depth, slot, &value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+
+ return value;
+}
+
+static void
+setFloatJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth, jbyte sig,
+ jfloat value)
{
+ jvmtiError jerr = env->SetLocalFloat (thread, depth, slot, value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+}
+
+static jdouble
+getDoubleJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth,
+ jbyte sig)
+{
+ jdouble value;
+ jvmtiError jerr = env->GetLocalDouble (thread, depth, slot, &value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+
+ return value;
+}
+
+static void
+setDoubleJVMTI (jvmtiEnv *env, jthread thread, jint slot, jint depth,
+ jbyte sig, jdouble value)
+{
+ jvmtiError jerr = env->SetLocalDouble (thread, depth, slot, value);
+
+ checkJVMTIError (env, thread, jerr, slot, sig);
+}
+
+// This is necessary since JVMTI requires a stack depth as a parameter in all
+// its local variable functions. Since JDWP needs frameids, we have to run
+// through the call stack to translate these ids into the parameters JVMTI
+// wants.
+static jint
+getFrameDepth (_Jv_Frame *frame)
+{
+ jint depth = 0;
+ _Jv_Frame *top_frame = (_Jv_Frame *) frame->thread->frame;
+ jint num_frames = VMVirtualMachine::getFrameCount (frame->thread);
+
+ while (frame != top_frame)
+ {
+ top_frame = top_frame->next;
+ depth++;
+
+ if (depth >= num_frames || top_frame == NULL)
+ throw new InvalidFrameException ((jlong) frame);
+ }
+
+ return depth;
+}
+
+using namespace gnu::classpath::jdwp::value;
+
+Value *
+gnu::classpath::jdwp::VMFrame::getValue (jint slot, jbyte sig)
+{
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (id);
+ jint depth = getFrameDepth (frame);
+ jthread thread = reinterpret_cast<jthread> (frame->thread);
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+
+ Value *value = NULL;
+
+ switch (sig)
+ {
+ case 'B':
+ value = new ByteValue ((jbyte) getIntJVMTI (env, thread, slot, depth,
+ sig));
+ break;
+ case 'Z':
+ value = new BooleanValue ((jboolean) getIntJVMTI (env, thread, slot,
+ depth, sig));
+ break;
+ case 'C':
+ value = new CharValue ((jchar) getIntJVMTI (env, thread, slot, depth,
+ sig));
+ break;
+ case 'S':
+ value = new ShortValue ((jshort) getIntJVMTI (env, thread, slot, depth,
+ sig));
+ break;
+ case 'I':
+ value = new IntValue (getIntJVMTI (env, thread, slot, depth, sig));
+ break;
+ case 'J':
+ value = new LongValue (getLongJVMTI (env, thread, slot, depth, sig));
+ break;
+ case 'F':
+ value = new FloatValue (getFloatJVMTI (env, thread, slot, depth, sig));
+ break;
+ case 'D':
+ value = new DoubleValue (getDoubleJVMTI (env, thread, slot, depth, sig));
+ break;
+ case 'V':
+ value = new VoidValue ();
+ break;
+ case '[':
+ {
+ Object *obj = getObjectJVMTI (env, thread, slot, depth, sig);
+ if (obj == NULL)
+ obj = new util::NullObject ();
+ value = new ArrayValue (obj);
+ break;
+ }
+ default:
+ Object *obj = getObjectJVMTI (env, thread, slot, depth, sig);
+ if (obj == NULL)
+ obj = new util::NullObject ();
+ value = new ObjectValue (obj);
+ break;
+ }
+
+ return value;
+}
+
+void
+gnu::classpath::jdwp::VMFrame::setValue (jint slot, Value* value)
+{
+ jbyte sig = value->getTag ();
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (id);
+ jint depth = getFrameDepth (frame);
+ jthread thread = reinterpret_cast<jthread> (frame->thread);
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+
+ switch (sig)
+ {
+ case 'B':
+ {
+ ByteValue *val = reinterpret_cast<ByteValue *> (value);
+ setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ());
+ break;
+ }
+ case 'Z':
+ {
+ BooleanValue *val = reinterpret_cast<BooleanValue *> (value);
+ setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ());
+ break;
+ }
+ case 'C':
+ {
+ CharValue *val = reinterpret_cast<CharValue *> (value);
+ setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ());
+ break;
+ }
+ case 'S':
+ {
+ ShortValue *val = reinterpret_cast<ShortValue *> (value);
+ setIntJVMTI (env, thread, slot, depth, sig, (jint) val->getValue ());
+ break;
+ }
+ case 'I':
+ {
+ IntValue *val = reinterpret_cast<IntValue *> (value);
+ setIntJVMTI (env, thread, slot, depth, sig, val->getValue ());
+ break;
+ }
+ case 'J':
+ {
+ LongValue *val = reinterpret_cast<LongValue *> (value);
+ setLongJVMTI (env, thread, slot, depth, sig, val->getValue ());
+ break;
+ }
+ case 'F':
+ {
+ FloatValue *val = reinterpret_cast<FloatValue *> (value);
+ setFloatJVMTI (env, thread, slot, depth, sig, val->getValue ());
+ break;
+ }
+ case 'D':
+ {
+ DoubleValue *val = reinterpret_cast<DoubleValue *> (value);
+ setDoubleJVMTI (env, thread, slot, depth, sig, val->getValue ());
+ break;
+ }
+ case 'V':
+ break;
+ case '[':
+ {
+ ArrayValue *val = reinterpret_cast<ArrayValue *> (value);
+ setObjectJVMTI (env, thread, slot, depth, sig, val->getObject ());
+ break;
+ }
+ default:
+ {
+ ObjectValue *val = reinterpret_cast<ObjectValue *> (value);
+ setObjectJVMTI (env, thread, slot, depth, sig, val->getObject());
+ break;
+ }
+ }
}
diff --git a/libjava/gnu/classpath/jdwp/natVMMethod.cc b/libjava/gnu/classpath/jdwp/natVMMethod.cc
index 7dea4747731..1cea54dae9d 100644
--- a/libjava/gnu/classpath/jdwp/natVMMethod.cc
+++ b/libjava/gnu/classpath/jdwp/natVMMethod.cc
@@ -1,6 +1,6 @@
// natVMMethod.cc -- native support for VMMethod
-/* Copyright (C) 2006 Free Software Foundation
+/* Copyright (C) 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -11,39 +11,74 @@ details. */
#include <config.h>
#include <gcj/cni.h>
#include <java-interp.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
+#include <java/lang/reflect/Modifier.h>
#include <gnu/classpath/jdwp/VMMethod.h>
+#include <gnu/classpath/jdwp/exception/AbsentInformationException.h>
+#include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
#include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
#include <gnu/classpath/jdwp/util/LineTable.h>
#include <gnu/classpath/jdwp/util/VariableTable.h>
-java::lang::String*
+using namespace java::lang;
+
+#define CHECK_INTERP_CLASS() \
+do \
+ { \
+ if (!_Jv_IsInterpretedClass (getDeclaringClass ())) \
+ { \
+ ::java::lang::String *msg = JvNewStringLatin1 ("native class"); \
+ throw new exception::JdwpInternalErrorException (msg); \
+ } \
+ } \
+while (0)
+
+jstring
gnu::classpath::jdwp::VMMethod::getName ()
{
- return NULL;
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+ jmethodID method = reinterpret_cast<jmethodID> (_methodId);
+ char *name;
+ env->GetMethodName (method, &name, NULL, NULL);
+ jstring string = JvNewStringUTF (name);
+ env->Deallocate (reinterpret_cast<unsigned char *> (name));
+ return string;
}
-java::lang::String*
+jstring
gnu::classpath::jdwp::VMMethod::getSignature ()
{
- return NULL;
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+ jmethodID method = reinterpret_cast<jmethodID> (_methodId);
+ char *signature;
+ env->GetMethodName (method, NULL, &signature, NULL);
+ jstring string = JvNewStringUTF (signature);
+ env->Deallocate (reinterpret_cast<unsigned char *> (signature));
+ return string;
}
jint
gnu::classpath::jdwp::VMMethod::getModifiers ()
{
- return 0;
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+ jmethodID method = reinterpret_cast<jmethodID> (_methodId);
+ jint flags;
+ env->GetMethodModifiers (method, &flags);
+
+ // If this class is compiled, as far as JDWP is concerned, its methods are
+ // native. This will set the native flag for these methods.
+ if (!_Jv_IsInterpretedClass (getDeclaringClass ()))
+ flags |= ::java::lang::reflect::Modifier::NATIVE;
+
+ return flags;
}
gnu::classpath::jdwp::util::LineTable *
gnu::classpath::jdwp::VMMethod::getLineTable ()
{
- if (!_Jv_IsInterpretedClass (getDeclaringClass ()))
- {
- // this should not happen
- ::java::lang::String *msg = JvNewStringLatin1 ("native class");
- throw new exception::JdwpInternalErrorException (msg);
- }
+ CHECK_INTERP_CLASS ();
jmethodID desired_method = reinterpret_cast<jmethodID> (_methodId);
@@ -79,5 +114,78 @@ gnu::classpath::jdwp::VMMethod::getLineTable ()
gnu::classpath::jdwp::util::VariableTable*
gnu::classpath::jdwp::VMMethod::getVariableTable ()
{
- return NULL;
+ using namespace gnu::classpath::jdwp::util;
+
+ jvmtiEnv *env = _Jv_GetJDWP_JVMTIEnv ();
+
+ CHECK_INTERP_CLASS ();
+
+ jmethodID meth = reinterpret_cast<jmethodID> (_methodId);
+ jvmtiLocalVariableEntry *var_table;
+ jint num_slots, args_len;
+
+ jvmtiError jerr = env->GetLocalVariableTable (meth, &num_slots, &var_table);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ goto error;
+
+ jerr = env->GetArgumentsSize (meth, &args_len);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ {
+ error:
+ using namespace gnu::classpath::jdwp::exception;
+ char *error;
+ env->GetErrorName (jerr, &error);
+ String *msg = JvNewStringUTF (error);
+ env->Deallocate (reinterpret_cast<unsigned char *> (error));
+
+ if (jerr == JVMTI_ERROR_NATIVE_METHOD)
+ throw new AbsentInformationException (msg);
+ else if (jerr == JVMTI_ERROR_INVALID_METHODID)
+ throw new InvalidMethodException (_methodId);
+ else
+ throw new JdwpInternalErrorException (msg);
+ }
+
+ jlongArray start_pcs = JvNewLongArray (num_slots);
+ jlong *start_pcs_ptr = elements (start_pcs);
+ jintArray lengths = JvNewIntArray (num_slots);
+ jint *lengths_ptr = elements (lengths);
+ jintArray slots = JvNewIntArray (num_slots);
+ jint *slots_ptr = elements (slots);
+ JArray<String *> *names = reinterpret_cast<JArray<String *> *>
+ (JvNewObjectArray (num_slots,
+ &String::class$, NULL));
+ jstring *names_ptr = elements (names);
+ JArray<String *> *signatures = reinterpret_cast<JArray<String *> *>
+ (JvNewObjectArray (num_slots,
+ &String::class$, NULL));
+ jstring *signatures_ptr = elements (signatures);
+
+ // Get the information out of the JVMTI strucutre and Deallocate the strings.
+ for (int i = 0; i < num_slots; i++)
+ {
+ start_pcs_ptr[i] = var_table[i].start_location;
+ lengths_ptr[i] = var_table[i].length;
+ slots_ptr[i] = var_table[i].slot;
+ names_ptr[i] = JvNewStringUTF (var_table[i].name);
+ env->Deallocate (reinterpret_cast<unsigned char *>
+ (var_table[i].name));
+ signatures_ptr[i] = JvNewStringUTF (var_table[i].signature);
+ env->Deallocate (reinterpret_cast<unsigned char *>
+ (var_table[i].signature));
+ env->Deallocate (reinterpret_cast<unsigned char *>
+ (var_table[i].generic_signature));
+ }
+
+ // Now Deallocate the table since it's strings have already been freed.
+ env->Deallocate (reinterpret_cast<unsigned char *> (var_table));
+
+ // Create the new JDWP VariableTable to return with the now filled arrays.
+ VariableTable* jdwp_vtable = new VariableTable (args_len, num_slots,
+ start_pcs, names, signatures,
+ lengths, slots);
+
+ return jdwp_vtable;
}
diff --git a/libjava/gnu/classpath/jdwp/natVMVirtualMachine.cc b/libjava/gnu/classpath/jdwp/natVMVirtualMachine.cc
index 351bb23ccb2..db33781378e 100644
--- a/libjava/gnu/classpath/jdwp/natVMVirtualMachine.cc
+++ b/libjava/gnu/classpath/jdwp/natVMVirtualMachine.cc
@@ -10,6 +10,8 @@ details. */
#include <config.h>
#include <gcj/cni.h>
+#include <java-assert.h>
+#include <java-interp.h>
#include <jvm.h>
#include <jvmti.h>
@@ -19,40 +21,111 @@ details. */
#include <java/lang/String.h>
#include <java/lang/StringBuilder.h>
#include <java/lang/Thread.h>
+#include <java/lang/Throwable.h>
#include <java/nio/ByteBuffer.h>
+#include <java/nio/ByteBufferImpl.h>
#include <java/util/ArrayList.h>
+#include <java/util/Collection.h>
#include <java/util/Hashtable.h>
#include <java/util/Iterator.h>
#include <gnu/classpath/jdwp/Jdwp.h>
+#include <gnu/classpath/jdwp/JdwpConstants$StepDepth.h>
+#include <gnu/classpath/jdwp/JdwpConstants$StepSize.h>
+#include <gnu/classpath/jdwp/JdwpConstants$ThreadStatus.h>
#include <gnu/classpath/jdwp/VMFrame.h>
#include <gnu/classpath/jdwp/VMMethod.h>
#include <gnu/classpath/jdwp/VMVirtualMachine.h>
+#include <gnu/classpath/jdwp/event/BreakpointEvent.h>
+#include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
+#include <gnu/classpath/jdwp/event/ExceptionEvent.h>
+#include <gnu/classpath/jdwp/event/EventManager.h>
#include <gnu/classpath/jdwp/event/EventRequest.h>
+#include <gnu/classpath/jdwp/event/SingleStepEvent.h>
+#include <gnu/classpath/jdwp/event/ThreadEndEvent.h>
+#include <gnu/classpath/jdwp/event/ThreadStartEvent.h>
+#include <gnu/classpath/jdwp/event/VmDeathEvent.h>
#include <gnu/classpath/jdwp/event/VmInitEvent.h>
+#include <gnu/classpath/jdwp/event/filters/IEventFilter.h>
+#include <gnu/classpath/jdwp/event/filters/LocationOnlyFilter.h>
+#include <gnu/classpath/jdwp/event/filters/StepFilter.h>
+#include <gnu/classpath/jdwp/exception/AbsentInformationException.h>
+#include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
+#include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
+#include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
#include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
+#include <gnu/classpath/jdwp/id/ThreadId.h>
+#include <gnu/classpath/jdwp/util/Location.h>
#include <gnu/classpath/jdwp/util/MethodResult.h>
+#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
using namespace java::lang;
using namespace gnu::classpath::jdwp::event;
using namespace gnu::classpath::jdwp::util;
+// Stepping information
+struct step_info
+{
+ jint size; // See gnu.classpath.jdwp.JdwpConstants.StepSize
+ jint depth; // See gnu.classpath.jdwp.JdwpConstants.StepDepth
+ int stack_depth; // stack depth at start of stepping
+ jmethodID method; // method in which we are stepping
+};
+
// Forward declarations
-static void jdwpVMInitCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread);
+static jvmtiError get_linetable (jvmtiEnv *, jmethodID, jint *,
+ jvmtiLineNumberEntry **);
+static Location *get_request_location (EventRequest *);
+static gnu::classpath::jdwp::event::filters::StepFilter *
+get_request_step_filter (EventRequest *);
+static void handle_single_step (jvmtiEnv *, struct step_info *, jthread,
+ jmethodID, jlocation);
+static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
+ jmethodID, jlocation);
+static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
+static void JNICALL jdwpExceptionCB (jvmtiEnv *, JNIEnv *jni_env, jthread,
+ jmethodID, jlocation, jobject,
+ jmethodID, jlocation);
+static void JNICALL jdwpSingleStepCB (jvmtiEnv *, JNIEnv *, jthread,
+ jmethodID, jlocation);
+static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
+static void JNICALL jdwpThreadStartCB (jvmtiEnv *, JNIEnv *, jthread);
+static void JNICALL jdwpVMDeathCB (jvmtiEnv *, JNIEnv *);
+static void JNICALL jdwpVMInitCB (jvmtiEnv *, JNIEnv *, jthread);
+static void throw_jvmti_error (jvmtiError);
#define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
+#define DISABLE_EVENT(Event,Thread) \
+ _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE, \
+ JVMTI_EVENT_ ## Event, Thread)
#define ENABLE_EVENT(Event,Thread) \
_jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE, \
JVMTI_EVENT_ ## Event, Thread)
// JVMTI environment
static jvmtiEnv *_jdwp_jvmtiEnv;
+jvmtiEnv *
+_Jv_GetJDWP_JVMTIEnv (void)
+{
+ return _jdwp_jvmtiEnv;
+}
+
void
gnu::classpath::jdwp::VMVirtualMachine::initialize ()
{
_jdwp_suspend_counts = new ::java::util::Hashtable ();
+ _stepping_threads = new ::java::util::Hashtable ();
+ _event_list = new ::java::util::ArrayList ();
+
JavaVM *vm = _Jv_GetJavaVM ();
- vm->GetEnv (reinterpret_cast<void **> (&_jdwp_jvmtiEnv), JVMTI_VERSION_1_0);
+ union
+ {
+ void *ptr;
+ jvmtiEnv *env;
+ } foo;
+ vm->GetEnv (&(foo.ptr), JVMTI_VERSION_1_0);
+ _jdwp_jvmtiEnv = foo.env;
// Wait for VM_INIT to do more initialization
jvmtiEventCallbacks callbacks;
@@ -62,7 +135,7 @@ gnu::classpath::jdwp::VMVirtualMachine::initialize ()
}
void
-gnu::classpath::jdwp::VMVirtualMachine ::suspendThread (Thread *thread)
+gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
{
jint value;
Integer *count;
@@ -170,9 +243,57 @@ gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
switch (request->getEventKind ())
{
case EventRequest::EVENT_SINGLE_STEP:
+ {
+ Thread *thread;
+ filters::StepFilter *filter = get_request_step_filter (request);
+ if (filter == NULL)
+ {
+ // No filter specified: report every step in every
+ // thread.
+ thread = NULL;
+ }
+ else
+ {
+ // Add stepping information to list of stepping threads
+ thread = filter->getThread ()->getThread ();
+ _Jv_InterpFrame *frame
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+ struct step_info *sinfo
+ = (struct step_info *) JvAllocBytes (sizeof (struct step_info));
+ sinfo->size = filter->getSize ();
+ sinfo->depth = filter->getDepth ();
+ sinfo->stack_depth = frame->depth ();
+ sinfo->method = frame->self->get_method ();
+ _stepping_threads->put (thread, (jobject) sinfo);
+ }
+
+ ENABLE_EVENT (SINGLE_STEP, thread);
+ }
break;
case EventRequest::EVENT_BREAKPOINT:
+ {
+ using namespace ::gnu::gcj::jvmti;
+ Location *loc = get_request_location (request);
+ if (loc == NULL)
+ {
+ using namespace gnu::classpath::jdwp::exception;
+ throw new InvalidLocationException ();
+ }
+
+ jlong method = loc->getMethod ()->getId ();
+ jlocation index = loc->getIndex ();
+ Breakpoint *bp = BreakpointManager::getBreakpoint (method, index);
+ if (bp == NULL)
+ {
+ // Breakpoint not in interpreter yet
+ bp = BreakpointManager::newBreakpoint (method, index);
+ }
+ else
+ {
+ // Ignore the duplicate
+ }
+ }
break;
case EventRequest::EVENT_FRAME_POP:
@@ -213,7 +334,7 @@ gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
case EventRequest::EVENT_VM_INIT:
break;
-
+
case EventRequest::EVENT_VM_DEATH:
break;
}
@@ -225,9 +346,62 @@ gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
switch (request->getEventKind ())
{
case EventRequest::EVENT_SINGLE_STEP:
+ {
+ Thread *thread;
+ filters::StepFilter *filter = get_request_step_filter (request);
+ if (filter == NULL)
+ thread = NULL;
+ else
+ {
+ thread = filter->getThread ()->getThread ();
+ _stepping_threads->remove (thread);
+ }
+
+ DISABLE_EVENT (SINGLE_STEP, thread);
+ }
break;
case EventRequest::EVENT_BREAKPOINT:
+ {
+ using namespace gnu::gcj::jvmti;
+ ::java::util::Collection *breakpoints;
+ EventManager *em = EventManager::getDefault ();
+ breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
+
+ // Check for duplicates
+ int matches = 0;
+ Location *the_location = get_request_location (request);
+
+ // This should not be possible: we REQUIRE a Location
+ // to install a breakpoint
+ JvAssert (the_location != NULL);
+
+ ::java::util::Iterator *iter = breakpoints->iterator ();
+ while (iter->hasNext ())
+ {
+ EventRequest *er
+ = reinterpret_cast<EventRequest *> (iter->next ());
+ Location *loc = get_request_location (er);
+ JvAssert (loc != NULL);
+ if (loc->equals (the_location) && ++matches == 2)
+ {
+ // Short-circuit: already more than one breakpoint
+ return;
+ }
+ }
+
+ if (matches == 0)
+ {
+ using namespace gnu::classpath::jdwp::exception;
+ jstring msg
+ = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
+ throw new JdwpInternalErrorException (msg);
+ }
+
+ jlong methodId = the_location->getMethod ()->getId ();
+ BreakpointManager::deleteBreakpoint (methodId,
+ the_location->getIndex ());
+ }
break;
case EventRequest::EVENT_FRAME_POP:
@@ -244,7 +418,7 @@ gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
case EventRequest::EVENT_THREAD_END:
break;
-
+
case EventRequest::EVENT_CLASS_PREPARE:
break;
@@ -268,103 +442,718 @@ gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
case EventRequest::EVENT_VM_INIT:
break;
-
+
case EventRequest::EVENT_VM_DEATH:
break;
}
}
void
-gnu::classpath::jdwp::VMVirtualMachine::clearEvents (jbyte kind)
+gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
{
}
-jint
-gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClassesCount (void)
-{
- return 0;
-}
-
-java::util::Iterator *
+java::util::Collection *
gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
{
- return NULL;
+ using namespace ::java::util;
+ return (Collection *) new ArrayList ();
}
jint
-gnu::classpath::jdwp::VMVirtualMachine::getClassStatus (jclass klass)
+gnu::classpath::jdwp::VMVirtualMachine::
+getClassStatus (jclass klass)
{
- return 0;
+ jint flags = 0;
+ jvmtiError err = _jdwp_jvmtiEnv->GetClassStatus (klass, &flags);
+ if (err != JVMTI_ERROR_NONE)
+ throw_jvmti_error (err);
+
+ using namespace gnu::classpath::jdwp::event;
+ jint status = 0;
+ if (flags & JVMTI_CLASS_STATUS_VERIFIED)
+ status |= ClassPrepareEvent::STATUS_VERIFIED;
+ if (flags & JVMTI_CLASS_STATUS_PREPARED)
+ status |= ClassPrepareEvent::STATUS_PREPARED;
+ if (flags & JVMTI_CLASS_STATUS_ERROR)
+ status |= ClassPrepareEvent::STATUS_ERROR;
+ if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
+ status |= ClassPrepareEvent::STATUS_INITIALIZED;
+
+ return status;
}
JArray<gnu::classpath::jdwp::VMMethod *> *
-gnu::classpath::jdwp::VMVirtualMachine::getAllClassMethods (jclass klass)
+gnu::classpath::jdwp::VMVirtualMachine::
+getAllClassMethods (jclass klass)
{
- return NULL;
+ jint count;
+ jmethodID *methods;
+ jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
+ if (err != JVMTI_ERROR_NONE)
+ throw_jvmti_error (err);
+
+ JArray<VMMethod *> *result
+ = (JArray<VMMethod *> *) JvNewObjectArray (count,
+ &VMMethod::class$, NULL);
+ VMMethod **rmeth = elements (result);
+ for (int i = 0; i < count; ++i)
+ {
+ jlong id = reinterpret_cast<jlong> (methods[i]);
+ rmeth[i] = getClassMethod (klass, id);
+ }
+
+ _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
+ return result;
}
gnu::classpath::jdwp::VMMethod *
-gnu::classpath::jdwp::VMVirtualMachine::getClassMethod (jclass klass, jlong id)
+gnu::classpath::jdwp::VMVirtualMachine::
+getClassMethod (jclass klass, jlong id)
{
- return NULL;
+ jint count;
+ jmethodID *methods;
+ jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
+ if (err != JVMTI_ERROR_NONE)
+ throw_jvmti_error (err);
+
+ jmethodID meth_id = reinterpret_cast<jmethodID> (id);
+
+ using namespace gnu::classpath::jdwp;
+
+ // Check if this method is defined for the given class and if so return a
+ // VMMethod representing it.
+ for (int i = 0; i < count; i++)
+ {
+ if (methods[i] == meth_id)
+ return new VMMethod (klass, reinterpret_cast<jlong> (meth_id));
+ }
+
+ throw new exception::InvalidMethodException (id);
}
java::util::ArrayList *
-gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread,
- jint start,
- jint length)
+gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread, jint start,
+ jint length)
{
- return NULL;
+ jint frame_count = getFrameCount (thread);
+ ::java::util::ArrayList *frame_list;
+
+ // Calculate the max number of frames to be returned.
+ jint num_frames = frame_count - start;
+
+ // Check if num_frames is valid.
+ if (num_frames < 0)
+ num_frames = 0;
+
+ // Check if there are more than length frames left after start.
+ // If length ios -1 return all remaining frames.
+ if (length != -1 && num_frames > length)
+ num_frames = length;
+
+ frame_list = new ::java::util::ArrayList (num_frames);
+
+ _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+
+ // Take start frames off the top of the stack
+ while (vm_frame != NULL && start > 0)
+ {
+ start--;
+ vm_frame = vm_frame->next;
+ }
+
+ // Use as a counter for the number of frames returned.
+ num_frames = 0;
+
+ while (vm_frame != NULL && (num_frames < length || length == -1))
+ {
+ jlong frameId = reinterpret_cast<jlong> (vm_frame);
+
+ VMFrame *frame = getFrame (thread, frameId);
+ frame_list->add (frame);
+ vm_frame = vm_frame->next;
+ num_frames++;
+ }
+
+ return frame_list;
}
gnu::classpath::jdwp::VMFrame *
-gnu::classpath::jdwp::VMVirtualMachine::getFrame (Thread *thread,
- ::java::nio::ByteBuffer *bb)
+gnu::classpath::jdwp::VMVirtualMachine::
+getFrame (Thread *thread, jlong frameID)
{
- return NULL;
+ using namespace gnu::classpath::jdwp::exception;
+
+ _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
+ jint depth = 0;
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID);
+
+ // We need to find the stack depth of the frame, so search through the call
+ // stack to find it. This also checks for a valid frameID.
+ while (vm_frame != frame)
+ {
+ vm_frame = vm_frame->next;
+ depth++;
+ if (vm_frame == NULL)
+ throw new InvalidFrameException (frameID);
+ }
+
+ Location *loc = NULL;
+ jvmtiFrameInfo info;
+ jvmtiError jerr;
+ jint num_frames;
+ jclass klass;
+
+ // Get the info for the frame of interest
+ jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ throw_jvmti_error (jerr);
+
+ jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ throw_jvmti_error (jerr);
+
+ VMMethod *meth
+ = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
+
+ jobject this_obj;
+
+ if (info.location == -1)
+ {
+ loc = new Location (meth, 0);
+ this_obj = NULL;
+ }
+ else
+ {
+ loc = new Location (meth, info.location);
+ _Jv_InterpFrame *iframe = reinterpret_cast<_Jv_InterpFrame *> (vm_frame);
+ this_obj = iframe->get_this_ptr ();
+ }
+
+ return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc,
+ this_obj);
}
jint
-gnu::classpath::jdwp::VMVirtualMachine::getFrameCount (Thread *thread)
+gnu::classpath::jdwp::VMVirtualMachine::
+getFrameCount (Thread *thread)
{
- return 0;
+ jint frame_count;
+
+ jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ throw_jvmti_error (jerr);
+
+ return frame_count;
}
jint
-gnu::classpath::jdwp::VMVirtualMachine::getThreadStatus (Thread *thread)
+gnu::classpath::jdwp::VMVirtualMachine::
+getThreadStatus (Thread *thread)
{
- return 0;
+ jint thr_state, status;
+
+ jvmtiError jerr = _jdwp_jvmtiEnv->GetThreadState (thread, &thr_state);
+ if (jerr != JVMTI_ERROR_NONE)
+ throw_jvmti_error (jerr);
+
+ if (thr_state & JVMTI_THREAD_STATE_SLEEPING)
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::SLEEPING;
+ else if (thr_state & JVMTI_THREAD_STATE_RUNNABLE)
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
+ else if (thr_state & JVMTI_THREAD_STATE_WAITING)
+ {
+ if (thr_state & (JVMTI_THREAD_STATE_IN_OBJECT_WAIT
+ | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER))
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::MONITOR;
+ else
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::WAIT;
+ }
+ else
+ {
+ // The thread is not SLEEPING, MONITOR, or WAIT. It may, however, be
+ // alive but not yet started.
+ if (!(thr_state & (JVMTI_THREAD_STATE_ALIVE
+ | JVMTI_THREAD_STATE_TERMINATED)))
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
+ status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::ZOMBIE;
+ }
+
+ return status;
}
java::util::ArrayList *
-gnu::classpath::jdwp::VMVirtualMachine::getLoadRequests (ClassLoader *cl)
+gnu::classpath::jdwp::VMVirtualMachine::
+getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
{
- return NULL;
+ return new ::java::util::ArrayList ();
}
MethodResult *
-gnu::classpath::jdwp::VMVirtualMachine::executeMethod (jobject obj,
- Thread *thread,
- jclass clazz,
- reflect::Method *method,
- jobjectArray values,
- jboolean nonVirtual)
+gnu::classpath::jdwp::VMVirtualMachine::
+executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
+ MAYBE_UNUSED jclass clazz, MAYBE_UNUSED reflect::Method *method,
+ MAYBE_UNUSED jobjectArray values,
+ MAYBE_UNUSED jboolean nonVirtual)
{
return NULL;
}
jstring
-gnu::classpath::jdwp::VMVirtualMachine::getSourceFile (jclass clazz)
+gnu::classpath::jdwp::VMVirtualMachine::
+getSourceFile (jclass clazz)
+{
+ jstring file = _Jv_GetInterpClassSourceFile (clazz);
+
+ // Check if the source file was found.
+ if (file == NULL)
+ throw new exception::AbsentInformationException (
+ _Jv_NewStringUTF("Source file not found"));
+
+ return file;
+}
+
+void
+gnu::classpath::jdwp::VMVirtualMachine::
+redefineClasses (MAYBE_UNUSED JArray<jclass> *types,
+ MAYBE_UNUSED JArray<jbyteArray> *bytecodes)
+{
+}
+
+void
+gnu::classpath::jdwp::VMVirtualMachine::
+setDefaultStratum (MAYBE_UNUSED jstring stratum)
+{
+}
+
+jstring
+gnu::classpath::jdwp::VMVirtualMachine::
+getSourceDebugExtension (MAYBE_UNUSED jclass klass)
{
return NULL;
}
+jbyteArray
+gnu::classpath::jdwp::VMVirtualMachine::
+getBytecodes (MAYBE_UNUSED gnu::classpath::jdwp::VMMethod *method)
+{
+ return NULL;
+}
+
+gnu::classpath::jdwp::util::MonitorInfo *
+gnu::classpath::jdwp::VMVirtualMachine::
+getMonitorInfo (MAYBE_UNUSED jobject obj)
+{
+ return NULL;
+}
+
+jobjectArray
+gnu::classpath::jdwp::VMVirtualMachine::
+getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread *thread)
+{
+ return NULL;
+}
+
+jobject
+gnu::classpath::jdwp::VMVirtualMachine::
+getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread *thread)
+{
+ return NULL;
+}
+
+void
+gnu::classpath::jdwp::VMVirtualMachine::
+popFrames (MAYBE_UNUSED ::java::lang::Thread *thread,
+ MAYBE_UNUSED jlong frameId)
+{
+}
+
+// A simple caching function used while single-stepping
+static jvmtiError
+get_linetable (jvmtiEnv *env, jmethodID method, jint *count_ptr,
+ jvmtiLineNumberEntry **table_ptr)
+{
+ static jint last_count = 0;
+ static jvmtiLineNumberEntry *last_table = NULL;
+ static jmethodID last_method = 0;
+
+ if (method == last_method)
+ {
+ *count_ptr = last_count;
+ *table_ptr = last_table;
+ return JVMTI_ERROR_NONE;
+ }
+
+ jvmtiError err;
+ jint count;
+ jvmtiLineNumberEntry *table;
+ err = env->GetLineNumberTable (method, &count, &table);
+ if (err != JVMTI_ERROR_NONE)
+ {
+ // Keep last table in cache
+ return err;
+ }
+
+ env->Deallocate ((unsigned char *) last_table);
+ last_table = *table_ptr = table;
+ last_count = *count_ptr = count;
+ return JVMTI_ERROR_NONE;
+}
+
+static gnu::classpath::jdwp::event::filters::StepFilter *
+get_request_step_filter (EventRequest *request)
+{
+ ::java::util::Collection *filters = request->getFilters ();
+ ::java::util::Iterator *iter = filters->iterator ();
+ filters::StepFilter *filter = NULL;
+ while (iter->hasNext ())
+ {
+ using namespace gnu::classpath::jdwp::event::filters;
+ IEventFilter *next = (IEventFilter *) iter->next ();
+ if (next->getClass () == &StepFilter::class$)
+ {
+ filter = reinterpret_cast<StepFilter *> (next);
+ break;
+ }
+ }
+
+ return filter;
+}
+
+static Location *
+get_request_location (EventRequest *request)
+{
+ Location *loc = NULL;
+ ::java::util::Collection *filters = request->getFilters ();
+ ::java::util::Iterator *iter = filters->iterator ();
+ while (iter->hasNext ())
+ {
+ using namespace gnu::classpath::jdwp::event::filters;
+ IEventFilter *filter = (IEventFilter *) iter->next ();
+ if (filter->getClass () == &LocationOnlyFilter::class$)
+ {
+ LocationOnlyFilter *lof
+ = reinterpret_cast<LocationOnlyFilter *> (filter);
+ loc = lof->getLocation ();
+ }
+ }
+
+ return loc;
+}
+
static void
+handle_single_step (jvmtiEnv *env, struct step_info *sinfo, jthread thread,
+ jmethodID method, jlocation location)
+{
+ using namespace gnu::classpath::jdwp;
+
+ if (sinfo == NULL || sinfo->size == JdwpConstants$StepSize::MIN)
+ {
+ // Stop now
+ goto send_notification;
+ }
+ else
+ {
+ // Check if we're on a new source line
+ /* This is a little inefficient when we're stepping OVER,
+ but this must be done when stepping INTO. */
+ jint count;
+ jvmtiLineNumberEntry *table;
+ if (get_linetable (env, method, &count, &table) == JVMTI_ERROR_NONE)
+ {
+ jint i;
+ for (i = 0; i < count; ++i)
+ {
+ if (table[i].start_location == location)
+ {
+ // This is the start of a new line -- stop
+ goto send_notification;
+ }
+ }
+
+ // Not at a new source line -- just keep stepping
+ return;
+ }
+ else
+ {
+ /* Something went wrong: either "absent information"
+ or "out of memory" ("invalid method id" and "native
+ method" aren't possible -- those are validated before
+ single stepping is enabled).
+
+ Do what gdb does: just keep going. */
+ return;
+ }
+ }
+
+ send_notification:
+ jclass klass;
+ jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
+ if (err != JVMTI_ERROR_NONE)
+ {
+ fprintf (stderr, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
+ return;
+ }
+
+ VMMethod *vmmethod = new VMMethod (klass, reinterpret_cast<jlong> (method));
+ Location *loc = new Location (vmmethod, location);
+ JvAssert (thread->frame.frame_type == frame_interpreter);
+ _Jv_InterpFrame *iframe
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+ jobject instance = iframe->get_this_ptr ();
+ event::SingleStepEvent *event
+ = new event::SingleStepEvent (thread, loc, instance);
+
+ // We only want to send the notification (and consequently
+ // suspend) if we are not about to execute a breakpoint.
+ _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (iframe->self);
+ if (im->breakpoint_at (location))
+ {
+ // Next insn is a breakpoint -- record event and
+ // wait for the JVMTI breakpoint notification to
+ // enforce a suspension policy.
+ VMVirtualMachine::_event_list->add (event);
+ }
+ else
+ {
+ // Next insn is not a breakpoint, so send notification
+ // and enforce the suspend policy.
+ Jdwp::notify (event);
+ }
+}
+
+static void
+throw_jvmti_error (jvmtiError err)
+{
+ char *error;
+ jstring msg;
+ if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
+ {
+ msg = JvNewStringLatin1 (error);
+ _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
+ }
+ else
+ msg = JvNewStringLatin1 ("out of memory");
+
+ using namespace gnu::classpath::jdwp::exception;
+ throw new JdwpInternalErrorException (msg);
+}
+
+static void JNICALL
+jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
+ jthread thread, jmethodID method, jlocation location)
+{
+ jclass klass;
+ jvmtiError err;
+ err = env->GetMethodDeclaringClass (method, &klass);
+ JvAssert (err == JVMTI_ERROR_NONE);
+
+ using namespace gnu::classpath::jdwp;
+ using namespace gnu::classpath::jdwp::event;
+
+ jlong methodId = reinterpret_cast<jlong> (method);
+ VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
+ Location *loc = new Location (meth, location);
+ JvAssert (thread->frame.frame_type == frame_interpreter);
+ _Jv_InterpFrame *iframe
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+ jobject instance = iframe->get_this_ptr ();
+ BreakpointEvent *event = new BreakpointEvent (thread, loc, instance);
+
+ VMVirtualMachine::_event_list->add (event);
+ JArray<Event *> *events
+ = ((JArray<Event *> *)
+ JvNewObjectArray (VMVirtualMachine::_event_list->size (),
+ &Event::class$, NULL));
+ VMVirtualMachine::_event_list->toArray ((jobjectArray) events);
+ VMVirtualMachine::_event_list->clear ();
+ Jdwp::notify (events);
+}
+
+static void JNICALL
+jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
+ jthread thread, jclass klass)
+{
+ using namespace gnu::classpath::jdwp;
+
+ jint status = VMVirtualMachine::getClassStatus (klass);
+ event::ClassPrepareEvent *event
+ = new event::ClassPrepareEvent (thread, klass, status);
+ Jdwp::notify (event);
+}
+
+static void JNICALL
+jdwpExceptionCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
+ jmethodID method, jlocation location, jobject exception,
+ jmethodID catch_method, jlocation catch_location)
+{
+ using namespace gnu::classpath::jdwp;
+ jclass throw_klass;
+ jvmtiError err = env->GetMethodDeclaringClass (method, &throw_klass);
+ if (err != JVMTI_ERROR_NONE)
+ {
+ fprintf (stderr, "libgcj: internal error: could not find class for ");
+ fprintf (stderr, "method throwing exception -- continuing\n");
+ return;
+ }
+
+ VMMethod *vmmethod = new VMMethod (throw_klass,
+ reinterpret_cast<jlong> (method));
+ Location *throw_loc = new Location (vmmethod, location);
+ Location *catch_loc = NULL;
+ if (catch_method == 0)
+ catch_loc = Location::getEmptyLocation ();
+ else
+ {
+ jclass catch_klass;
+ err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
+ if (err != JVMTI_ERROR_NONE)
+ {
+ fprintf (stderr,
+ "libgcj: internal error: could not find class for ");
+ fprintf (stderr,
+ "method catching exception -- ignoring\n");
+ }
+ else
+ {
+ vmmethod = new VMMethod (catch_klass,
+ reinterpret_cast<jlong> (catch_method));
+ catch_loc = new Location (vmmethod, catch_location);
+ }
+ }
+
+ _Jv_InterpFrame *iframe
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+ jobject instance = (iframe == NULL) ? NULL : iframe->get_this_ptr ();
+ Throwable *throwable = reinterpret_cast<Throwable *> (exception);
+ event::ExceptionEvent *e = new ExceptionEvent (throwable, thread,
+ throw_loc, catch_loc,
+ throw_klass, instance);
+ Jdwp::notify (e);
+}
+
+static void JNICALL
+jdwpSingleStepCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
+ jmethodID method, jlocation location)
+{
+ jobject si =
+ gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
+ struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
+
+ if (sinfo == NULL)
+ {
+ // no step filter for this thread - simply report it
+ handle_single_step (env, NULL, thread, method, location);
+ }
+ else
+ {
+ // A step filter exists for this thread
+ using namespace gnu::classpath::jdwp;
+
+ _Jv_InterpFrame *frame
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+
+ switch (sinfo->depth)
+ {
+ case JdwpConstants$StepDepth::INTO:
+ /* This is the easy case. We ignore the method and
+ simply stop at either the next insn, or the next source
+ line. */
+ handle_single_step (env, sinfo, thread, method, location);
+ break;
+
+ case JdwpConstants$StepDepth::OVER:
+ /* This is also a pretty easy case. We just make sure that
+ the methods are the same and that we are at the same
+ stack depth, but we should also stop on the next
+ insn/line if the stack depth is LESS THAN it was when
+ we started stepping. */
+ if (method == sinfo->method)
+ {
+ // Still in the same method -- must be at same stack depth
+ // to avoid confusion with recursive methods.
+ if (frame->depth () == sinfo->stack_depth)
+ handle_single_step (env, sinfo, thread, method, location);
+ }
+ else if (frame->depth () < sinfo->stack_depth)
+ {
+ // The method in which we were stepping was popped off
+ // the stack. We simply need to stop at the next insn/line.
+ handle_single_step (env, sinfo, thread, method, location);
+ }
+ break;
+
+ case JdwpConstants$StepDepth::OUT:
+ // All we need to do is check the stack depth
+ if (sinfo->stack_depth > frame->depth ())
+ handle_single_step (env, sinfo, thread, method, location);
+ break;
+
+ default:
+ /* This should not happen. The JDWP back-end should have
+ validated the StepFilter. */
+ fprintf (stderr,
+ "libgcj: unknown step depth while single stepping\n");
+ return;
+ }
+ }
+}
+
+static void JNICALL
+jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
+ jthread thread)
+{
+ using namespace gnu::classpath::jdwp::event;
+
+ ThreadEndEvent *e = new ThreadEndEvent (thread);
+ gnu::classpath::jdwp::Jdwp::notify (e);
+}
+
+static void JNICALL
+jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
+ jthread thread)
+{
+ using namespace gnu::classpath::jdwp::event;
+
+ ThreadStartEvent *e = new ThreadStartEvent (thread);
+ gnu::classpath::jdwp::Jdwp::notify (e);
+}
+
+static void JNICALL
+jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
+{
+ using namespace gnu::classpath::jdwp::event;
+ gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
+}
+
+static void JNICALL
jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
jthread thread)
{
+ // The VM is now initialized, add our callbacks
+ jvmtiEventCallbacks callbacks;
+ DEFINE_CALLBACK (callbacks, Breakpoint);
+ DEFINE_CALLBACK (callbacks, ClassPrepare);
+ DEFINE_CALLBACK (callbacks, Exception);
+ DEFINE_CALLBACK (callbacks, SingleStep);
+ DEFINE_CALLBACK (callbacks, ThreadEnd);
+ DEFINE_CALLBACK (callbacks, ThreadStart);
+ DEFINE_CALLBACK (callbacks, VMDeath);
+ _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
+
+ // Enable callbacks
+ ENABLE_EVENT (BREAKPOINT, NULL);
+ ENABLE_EVENT (CLASS_PREPARE, NULL);
+ ENABLE_EVENT (EXCEPTION, NULL);
+ // SingleStep is enabled only when needed
+ ENABLE_EVENT (THREAD_END, NULL);
+ ENABLE_EVENT (THREAD_START, NULL);
+ ENABLE_EVENT (VM_DEATH, NULL);
+
// Send JDWP VMInit
using namespace gnu::classpath::jdwp::event;
- Thread *init_thread = reinterpret_cast<Thread *> (thread);
- gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (init_thread));
+ gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));
}
diff --git a/libjava/gnu/gcj/jvmti/BreakpointManager.java b/libjava/gnu/gcj/jvmti/BreakpointManager.java
index 205bf6d8a5b..5ef1b08d4df 100644
--- a/libjava/gnu/gcj/jvmti/BreakpointManager.java
+++ b/libjava/gnu/gcj/jvmti/BreakpointManager.java
@@ -1,6 +1,6 @@
// BreakpointManager.java - A convenience class for dealing with breakpoints
-/* Copyright (C) 2006 Free Software Foundation
+/* Copyright (C) 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -45,6 +45,7 @@ public class BreakpointManager
{
Breakpoint bp = new Breakpoint (method, location);
Location loc = new Location (method, location);
+ bp.install ();
_instance._breakpoints.put (loc, bp);
return bp;
}
@@ -58,7 +59,12 @@ public class BreakpointManager
public static void deleteBreakpoint (long method, long location)
{
Location loc = new Location (method, location);
- _instance._breakpoints.remove (loc);
+ Breakpoint bp = (Breakpoint) _instance._breakpoints.get (loc);
+ if (bp != null)
+ {
+ bp.remove ();
+ _instance._breakpoints.remove (loc);
+ }
}
/**
diff --git a/libjava/gnu/gcj/jvmti/natBreakpoint.cc b/libjava/gnu/gcj/jvmti/natBreakpoint.cc
index ab9de417bb8..5dbd3f834dd 100644
--- a/libjava/gnu/gcj/jvmti/natBreakpoint.cc
+++ b/libjava/gnu/gcj/jvmti/natBreakpoint.cc
@@ -1,6 +1,6 @@
// natBreakpoint.cc - C++ side of Breakpoint
-/* Copyright (C) 2006 Free Software Foundation
+/* Copyright (C) 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -17,6 +17,7 @@ details. */
#include <jvmti.h>
#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
static _Jv_InterpMethod *
get_interp_method (jlong method)
@@ -39,7 +40,6 @@ gnu::gcj::jvmti::Breakpoint::initialize_native ()
pc_t code = imeth->get_insn (location);
data = (RawDataManaged *) JvAllocBytes (sizeof (*code));
memcpy (data, code, sizeof (*code));
- install ();
}
void
@@ -55,3 +55,18 @@ gnu::gcj::jvmti::Breakpoint::remove ()
_Jv_InterpMethod *imeth = get_interp_method (method);
imeth->set_insn (location, reinterpret_cast<pc_t> (data));
}
+
+#ifdef DIRECT_THREADED
+void
+_Jv_RewriteBreakpointInsn (jmethodID mid, jlocation loc, pc_t new_insn)
+{
+ using namespace ::gnu::gcj::jvmti;
+ Breakpoint *bp
+ = BreakpointManager::getBreakpoint (reinterpret_cast<jlong> (mid), loc);
+ if (bp != NULL)
+ {
+ pc_t old_insn = (pc_t) bp->data;
+ old_insn->insn = new_insn;
+ }
+}
+#endif // DIRECT_THREADED
diff --git a/libjava/headers.txt b/libjava/headers.txt
index 3e08f175889..cc79b771b3d 100644
--- a/libjava/headers.txt
+++ b/libjava/headers.txt
@@ -65,5 +65,13 @@ friend class java::io::ObjectInputStream;
friend java::lang::reflect::Method* ::_Jv_GetReflectedMethod (jclass, _Jv_Utf8Const*, _Jv_Utf8Const*);
friend java::lang::reflect::Method* ::_Jv_LookupProxyMethod (jclass, _Jv_Utf8Const *, _Jv_Utf8Const *);
+class gnu/gcj/jvmti/Breakpoint
+prepend #ifdef DIRECT_THREADED
+prepend void _Jv_RewriteBreakpointInsn (jmethodID, jlocation, pc_t);
+prepend #endif
+add #ifdef DIRECT_THREADED
+add friend void (::_Jv_RewriteBreakpointInsn (jmethodID, jlocation, pc_t));
+add #endif
+
class gnu/gcj/runtime/ExtensionClassLoader
friend class ::java::lang::ClassLoader;
diff --git a/libjava/include/boehm-gc.h b/libjava/include/boehm-gc.h
index 7e61b8e48fb..ed8ac6aa2e3 100644
--- a/libjava/include/boehm-gc.h
+++ b/libjava/include/boehm-gc.h
@@ -1,7 +1,7 @@
// -*- c++ -*-
// boehm-gc.h - Defines for Boehm collector.
-/* Copyright (C) 1998, 1999, 2002, 2004, 2006 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2002, 2004, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -93,4 +93,6 @@ extern "C" void _Jv_SuspendThread (_Jv_Thread_t *);
// Resume a suspended thread.
extern "C" void _Jv_ResumeThread (_Jv_Thread_t *);
+// Is the given thread suspended?
+extern "C" int _Jv_IsThreadSuspended (_Jv_Thread_t *);
#endif /* __JV_BOEHM_GC__ */
diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h
index ae93109ef7b..52a04e78e1d 100644
--- a/libjava/include/java-interp.h
+++ b/libjava/include/java-interp.h
@@ -1,6 +1,6 @@
// java-interp.h - Header file for the bytecode interpreter. -*- c++ -*-
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -137,6 +137,21 @@ struct _Jv_LineTableEntry
int line;
};
+// This structure holds local variable information.
+// The pc value is the first pc where the variable must have a value and it
+// must continue to have a value until (start_pc + length).
+// The name is the variable name, and the descriptor contains type information.
+// The slot is the index in the local variable array of this method, long and
+// double occupy slot and slot+1.
+struct _Jv_LocalVarTableEntry
+{
+ int bytecode_start_pc;
+ int length;
+ char *name;
+ char *descriptor;
+ int slot;
+};
+
class _Jv_InterpMethod : public _Jv_MethodBase
{
// Breakpoint instruction
@@ -157,6 +172,10 @@ class _Jv_InterpMethod : public _Jv_MethodBase
// Length of the line_table - when this is zero then line_table is NULL.
int line_table_len;
_Jv_LineTableEntry *line_table;
+
+ // The local variable table length and the table itself
+ int local_var_table_len;
+ _Jv_LocalVarTableEntry *local_var_table;
pc_t prepared;
int number_insn_slots;
@@ -205,11 +224,16 @@ class _Jv_InterpMethod : public _Jv_MethodBase
// number info is unavailable.
int get_source_line(pc_t mpc);
+ public:
+
// Convenience function for indexing bytecode PC/insn slots in
// line tables for JDWP
jlong insn_index (pc_t pc);
- public:
+ // Helper function used to check if there is a handler for an exception
+ // present at this code index
+ jboolean check_handler (pc_t *pc, _Jv_InterpMethod *meth,
+ java::lang::Throwable *ex);
/* Get the line table for this method.
* start is the lowest index in the method
@@ -219,6 +243,25 @@ class _Jv_InterpMethod : public _Jv_MethodBase
*/
void get_line_table (jlong& start, jlong& end, jintArray& line_numbers,
jlongArray& code_indices);
+
+ int get_max_locals ()
+ {
+ return static_cast<int> (max_locals);
+ }
+
+ /* Get info for a local variable of this method.
+ * If there is no loca_var_table for this method it will return -1.
+ * table_slot indicates which slot in the local_var_table to get, if there is
+ * no variable at this location it will return 0.
+ * Otherwise, it will return the number of table slots after the selected
+ * slot, indexed from 0.
+ *
+ * Example: there are 5 slots in the table, you request slot 0 so it will
+ * return 4.
+ */
+ int get_local_var_table (char **name, char **sig, char **generic_sig,
+ jlong *startloc, jint *length, jint *slot,
+ int table_slot);
/* Installs a break instruction at the given code index. Returns
the pc_t of the breakpoint or NULL if index is invalid. */
@@ -231,6 +274,9 @@ class _Jv_InterpMethod : public _Jv_MethodBase
the insn or NULL if index is invalid. */
pc_t set_insn (jlong index, pc_t insn);
+ // Is the given location in this method a breakpoint?
+ bool breakpoint_at (jlong index);
+
#ifdef DIRECT_THREADED
friend void _Jv_CompileMethod (_Jv_InterpMethod*);
#endif
@@ -263,6 +309,7 @@ class _Jv_InterpClass
#endif
friend _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass);
+ friend jstring _Jv_GetInterpClassSourceFile (jclass);
};
extern inline _Jv_MethodBase **
@@ -316,35 +363,123 @@ public:
}
};
-// The interpreted call stack, represented by a linked list of frames.
-struct _Jv_InterpFrame
+enum _Jv_FrameType
+{
+ frame_native,
+ frame_interpreter,
+ frame_proxy
+};
+
+// The composite call stack as represented by a linked list of frames
+class _Jv_Frame
{
+public:
+ java::lang::Thread *thread;
+
union
{
+ _Jv_MethodBase *self;
void *meth;
- _Jv_InterpMethod *self;
_Jv_Method *proxyMethod;
};
- java::lang::Thread *thread;
- _Jv_InterpFrame *next;
+
+ //The full list of frames, JNI and interpreted
+ _Jv_Frame *next;
+ _Jv_FrameType frame_type;
+
+ _Jv_Frame (_Jv_MethodBase *s, java::lang::Thread *thr, _Jv_FrameType type)
+ {
+ self = s;
+ frame_type = type;
+ next = (_Jv_Frame *) thr->frame;
+ thr->frame = (gnu::gcj::RawData *) this;
+ thread = thr;
+ }
+
+ ~_Jv_Frame ()
+ {
+ thread->frame = (gnu::gcj::RawData *) next;
+ }
+
+ int depth ()
+ {
+ int depth = 0;
+ struct _Jv_Frame *f;
+ for (f = this; f != NULL; f = f->next)
+ ++depth;
+
+ return depth;
+ }
+};
+
+// An interpreted frame in the call stack
+class _Jv_InterpFrame : public _Jv_Frame
+{
+public:
+
+ // Keep the purely interpreted list around so as not to break backtraces
+ _Jv_InterpFrame *next_interp;
+
union
{
pc_t pc;
jclass proxyClass;
};
- _Jv_InterpFrame (void *meth, java::lang::Thread *thr, jclass proxyClass = NULL)
+ // Pointer to the actual pc value.
+ pc_t *pc_ptr;
+
+ //Debug info for local variables.
+ _Jv_word *locals;
+ char *locals_type;
+
+ // Object pointer for this frame ("this")
+ jobject obj_ptr;
+
+ _Jv_InterpFrame (void *meth, java::lang::Thread *thr, jclass proxyCls = NULL,
+ pc_t *pc = NULL)
+ : _Jv_Frame (reinterpret_cast<_Jv_MethodBase *> (meth), thr,
+ frame_interpreter)
{
- this->meth = meth;
- thread = thr;
- next = (_Jv_InterpFrame *) thr->interp_frame;
+ next_interp = (_Jv_InterpFrame *) thr->interp_frame;
+ proxyClass = proxyCls;
thr->interp_frame = (gnu::gcj::RawData *) this;
- this->proxyClass = proxyClass;
+ obj_ptr = NULL;
+ pc_ptr = pc;
}
~_Jv_InterpFrame ()
{
- thread->interp_frame = (gnu::gcj::RawData *) next;
+ thread->interp_frame = (gnu::gcj::RawData *) next_interp;
+ }
+
+ jobject get_this_ptr ()
+ {
+ return obj_ptr;
+ }
+
+ pc_t get_pc ()
+ {
+ pc_t pc;
+
+ // If the PC_PTR is NULL, we are not debugging.
+ if (pc_ptr == NULL)
+ pc = 0;
+ else
+ pc = *pc_ptr;
+
+ return pc - 1;
+ }
+};
+
+// A native frame in the call stack really just a placeholder
+class _Jv_NativeFrame : public _Jv_Frame
+{
+public:
+
+ _Jv_NativeFrame (_Jv_JNIMethod *s, java::lang::Thread *thr)
+ : _Jv_Frame (s, thr, frame_native)
+ {
}
};
diff --git a/libjava/include/java-stack.h b/libjava/include/java-stack.h
index d4d63d74342..49e68412be6 100644
--- a/libjava/include/java-stack.h
+++ b/libjava/include/java-stack.h
@@ -41,13 +41,6 @@ extern "Java"
}
}
-enum _Jv_FrameType
-{
- frame_native,
- frame_interpreter,
- frame_proxy
-};
-
#ifdef INTERPRETER
struct _Jv_InterpFrameInfo
{
diff --git a/libjava/include/jvmti-int.h b/libjava/include/jvmti-int.h
index f88b4ce0a3a..6b09c837659 100644
--- a/libjava/include/jvmti-int.h
+++ b/libjava/include/jvmti-int.h
@@ -1,5 +1,5 @@
/* jvmti-int.h -- Internal JVMTI definitions
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,6 +37,10 @@ executable file might be covered by the GNU General Public License. */
False means no JVMTI environment requested that event type. */
namespace JVMTI
{
+ // Is JVMTI enabled? (i.e., any jvmtiEnv created?)
+ extern bool enabled;
+
+ // Event notifications
extern bool VMInit;
extern bool VMDeath;
extern bool ThreadStart;
@@ -82,4 +86,9 @@ namespace JVMTI
For speed, this function should only be called after
JVMTI_REQUESTED_EVENT is checked. */
extern void _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...);
+// Returns the jvmtiEnv used by the JDWP backend
+extern jvmtiEnv *_Jv_GetJDWP_JVMTIEnv (void);
+
+// Reports JVMTI excpetions
+extern void _Jv_ReportJVMTIExceptionThrow (jthrowable);
#endif /* __GCJ_JVMTI_INT_H__ */
diff --git a/libjava/include/jvmti_md.h b/libjava/include/jvmti_md.h
index 549d42151d3..2270f3f3d16 100644
--- a/libjava/include/jvmti_md.h
+++ b/libjava/include/jvmti_md.h
@@ -1,5 +1,5 @@
/* jvmti_md.h
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -53,6 +53,14 @@ executable file might be covered by the GNU General Public License. */
/* One for each callback. */ \
bool enabled[EVENT_SLOTS];
+/* Redefine the standard JVMTI types to something a little more
+ precise than "jobject". */
+#define _CLASSPATH_VM_JVMTI_TYPES_DEFINED
+typedef java::lang::Thread *jthread;
+typedef java::lang::ThreadGroup *jthreadGroup;
+typedef jlong jlocation;
+typedef struct _Jv_rawMonitorID *jrawMonitorID;
+
#endif /* __GCJ_JNI_IMPL__ */
#endif /* __GCJ_JVMTI_MD_H__ */
diff --git a/libjava/include/no-gc.h b/libjava/include/no-gc.h
index 193b8ea4d05..ce0ffb81017 100644
--- a/libjava/include/no-gc.h
+++ b/libjava/include/no-gc.h
@@ -1,7 +1,7 @@
// -*- c++ -*-
// no-gc.h - Defines for no garbage collector.
-/* Copyright (C) 1998, 1999, 2006 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -18,4 +18,6 @@ extern "C" void _Jv_SuspendThread (_Jv_Thread_t *);
// Resume a suspended thread.
extern "C" void _Jv_ResumeThread (_Jv_Thread_t *);
+// Is the given thread suspended?
+extern "C" int _Jv_IsThreadSuspended (_Jv_Thread_t *);
#endif /* __JV_NO_GC__ */
diff --git a/libjava/include/win32-threads.h b/libjava/include/win32-threads.h
index 442149c3cd8..b8f70f5cba9 100644
--- a/libjava/include/win32-threads.h
+++ b/libjava/include/win32-threads.h
@@ -227,5 +227,6 @@ private:
#undef STRICT
#undef VOID
#undef TEXT
+#undef OUT
#endif /* __JV_WIN32_THREADS__ */
diff --git a/libjava/interpret-run.cc b/libjava/interpret-run.cc
index 26cc4a616dd..9be08df488b 100644
--- a/libjava/interpret-run.cc
+++ b/libjava/interpret-run.cc
@@ -1,6 +1,6 @@
// interpret-run.cc - Code to interpret bytecode
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -12,6 +12,8 @@ details. */
* compiled directly. */
using namespace java::lang::reflect;
+
+ pc_t pc = NULL;
// FRAME_DESC registers this particular invocation as the top-most
// interpreter frame. This lets the stack tracing code (for
@@ -20,13 +22,108 @@ details. */
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
+
+#ifdef DEBUG
+ _Jv_InterpFrame frame_desc (meth, thread, NULL, &pc);
+#else
_Jv_InterpFrame frame_desc (meth, thread);
+#endif
_Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
_Jv_word locals[meth->max_locals];
+#ifdef DEBUG
+ // This is the information needed to get and set local variables with
+ // proper type checking.
+ frame_desc.locals = locals;
+ char locals_type[meth->max_locals];
+ frame_desc.locals_type = locals_type;
+
+ // Set all slots as invalid until they are written to.
+ memset (locals_type, 'x', meth->max_locals);
+
+ // We need to set the local variable types for the method arguments since
+ // they are valid at invocation.
+
+ _Jv_Method *method = meth->get_method ();
+ int type_ctr = 0;
+
+ // If the method is non-static, we need to set the type for the "this" pointer.
+ if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0)
+ {
+ if (args)
+ {
+ // Set the "this" pointer for this frame.
+ _Jv_word *this_ptr = reinterpret_cast<_Jv_word *> (args);
+ frame_desc.obj_ptr = this_ptr[0].o;
+ }
+
+ frame_desc.locals_type[0] = 'o';
+ type_ctr++;
+ }
+
+ // Now parse the method signature to set the types of the other arguments.
+ int sig_len = method->signature->len ();
+ char *signature = method->signature->chars ();
+ for (int i = 1; signature[i] != ')' && i <= sig_len; i++)
+ {
+ if (signature[i] == 'Z' || signature[i] == 'B' || signature[i] == 'C'
+ || signature[i] == 'S' || signature[i] == 'I')
+ {
+ frame_desc.locals_type[type_ctr] = 'i';
+ type_ctr++;
+ continue;
+ }
+ else if (signature[i] == 'F')
+ {
+ frame_desc.locals_type[type_ctr] = 'f';
+ type_ctr++;
+ continue;
+ }
+ else if (signature[i] == 'J')
+ {
+ frame_desc.locals_type[type_ctr] = 'l';
+ frame_desc.locals_type[type_ctr+1] = 'x';
+ type_ctr += 2;
+ continue;
+ }
+ else if (signature[i] == 'D')
+ {
+ frame_desc.locals_type[type_ctr] = 'd';
+ frame_desc.locals_type[type_ctr+1] = 'x';
+ type_ctr += 2;
+ continue;
+ }
+ else if (signature[i] == 'L')
+ {
+ frame_desc.locals_type[type_ctr] = 'o';
+ type_ctr++;
+ while (signature[i] != ';')
+ i++;
+ continue;
+ }
+ else if (signature[i] == '[')
+ {
+ frame_desc.locals_type[type_ctr] = 'o';
+ type_ctr++;
+
+ // Ignore multi-dimensional arrays.
+ while (signature[i] == '[')
+ i++;
+
+ // Check for an object array
+ if (signature[i] == 'L')
+ {
+ while (signature[i] != ';')
+ i++;
+ }
+ continue;
+ }
+ }
+#endif /* DEBUG */
+
#define INSN_LABEL(op) &&insn_##op
static const void *const insn_target[] =
@@ -217,7 +314,7 @@ details. */
INSN_LABEL(invokespecial),
INSN_LABEL(invokestatic),
INSN_LABEL(invokeinterface),
- INSN_LABEL (breakpoint),
+ INSN_LABEL(breakpoint),
INSN_LABEL(new),
INSN_LABEL(newarray),
INSN_LABEL(anewarray),
@@ -244,11 +341,58 @@ details. */
#endif
};
- pc_t pc;
-
#ifdef DIRECT_THREADED
+#ifdef DEBUG
+#undef NEXT_INSN
+#define NEXT_INSN \
+ do \
+ { \
+ pc_t insn = pc++; \
+ if (JVMTI_REQUESTED_EVENT (SingleStep)) \
+ { \
+ JNIEnv *env = _Jv_GetCurrentJNIEnv (); \
+ jmethodID method = meth->self; \
+ jlocation loc = meth->insn_index (insn); \
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_SINGLE_STEP, thread, \
+ env, method, loc); \
+ } \
+ goto *(insn->insn); \
+ } \
+ while (0)
+
+#undef REWRITE_INSN
+#define REWRITE_INSN(INSN,SLOT,VALUE) \
+ do { \
+ if (pc[-2].insn == breakpoint_insn->insn) \
+ { \
+ using namespace ::gnu::gcj::jvmti; \
+ jlocation location = meth->insn_index (pc - 2); \
+ _Jv_RewriteBreakpointInsn (meth->self, location, (pc_t) INSN); \
+ } \
+ else \
+ pc[-2].insn = INSN; \
+ \
+ pc[-1].SLOT = VALUE; \
+ } \
+ while (0)
+
+#undef INTERP_REPORT_EXCEPTION
+#define INTERP_REPORT_EXCEPTION(Jthrowable) REPORT_EXCEPTION (Jthrowable)
+#else // !DEBUG
+#undef NEXT_INSN
#define NEXT_INSN goto *((pc++)->insn)
+#define REWRITE_INSN(INSN,SLOT,VALUE) \
+ do { \
+ pc[-2].insn = INSN; \
+ pc[-1].SLOT = VALUE; \
+ } \
+ while (0)
+
+#undef INTERP_REPORT_EXCEPTION
+#define INTERP_REPORT_EXCEPTION(Jthrowable) /* not needed when not debugging */
+#endif // !DEBUG
+
#define INTVAL() ((pc++)->int_val)
#define AVAL() ((pc++)->datum)
@@ -281,7 +425,22 @@ details. */
#else
+#ifdef DEBUG
+#define NEXT_INSN \
+ do \
+ { \
+ if (JVMTI_REQUESTED_EVENT (SingleStep)) \
+ { \
+ JNIEnv *env = _Jv_GetCurrentJNIEnv (); \
+ jmethodID method = meth->self; \
+ jlocation loc = meth->insn_index (pc); \
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_SINGLE_STEP, thread, \
+ env, method, loc); \
+ } \
+ goto *(insn_target[*pc++])
+#else
#define NEXT_INSN goto *(insn_target[*pc++])
+#endif
#define GET1S() get1s (pc++)
#define GET2S() (pc += 2, get2s (pc- 2))
@@ -381,8 +540,7 @@ details. */
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokevirtual_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokevirtual_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
@@ -1716,8 +1874,7 @@ details. */
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].datum = field->u.addr;
+ REWRITE_INSN (newinsn, datum, field->u.addr);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -1807,8 +1964,7 @@ details. */
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].int_val = field_offset;
+ REWRITE_INSN (newinsn, int_val, field_offset);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -1923,8 +2079,7 @@ details. */
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].datum = field->u.addr;
+ REWRITE_INSN (newinsn, datum, field->u.addr);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2022,8 +2177,7 @@ details. */
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].int_val = field_offset;
+ REWRITE_INSN (newinsn, int_val, field_offset);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2098,8 +2252,7 @@ details. */
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokespecial_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokespecial_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
@@ -2136,8 +2289,7 @@ details. */
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokestatic_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokestatic_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
@@ -2175,8 +2327,7 @@ details. */
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokeinterface_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokeinterface_resolved, datum, rmeth);
#else
// Skip dummy bytes.
pc += 2;
@@ -2209,13 +2360,16 @@ details. */
/* VM spec, section 3.11.5 */
if ((klass->getModifiers() & Modifier::ABSTRACT)
|| klass->isInterface())
- throw new java::lang::InstantiationException;
+ {
+ jthrowable t = new java::lang::InstantiationException;
+ INTERP_REPORT_EXCEPTION (t);
+ throw t;
+ }
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&new_resolved;
- pc[-1].datum = klass;
+ REWRITE_INSN (&&new_resolved, datum, klass);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2250,8 +2404,7 @@ details. */
PUSHA (result);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&anewarray_resolved;
- pc[-1].datum = klass;
+ REWRITE_INSN (&&anewarray_resolved, datum, klass);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2278,7 +2431,9 @@ details. */
insn_athrow:
{
jobject value = POPA();
- throw static_cast<jthrowable>(value);
+ jthrowable t = static_cast<jthrowable> (value);
+ INTERP_REPORT_EXCEPTION (t);
+ throw t;
}
NEXT_INSN;
@@ -2295,8 +2450,7 @@ details. */
PUSHA (value);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&checkcast_resolved;
- pc[-1].datum = to;
+ REWRITE_INSN (&&checkcast_resolved, datum, to);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2323,8 +2477,7 @@ details. */
PUSHI (to->isInstance (value));
#ifdef DIRECT_THREADED
- pc[-2].insn = &&instanceof_resolved;
- pc[-1].datum = to;
+ REWRITE_INSN (&&instanceof_resolved, datum, to);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
@@ -2466,47 +2619,56 @@ details. */
insn_breakpoint:
{
- // nothing just yet
- }
- }
- catch (java::lang::Throwable *ex)
- {
-#ifdef DIRECT_THREADED
- void *logical_pc = (void *) ((insn_slot *) pc - 1);
-#else
- int logical_pc = pc - 1 - meth->bytecode ();
-#endif
- _Jv_InterpException *exc = meth->exceptions ();
- jclass exc_class = ex->getClass ();
+ JvAssert (JVMTI_REQUESTED_EVENT (Breakpoint));
- for (int i = 0; i < meth->exc_count; i++)
- {
- if (PCVAL (exc[i].start_pc) <= logical_pc
- && logical_pc < PCVAL (exc[i].end_pc))
- {
-#ifdef DIRECT_THREADED
- jclass handler = (jclass) exc[i].handler_type.p;
-#else
- jclass handler = NULL;
- if (exc[i].handler_type.i != 0)
- handler = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
- exc[i].handler_type.i)).clazz;
-#endif /* DIRECT_THREADED */
+ // Send JVMTI notification
+ using namespace ::java::lang;
+ jmethodID method = meth->self;
+ jlocation location = meth->insn_index (pc - 1);
+ Thread *thread = Thread::currentThread ();
+ JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
- if (handler == NULL || handler->isAssignableFrom (exc_class))
- {
+ // Save the insn here since the breakpoint could be removed
+ // before the JVMTI notification returns.
+ using namespace gnu::gcj::jvmti;
+ Breakpoint *bp
+ = BreakpointManager::getBreakpoint (reinterpret_cast<jlong> (method),
+ location);
+ JvAssert (bp != NULL);
+ pc_t opc = reinterpret_cast<pc_t> (bp->getInsn ());
+
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_BREAKPOINT, thread, jni_env,
+ method, location);
+ // Continue execution
#ifdef DIRECT_THREADED
- pc = (insn_slot *) exc[i].handler_pc.p;
+ goto *(opc->insn);
#else
- pc = meth->bytecode () + exc[i].handler_pc.i;
-#endif /* DIRECT_THREADED */
- sp = stack;
- sp++->o = ex; // Push exception.
- NEXT_INSN;
- }
- }
- }
+ goto *(insn_target[*opc]);
+#endif
+ }
+ }
+ catch (java::lang::Throwable *ex)
+ {
+ // Check if the exception is handled and, if so, set the pc to the start
+ // of the appropriate catch block.
+ if (meth->check_handler (&pc, meth, ex))
+ {
+ sp = stack;
+ sp++->o = ex; // Push exception.
+#ifdef DEBUG
+ if (JVMTI_REQUESTED_EVENT (ExceptionCatch))
+ {
+ using namespace gnu::gcj::jvmti;
+ jlong catch_meth = reinterpret_cast<jlong> (meth->get_method ());
+ jlong catch_loc = meth->insn_index (pc);
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION_CATCH, thread,
+ _Jv_GetCurrentJNIEnv (), catch_meth,
+ catch_loc, ex);
+ }
+#endif
+ NEXT_INSN;
+ }
// No handler, so re-throw.
throw ex;
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
index 7dade7eec8c..cdc4d002fc8 100644
--- a/libjava/interpret.cc
+++ b/libjava/interpret.cc
@@ -1,6 +1,6 @@
// interpret.cc - Code for the interpreter
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -37,7 +37,11 @@ details. */
#include <execution.h>
#include <java/lang/reflect/Modifier.h>
-#include <gnu/classpath/jdwp/Jdwp.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
+
+#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
#ifdef INTERPRETER
@@ -60,6 +64,16 @@ static void throw_class_format_error (jstring msg)
static void throw_class_format_error (const char *msg)
__attribute__ ((__noreturn__));
+static void find_catch_location (jthrowable, jthread, jmethodID *, jlong *);
+
+// A macro to facilitate JVMTI exception reporting
+#define REPORT_EXCEPTION(Jthrowable) \
+ do { \
+ if (JVMTI_REQUESTED_EVENT (Exception)) \
+ _Jv_ReportJVMTIExceptionThrow (Jthrowable); \
+ } \
+ while (0)
+
#ifdef DIRECT_THREADED
// Lock to ensure that methods are not compiled concurrently.
// We could use a finer-grained lock here, however it is not safe to use
@@ -166,54 +180,81 @@ convert (FROM val, TO min, TO max)
# define LOADD(I) LOADL(I)
#endif
-#define STOREA(I) \
-do { \
-DEBUG_LOCALS_INSN(I, 'o'); \
-locals[I].o = (--sp)->o; \
-} while(0)
-#define STOREI(I) \
-do { \
-DEBUG_LOCALS_INSN (I, 'i'); \
-locals[I].i = (--sp)->i; \
-} while(0)
-#define STOREF(I) \
-do { \
-DEBUG_LOCALS_INSN (I, 'f'); \
-locals[I].f = (--sp)->f; \
-} while(0)
+#define STOREA(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'o'); \
+ locals[__idx].o = (--sp)->o; \
+ } \
+ while (0)
+#define STOREI(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'i'); \
+ locals[__idx].i = (--sp)->i; \
+ } while (0)
+#define STOREF(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'f'); \
+ locals[__idx].f = (--sp)->f; \
+ } \
+ while (0)
#if SIZEOF_VOID_P == 8
-# define STOREL(I) \
-do { \
-DEBUG_LOCALS_INSN (I, 'l'); \
-(sp -= 2, locals[I].l = sp->l); \
-} while(0)
-# define STORED(I) \
-do { \
-DEBUG_LOCALS_INSN (I, 'd'); \
-(sp -= 2, locals[I].d = sp->d); \
-} while(0)
+# define STOREL(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'l'); \
+ DEBUG_LOCALS_INSN (__idx + 1, 'x'); \
+ (sp -= 2, locals[__idx].l = sp->l); \
+ } \
+ while (0)
+# define STORED(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'd'); \
+ DEBUG_LOCALS_INSN (__idx + 1, 'x'); \
+ (sp -= 2, locals[__idx].d = sp->d); \
+ } \
+ while (0)
#else
-# define STOREL(I) \
-do { DEBUG_LOCALS_INSN(I, 'l'); \
- jint __idx = (I); \
- locals[__idx+1].ia[0] = (--sp)->ia[0]; \
- locals[__idx].ia[0] = (--sp)->ia[0]; \
- } while (0)
-# define STORED(I) \
-do { DEBUG_LOCALS_INSN(I, 'd'); \
- jint __idx = (I); \
- locals[__idx+1].ia[0] = (--sp)->ia[0]; \
- locals[__idx].ia[0] = (--sp)->ia[0]; \
- } while (0)
+# define STOREL(I) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'l'); \
+ DEBUG_LOCALS_INSN (__idx + 1, 'x'); \
+ locals[__idx + 1].ia[0] = (--sp)->ia[0]; \
+ locals[__idx].ia[0] = (--sp)->ia[0]; \
+ } \
+ while (0)
+# define STORED(I) \
+ do { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'd'); \
+ DEBUG_LOCALS_INSN (__idx + 1, 'x'); \
+ locals[__idx + 1].ia[0] = (--sp)->ia[0]; \
+ locals[__idx].ia[0] = (--sp)->ia[0]; \
+ } while (0)
#endif
#define PEEKI(I) (locals+(I))->i
#define PEEKA(I) (locals+(I))->o
-#define POKEI(I,V) \
-DEBUG_LOCALS_INSN(I,'i'); \
-((locals+(I))->i = (V))
+#define POKEI(I,V) \
+ do \
+ { \
+ jint __idx = (I); \
+ DEBUG_LOCALS_INSN (__idx, 'i'); \
+ ((locals + __idx)->i = (V)); \
+ } \
+ while (0)
#define BINOPI(OP) { \
@@ -916,18 +957,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
void
_Jv_InterpMethod::run_debug (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
{
-/* Used to keep track of local variable type
- *
- * Possible Types:
- * o object
- * i integer
- * f float
- * l long
- * d double
- */
#define DEBUG
#undef DEBUG_LOCALS_INSN
-#define DEBUG_LOCALS_INSN(s, t) do {} while(0)
+#define DEBUG_LOCALS_INSN(s, t) \
+ do \
+ { \
+ frame_desc.locals_type[s] = t; \
+ } \
+ while (0)
#include "interpret-run.cc"
}
@@ -935,19 +972,25 @@ _Jv_InterpMethod::run_debug (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
static void
throw_internal_error (const char *msg)
{
- throw new java::lang::InternalError (JvNewStringLatin1 (msg));
+ jthrowable t = new java::lang::InternalError (JvNewStringLatin1 (msg));
+ REPORT_EXCEPTION (t);
+ throw t;
}
static void
throw_incompatible_class_change_error (jstring msg)
{
- throw new java::lang::IncompatibleClassChangeError (msg);
+ jthrowable t = new java::lang::IncompatibleClassChangeError (msg);
+ REPORT_EXCEPTION (t);
+ throw t;
}
static void
throw_null_pointer_exception ()
{
- throw new java::lang::NullPointerException;
+ jthrowable t = new java::lang::NullPointerException;
+ REPORT_EXCEPTION (t);
+ throw t;
}
/* Look up source code line number for given bytecode (or direct threaded
@@ -1290,34 +1333,34 @@ _Jv_InterpMethod::ncode (jclass klass)
{
if (staticp)
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
}
else
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
- }
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
+ }
}
else
{
if (staticp)
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
}
else
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
}
}
@@ -1361,6 +1404,51 @@ _Jv_InterpMethod::insn_index (pc_t pc)
return -1;
}
+// Method to check if an exception is caught at some location in a method
+// (meth). Returns true if this method (meth) contains a catch block for the
+// exception (ex). False otherwise. If there is a catch block, it sets the pc
+// to the location of the beginning of the catch block.
+jboolean
+_Jv_InterpMethod::check_handler (pc_t *pc, _Jv_InterpMethod *meth,
+ java::lang::Throwable *ex)
+{
+#ifdef DIRECT_THREADED
+ void *logical_pc = (void *) ((insn_slot *) (*pc) - 1);
+#else
+ int logical_pc = (*pc) - 1 - meth->bytecode ();
+#endif
+ _Jv_InterpException *exc = meth->exceptions ();
+ jclass exc_class = ex->getClass ();
+
+ for (int i = 0; i < meth->exc_count; i++)
+ {
+ if (PCVAL (exc[i].start_pc) <= logical_pc
+ && logical_pc < PCVAL (exc[i].end_pc))
+ {
+#ifdef DIRECT_THREADED
+ jclass handler = (jclass) exc[i].handler_type.p;
+#else
+ jclass handler = NULL;
+ if (exc[i].handler_type.i != 0)
+ handler
+ = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
+ ex$
+#endif /* DIRECT_THREADED */
+ if (handler == NULL || handler->isAssignableFrom (exc_class))
+ {
+#ifdef DIRECT_THREADED
+ (*pc) = (insn_slot *) exc[i].handler_pc.p;
+#else
+ (*pc) = meth->bytecode () + exc[i].handler_pc.i;
+#endif /* DIRECT_THREADED */
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
void
_Jv_InterpMethod::get_line_table (jlong& start, jlong& end,
jintArray& line_numbers,
@@ -1409,6 +1497,30 @@ _Jv_InterpMethod::get_line_table (jlong& start, jlong& end,
#endif // !DIRECT_THREADED
}
+int
+_Jv_InterpMethod::get_local_var_table (char **name, char **sig,
+ char **generic_sig, jlong *startloc,
+ jint *length, jint *slot,
+ int table_slot)
+{
+ if (local_var_table == NULL)
+ return -2;
+ if (table_slot >= local_var_table_len)
+ return -1;
+ else
+ {
+ *name = local_var_table[table_slot].name;
+ *sig = local_var_table[table_slot].descriptor;
+ *generic_sig = local_var_table[table_slot].descriptor;
+
+ *startloc = static_cast<jlong>
+ (local_var_table[table_slot].bytecode_start_pc);
+ *length = static_cast<jint> (local_var_table[table_slot].length);
+ *slot = static_cast<jint> (local_var_table[table_slot].slot);
+ }
+ return local_var_table_len - table_slot -1;
+}
+
pc_t
_Jv_InterpMethod::install_break (jlong index)
{
@@ -1455,6 +1567,23 @@ _Jv_InterpMethod::set_insn (jlong index, pc_t insn)
return &code[index];
}
+bool
+_Jv_InterpMethod::breakpoint_at (jlong index)
+{
+ pc_t insn = get_insn (index);
+ if (insn != NULL)
+ {
+#ifdef DIRECT_THREADED
+ return (insn->insn == breakpoint_insn->insn);
+#else
+ pc_t code = reinterpret_cast<pc_t> (bytecode ());
+ return (code[index] == breakpoint_insn);
+#endif
+ }
+
+ return false;
+}
+
void *
_Jv_JNIMethod::ncode (jclass klass)
{
@@ -1523,9 +1652,11 @@ _Jv_JNIMethod::ncode (jclass klass)
static void
throw_class_format_error (jstring msg)
{
- throw (msg
+ jthrowable t = (msg
? new java::lang::ClassFormatError (msg)
: new java::lang::ClassFormatError);
+ REPORT_EXCEPTION (t);
+ throw t;
}
static void
@@ -1534,6 +1665,70 @@ throw_class_format_error (const char *msg)
throw_class_format_error (JvNewStringLatin1 (msg));
}
+/* This function finds the method and location where the exception EXC
+ is caught in the stack frame. On return, it sets CATCH_METHOD and
+ CATCH_LOCATION with the method and location where the catch will
+ occur. If the exception is not caught, these are set to 0.
+
+ This function should only be used with the DEBUG interpreter. */
+static void
+find_catch_location (::java::lang::Throwable *exc, jthread thread,
+ jmethodID *catch_method, jlong *catch_loc)
+{
+ *catch_method = 0;
+ *catch_loc = 0;
+
+ _Jv_InterpFrame *frame
+ = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
+ while (frame != NULL)
+ {
+ pc_t pc = frame->get_pc ();
+ _Jv_InterpMethod *imeth
+ = reinterpret_cast<_Jv_InterpMethod *> (frame->self);
+ if (imeth->check_handler (&pc, imeth, exc))
+ {
+ // This method handles the exception.
+ *catch_method = imeth->get_method ();
+ *catch_loc = imeth->insn_index (pc);
+ return;
+ }
+
+ frame = frame->next_interp;
+ }
+}
+
+/* This method handles JVMTI notifications of thrown exceptions. It
+ calls find_catch_location to figure out where the exception is
+ caught (if it is caught).
+
+ Like find_catch_location, this should only be called with the
+ DEBUG interpreter. Since a few exceptions occur outside the
+ interpreter proper, it is important to not call this function
+ without checking JVMTI_REQUESTED_EVENT(Exception) first. */
+void
+_Jv_ReportJVMTIExceptionThrow (jthrowable ex)
+{
+ jthread thread = ::java::lang::Thread::currentThread ();
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+ jmethodID throw_meth = frame->self->get_method ();
+ jlocation throw_loc = -1;
+ if (frame->frame_type == frame_interpreter)
+ {
+ _Jv_InterpFrame * iframe
+ = reinterpret_cast<_Jv_InterpFrame *> (frame);
+ _Jv_InterpMethod *imeth
+ = reinterpret_cast<_Jv_InterpMethod *> (frame->self);
+ throw_loc = imeth->insn_index (iframe->get_pc ());
+ }
+
+ jlong catch_loc;
+ jmethodID catch_method;
+ find_catch_location (ex, thread, &catch_method, &catch_loc);
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION, thread,
+ _Jv_GetCurrentJNIEnv (), throw_meth, throw_loc,
+ ex, catch_method, catch_loc);
+}
+
void
@@ -1690,7 +1885,12 @@ void
_Jv_CompileMethod (_Jv_InterpMethod* method)
{
if (method->prepared == NULL)
- _Jv_InterpMethod::run (NULL, NULL, method);
+ {
+ if (JVMTI::enabled)
+ _Jv_InterpMethod::run_debug (NULL, NULL, method);
+ else
+ _Jv_InterpMethod::run (NULL, NULL, method);
+ }
}
#endif // DIRECT_THREADED
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h
index 615c81e4d9c..a1795f7e58c 100644
--- a/libjava/java/lang/Class.h
+++ b/libjava/java/lang/Class.h
@@ -1,6 +1,6 @@
// Class.h - Header file for java.lang.Class. -*- c++ -*-
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -269,8 +269,11 @@ _Jv_Utf8Const *_Jv_GetClassNameUtf8 (jclass);
// Finds a desired interpreter method in the given class or NULL if not found
class _Jv_MethodBase;
_Jv_MethodBase *_Jv_FindInterpreterMethod (jclass, jmethodID);
+jstring _Jv_GetInterpClassSourceFile (jclass);
#endif
+jbyte _Jv_GetClassState (jclass);
+
// Friend classes and functions to implement the ClassLoader
class java::lang::ClassLoader;
class java::lang::VMClassLoader;
@@ -571,7 +574,9 @@ private:
#ifdef INTERPRETER
friend _Jv_MethodBase *(::_Jv_FindInterpreterMethod) (jclass klass,
jmethodID desired_method);
+ friend jstring ::_Jv_GetInterpClassSourceFile (jclass);
#endif
+ friend jbyte (::_Jv_GetClassState) (jclass klass);
// Friends classes and functions to implement the ClassLoader
friend class java::lang::ClassLoader;
diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java
index 02180711fc2..1e1e860cea0 100644
--- a/libjava/java/lang/Thread.java
+++ b/libjava/java/lang/Thread.java
@@ -185,6 +185,9 @@ public class Thread implements Runnable
// This describes the top-most interpreter frame for this thread.
RawData interp_frame;
+
+ // This describes the top most frame in the composite (interp + JNI) stack
+ RawData frame;
// Current state.
volatile int state;
diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc
index f96287d4fee..7bad53d6203 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -1,6 +1,6 @@
// natClass.cc - Implementation of java.lang.Class native methods.
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation
This file is part of libgcj.
@@ -2079,3 +2079,21 @@ _Jv_GetMethodDeclaringClass (jmethodID method)
return reinterpret_cast<jclass> (_Jv_StackTrace::ncodeMap->get (obj));
}
+jbyte
+_Jv_GetClassState (jclass klass)
+{
+ return klass->state;
+}
+
+jstring
+_Jv_GetInterpClassSourceFile (jclass klass)
+{
+ if (_Jv_IsInterpretedClass (klass))
+ {
+ _Jv_InterpClass *iclass =
+ reinterpret_cast<_Jv_InterpClass *> (klass->aux_info);
+ return iclass->source_file_name;
+ }
+
+ return NULL;
+}
diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc
index 564ed90d55a..42f18c4eb3a 100644
--- a/libjava/java/lang/natThread.cc
+++ b/libjava/java/lang/natThread.cc
@@ -27,6 +27,8 @@ details. */
#include <java/lang/NullPointerException.h>
#include <jni.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
@@ -215,6 +217,9 @@ java::lang::Thread::finish_ ()
nt->park_helper.deactivate ();
group->removeThread (this);
+ if (JVMTI_REQUESTED_EVENT (ThreadEnd))
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, this, nt->jni_env);
+
#ifdef ENABLE_JVMPI
if (_Jv_JVMPI_Notify_THREAD_END)
{
@@ -253,6 +258,12 @@ java::lang::Thread::finish_ ()
static void
_Jv_NotifyThreadStart (java::lang::Thread* thread)
{
+ if (JVMTI_REQUESTED_EVENT (ThreadStart))
+ {
+ natThread *nt = reinterpret_cast<natThread *> (thread->data);
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_START, thread, nt->jni_env);
+ }
+
#ifdef ENABLE_JVMPI
if (_Jv_JVMPI_Notify_THREAD_START)
{
diff --git a/libjava/jni.cc b/libjava/jni.cc
index 4bd56c9b0e8..efe88991b9d 100644
--- a/libjava/jni.cc
+++ b/libjava/jni.cc
@@ -1,6 +1,6 @@
// jni.cc - JNI implementation, including the jump table.
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation
This file is part of libgcj.
@@ -23,6 +23,7 @@ details. */
#include <jvmpi.h>
#endif
#include <jvmti.h>
+#include "jvmti-int.h"
#include <java/lang/Class.h>
#include <java/lang/ClassLoader.h>
@@ -456,6 +457,8 @@ _Jv_JNI_PopSystemFrame (JNIEnv *env)
{
jthrowable t = env->ex;
env->ex = NULL;
+ if (JVMTI_REQUESTED_EVENT (Exception))
+ _Jv_ReportJVMTIExceptionThrow (t);
throw t;
}
}
diff --git a/libjava/jvmti.cc b/libjava/jvmti.cc
index b9646b7d101..d9bcc806074 100644
--- a/libjava/jvmti.cc
+++ b/libjava/jvmti.cc
@@ -1,6 +1,6 @@
// jvmti.cc - JVMTI implementation
-/* Copyright (C) 2006 Free Software Foundation
+/* Copyright (C) 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -27,16 +27,18 @@ details. */
#include <java/lang/Class.h>
#include <java/lang/ClassLoader.h>
-#include <java/lang/Object.h>
#include <java/lang/OutOfMemoryError.h>
#include <java/lang/Thread.h>
#include <java/lang/ThreadGroup.h>
+#include <java/lang/Thread$State.h>
#include <java/lang/Throwable.h>
#include <java/lang/VMClassLoader.h>
#include <java/lang/reflect/Field.h>
#include <java/lang/reflect/Modifier.h>
#include <java/util/Collection.h>
#include <java/util/HashMap.h>
+#include <java/util/concurrent/locks/Lock.h>
+#include <java/util/concurrent/locks/ReentrantReadWriteLock.h>
#include <java/net/URL.h>
static void check_enabled_events (void);
@@ -44,6 +46,10 @@ static void check_enabled_event (jvmtiEvent);
namespace JVMTI
{
+ // Is JVMTI enabled? (i.e., any jvmtiEnv created?)
+ bool enabled;
+
+ // Event notifications
bool VMInit = false;
bool VMDeath = false;
bool ThreadStart = false;
@@ -99,7 +105,8 @@ struct jvmti_env_list
struct jvmti_env_list *next;
};
static struct jvmti_env_list *_jvmtiEnvironments = NULL;
-static java::lang::Object *_envListLock = NULL;
+static java::util::concurrent::locks::
+ReentrantReadWriteLock *_envListLock = NULL;
#define FOREACH_ENVIRONMENT(Ele) \
for (Ele = _jvmtiEnvironments; Ele != NULL; Ele = Ele->next)
@@ -149,18 +156,28 @@ static java::lang::Object *_envListLock = NULL;
} \
while (0)
+#define CHECK_FOR_NATIVE_METHOD(AjmethodID) \
+ do \
+ { \
+ jboolean is_native; \
+ jvmtiError jerr = env->IsMethodNative (AjmethodID, &is_native); \
+ if (jerr != JVMTI_ERROR_NONE) \
+ return jerr; \
+ if (is_native) \
+ return JVMTI_ERROR_NATIVE_METHOD; \
+ } \
+ while (0)
+
static jvmtiError JNICALL
_Jv_JVMTI_SuspendThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
{
using namespace java::lang;
THREAD_DEFAULT_TO_CURRENT (thread);
-
- Thread *t = reinterpret_cast<Thread *> (thread);
- THREAD_CHECK_VALID (t);
- THREAD_CHECK_IS_ALIVE (t);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
- _Jv_Thread_t *data = _Jv_ThreadGetData (t);
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
_Jv_SuspendThread (data);
return JVMTI_ERROR_NONE;
}
@@ -171,12 +188,10 @@ _Jv_JVMTI_ResumeThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
using namespace java::lang;
THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
- Thread *t = reinterpret_cast<Thread *> (thread);
- THREAD_CHECK_VALID (t);
- THREAD_CHECK_IS_ALIVE (t);
-
- _Jv_Thread_t *data = _Jv_ThreadGetData (t);
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
_Jv_ResumeThread (data);
return JVMTI_ERROR_NONE;
}
@@ -191,14 +206,260 @@ _Jv_JVMTI_InterruptThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
if (thread == NULL)
return JVMTI_ERROR_INVALID_THREAD;
- Thread *real_thread = reinterpret_cast<Thread *> (thread);
- THREAD_CHECK_VALID (real_thread);
- THREAD_CHECK_IS_ALIVE (real_thread);
- real_thread->interrupt();
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+ thread->interrupt();
+ return JVMTI_ERROR_NONE;
+}
+
+// This method performs the common tasks to get and set variables of all types.
+// It is called by the _Jv_JVMTI_Get/SetLocalInt/Object/.... methods.
+static jvmtiError
+getLocalFrame (jvmtiEnv *env, jthread thread, jint depth, jint slot, char type,
+ _Jv_InterpFrame **iframe)
+{
+ using namespace java::lang;
+
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ ILLEGAL_ARGUMENT (depth < 0);
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+
+ for (int i = 0; i < depth; i++)
+ {
+ frame = frame->next;
+
+ if (frame == NULL)
+ return JVMTI_ERROR_NO_MORE_FRAMES;
+ }
+
+ if (frame->frame_type == frame_native)
+ return JVMTI_ERROR_OPAQUE_FRAME;
+
+ jint max_locals;
+ jvmtiError jerr = env->GetMaxLocals (reinterpret_cast<jmethodID>
+ (frame->self->get_method ()),
+ &max_locals);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpFrame *tmp_iframe = reinterpret_cast<_Jv_InterpFrame *> (frame);
+
+ // The second slot taken up by a long type is marked as type 'x' meaning it
+ // is not valid for access since it holds only the 4 low bytes of the value.
+ if (tmp_iframe->locals_type[slot] == 'x')
+ return JVMTI_ERROR_INVALID_SLOT;
+
+ if (tmp_iframe->locals_type[slot] != type)
+ return JVMTI_ERROR_TYPE_MISMATCH;
+
+ // Check for invalid slots, if the type is a long type, we must check that
+ // the next slot is valid as well.
+ if (slot < 0 || slot >= max_locals
+ || ((type == 'l' || type == 'd') && slot + 1 >= max_locals))
+ return JVMTI_ERROR_INVALID_SLOT;
+
+ *iframe = tmp_iframe;
+
return JVMTI_ERROR_NONE;
}
-jvmtiError
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jobject *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].o;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jobject value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].o = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jint *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].i;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jint value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].i = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jlong *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ *value = frame->locals[slot].l;
+#else
+ _Jv_word2 val;
+ val.ia[0] = frame->locals[slot].ia[0];
+ val.ia[1] = frame->locals[slot + 1].ia[0];
+ *value = val.l;
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jlong value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ frame->locals[slot].l = value;
+#else
+ _Jv_word2 val;
+ val.l = value;
+ frame->locals[slot].ia[0] = val.ia[0];
+ frame->locals[slot + 1].ia[0] = val.ia[1];
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jfloat *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].f;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jfloat value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].f = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jdouble *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ *value = frame->locals[slot].d;
+#else
+ _Jv_word2 val;
+ val.ia[0] = frame->locals[slot].ia[0];
+ val.ia[1] = frame->locals[slot + 1].ia[0];
+ *value = val.d;
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jdouble value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ frame->locals[slot].d = value;
+#else
+ _Jv_word2 val;
+ val.d = value;
+ frame->locals[slot].ia[0] = val.ia[0];
+ frame->locals[slot + 1].ia[0] = val.ia[1];
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt,
jthread **threads)
{
@@ -207,7 +468,6 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt,
NULL_CHECK (threads);
using namespace java::lang;
- Thread *thr = Thread::currentThread ();
ThreadGroup *root_grp = ThreadGroup::root;
jint estimate = root_grp->activeCount ();
@@ -217,10 +477,9 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt,
// Allocate some extra space since threads can be created between calls
try
{
- thr_arr
- = reinterpret_cast<JArray<Thread *> *> (JvNewObjectArray
- ((estimate * 2),
- &Thread::class$, NULL));
+ thr_arr = reinterpret_cast<JArray<Thread *> *> (JvNewObjectArray
+ ((estimate * 2),
+ &Thread::class$, NULL));
}
catch (java::lang::OutOfMemoryError *err)
{
@@ -244,6 +503,85 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt,
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetFrameCount (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint *frame_count)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ NULL_CHECK (frame_count);
+
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+ (*frame_count) = frame->depth ();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetThreadState (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint *thread_state_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ NULL_CHECK (thread_state_ptr);
+
+ jint state = 0;
+ if (thread->isAlive ())
+ {
+ state |= JVMTI_THREAD_STATE_ALIVE;
+
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
+ if (_Jv_IsThreadSuspended (data))
+ state |= JVMTI_THREAD_STATE_SUSPENDED;
+
+ if (thread->isInterrupted ())
+ state |= JVMTI_THREAD_STATE_INTERRUPTED;
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+ if (frame != NULL && frame->frame_type == frame_native)
+ state |= JVMTI_THREAD_STATE_IN_NATIVE;
+
+ using namespace java::lang;
+ Thread$State *ts = thread->getState ();
+ if (ts == Thread$State::RUNNABLE)
+ state |= JVMTI_THREAD_STATE_RUNNABLE;
+ else if (ts == Thread$State::BLOCKED)
+ state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
+ else if (ts == Thread$State::TIMED_WAITING
+ || ts == Thread$State::WAITING)
+ {
+ state |= JVMTI_THREAD_STATE_WAITING;
+ state |= ((ts == Thread$State::WAITING)
+ ? JVMTI_THREAD_STATE_WAITING_INDEFINITELY
+ : JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT);
+
+ /* FIXME: We don't have a way to tell
+ the caller why the thread is suspended,
+ i.e., JVMTI_THREAD_STATE_SLEEPING,
+ JVMTI_THREAD_STATE_PARKED, and
+ JVMTI_THREAD_STATE_IN_OBJECT_WAIT
+ are never set. */
+ }
+ }
+ else
+ {
+ using namespace java::lang;
+ Thread$State *ts = thread->getState ();
+ if (ts == Thread$State::TERMINATED)
+ state |= JVMTI_THREAD_STATE_TERMINATED;
+ }
+
+ *thread_state_ptr = state;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_CreateRawMonitor (MAYBE_UNUSED jvmtiEnv *env, const char *name,
jrawMonitorID *result)
{
@@ -422,6 +760,36 @@ _Jv_JVMTI_Deallocate (MAYBE_UNUSED jvmtiEnv *env, unsigned char *mem)
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetClassStatus (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jint *status_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (status_ptr);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+
+ if (klass->isArray ())
+ *status_ptr = JVMTI_CLASS_STATUS_ARRAY;
+ else if (klass->isPrimitive ())
+ *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
+ else
+ {
+ jbyte state = _Jv_GetClassState (klass);
+ *status_ptr = 0;
+ if (state >= JV_STATE_LINKED)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_VERIFIED;
+ if (state >= JV_STATE_PREPARED)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_PREPARED;
+ if (state == JV_STATE_ERROR || state == JV_STATE_PHANTOM)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_ERROR;
+ else if (state == JV_STATE_DONE)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_INITIALIZED;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_GetClassModifiers (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
jint *mods)
{
@@ -540,6 +908,48 @@ _Jv_JVMTI_IsFieldSynthetic (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetMethodName (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ char **name_ptr, char **signature_ptr,
+ char **generic_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+
+ if (method == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ if (name_ptr != NULL)
+ {
+ int len = static_cast<int> (method->name->len ());
+ *name_ptr = (char *) _Jv_MallocUnchecked (len + 1);
+ if (*name_ptr == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ strncpy (*name_ptr, method->name->chars (), len);
+ (*name_ptr)[len] = '\0';
+ }
+
+ if (signature_ptr != NULL)
+ {
+ int len = static_cast<int> (method->signature->len ());
+ *signature_ptr = (char *) _Jv_MallocUnchecked (len + 1);
+ if (*signature_ptr == NULL)
+ {
+ if (name_ptr != NULL)
+ _Jv_Free (*name_ptr);
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy (*signature_ptr, method->signature->chars (), len);
+ (*signature_ptr)[len] = '\0';
+ }
+
+ if (generic_ptr != NULL)
+ {
+ *generic_ptr = NULL;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_GetMethodModifiers (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
jint *result)
{
@@ -602,6 +1012,88 @@ _Jv_JVMTI_GetLineNumberTable (jvmtiEnv *env, jmethodID method,
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalVariableTable (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jint *num_locals,
+ jvmtiLocalVariableEntry **locals)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ NULL_CHECK (num_locals);
+ NULL_CHECK (locals);
+
+ CHECK_FOR_NATIVE_METHOD(method);
+
+ jclass klass;
+ jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *>
+ (_Jv_FindInterpreterMethod (klass, method));
+
+ if (imeth == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ jerr = env->GetMaxLocals (method, num_locals);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ jerr = env->Allocate (static_cast<jlong>
+ ((*num_locals) * sizeof (jvmtiLocalVariableEntry)),
+ reinterpret_cast<unsigned char **> (locals));
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ //the slot in the methods local_var_table to get
+ int table_slot = 0;
+ char *name;
+ char *sig;
+ char *generic_sig;
+
+ while (table_slot < *num_locals
+ && imeth->get_local_var_table (&name, &sig, &generic_sig,
+ &((((*locals)[table_slot].start_location))),
+ &((*locals)[table_slot].length),
+ &((*locals)[table_slot].slot),
+ table_slot)
+ >= 0)
+ {
+ char **str_ptr = &(*locals)[table_slot].name;
+ jerr = env->Allocate (static_cast<jlong> (strlen (name) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].name, name);
+
+ str_ptr = &(*locals)[table_slot].signature;
+ jerr = env->Allocate (static_cast<jlong> (strlen (sig) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].signature, sig);
+
+ str_ptr = &(*locals)[table_slot].generic_signature;
+ jerr = env->Allocate (static_cast<jlong> (strlen (generic_sig) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].generic_signature, generic_sig);
+
+ table_slot++;
+ }
+
+ if (table_slot == 0)
+ return JVMTI_ERROR_ABSENT_INFORMATION;
+
+ // If there are double or long variables in the table, the the table will be
+ // smaller than the max number of slots, so correct for this here.
+ if ((table_slot) < *num_locals)
+ *num_locals = table_slot;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_IsMethodNative (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
jboolean *result)
{
@@ -631,6 +1123,75 @@ _Jv_JVMTI_IsMethodSynthetic (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetMaxLocals (jvmtiEnv *env, jmethodID method, jint *max_locals)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (max_locals);
+
+ CHECK_FOR_NATIVE_METHOD (method);
+
+ jclass klass;
+ jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *>
+ (_Jv_FindInterpreterMethod (klass, method));
+
+ if (imeth == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ *max_locals = imeth->get_max_locals ();
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetArgumentsSize (jvmtiEnv *env, jmethodID method, jint *size)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (size);
+
+ CHECK_FOR_NATIVE_METHOD (method);
+
+ jvmtiError jerr;
+ char *sig;
+ jint num_slots = 0;
+
+ jerr = env->GetMethodName (method, NULL, &sig, NULL);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ // If the method is non-static add a slot for the "this" pointer.
+ if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0)
+ num_slots++;
+
+ for (int i = 0; sig[i] != ')'; i++)
+ {
+ if (sig[i] == 'Z' || sig[i] == 'B' || sig[i] == 'C' || sig[i] == 'S'
+ || sig[i] == 'I' || sig[i] == 'F')
+ num_slots++;
+ else if (sig[i] == 'J' || sig[i] == 'D')
+ {
+ // If this is an array of wide types it uses a single slot
+ if (i > 0 && sig[i - 1] == '[')
+ num_slots++;
+ else
+ num_slots += 2;
+ }
+ else if (sig[i] == 'L')
+ {
+ num_slots++;
+ while (sig[i] != ';')
+ i++;
+ }
+ }
+
+ *size = num_slots;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_GetMethodDeclaringClass (MAYBE_UNUSED jvmtiEnv *env,
jmethodID method,
jclass *declaring_class_ptr)
@@ -683,6 +1244,80 @@ _Jv_JVMTI_GetClassLoaderClasses (MAYBE_UNUSED jvmtiEnv *env,
}
static jvmtiError JNICALL
+_Jv_JVMTI_GetStackTrace (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint start_depth, jint max_frames,
+ jvmtiFrameInfo *frames, jint *frame_count)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ ILLEGAL_ARGUMENT (max_frames < 0);
+
+ NULL_CHECK (frames);
+ NULL_CHECK (frame_count);
+
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ jvmtiError jerr = env->GetFrameCount (thread, frame_count);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ // start_depth can be either a positive number, indicating the depth of the
+ // stack at which to begin the trace, or a negative number indicating the
+ // number of frames at the bottom of the stack to exclude. These checks
+ // ensure that it is a valid value in either case
+
+ ILLEGAL_ARGUMENT (start_depth >= (*frame_count));
+ ILLEGAL_ARGUMENT (start_depth < (-(*frame_count)));
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+
+ // If start_depth is negative use this to determine at what depth to start
+ // the trace by adding it to the length of the call stack. This allows the
+ // use of the same frame "discarding" mechanism as for a positive start_depth
+ if (start_depth < 0)
+ start_depth = *frame_count + start_depth;
+
+ // If start_depth > 0 "remove" start_depth frames from the beginning
+ // of the stack before beginning the trace by moving along the frame list.
+ while (start_depth > 0)
+ {
+ frame = frame->next;
+ start_depth--;
+ (*frame_count)--;
+ }
+
+ // Now check to see if the array supplied by the agent is large enough to
+ // hold frame_count frames, after adjustment for start_depth.
+ if ((*frame_count) > max_frames)
+ (*frame_count) = max_frames;
+
+ for (int i = 0; i < (*frame_count); i++)
+ {
+ frames[i].method = frame->self->get_method ();
+
+ // Set the location in the frame, native frames have location = -1
+ if (frame->frame_type == frame_interpreter)
+ {
+ _Jv_InterpMethod *imeth
+ = static_cast<_Jv_InterpMethod *> (frame->self);
+ _Jv_InterpFrame *interp_frame
+ = static_cast<_Jv_InterpFrame *> (frame);
+ frames[i].location = imeth->insn_index (interp_frame->get_pc ());
+ }
+ else
+ frames[i].location = -1;
+
+ frame = frame->next;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
_Jv_JVMTI_ForceGarbageCollection (MAYBE_UNUSED jvmtiEnv *env)
{
REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
@@ -723,7 +1358,7 @@ _Jv_JVMTI_DisposeEnvironment (jvmtiEnv *env)
return JVMTI_ERROR_INVALID_ENVIRONMENT;
else
{
- JvSynchronize dummy (_envListLock);
+ _envListLock->writeLock ()->lock ();
if (_jvmtiEnvironments->env == env)
{
struct jvmti_env_list *next = _jvmtiEnvironments->next;
@@ -736,12 +1371,16 @@ _Jv_JVMTI_DisposeEnvironment (jvmtiEnv *env)
while (e->next != NULL && e->next->env != env)
e = e->next;
if (e->next == NULL)
- return JVMTI_ERROR_INVALID_ENVIRONMENT;
+ {
+ _envListLock->writeLock ()->unlock ();
+ return JVMTI_ERROR_INVALID_ENVIRONMENT;
+ }
struct jvmti_env_list *next = e->next->next;
_Jv_Free (e->next);
e->next = next;
}
+ _envListLock->writeLock ()->unlock ();
}
_Jv_Free (env);
@@ -1042,18 +1681,24 @@ check_enabled_event (jvmtiEvent type)
int index = EVENT_INDEX (type); // safe since caller checks this
- JvSynchronize dummy (_envListLock);
- struct jvmti_env_list *e;
- FOREACH_ENVIRONMENT (e)
+ if (_jvmtiEnvironments != NULL)
{
- char *addr
- = reinterpret_cast<char *> (&e->env->callbacks) + offset;
- void **callback = reinterpret_cast<void **> (addr);
- if (e->env->enabled[index] && *callback != NULL)
+ _envListLock->readLock ()->lock ();
+ struct jvmti_env_list *e;
+ FOREACH_ENVIRONMENT (e)
{
- *enabled = true;
- return;
+ char *addr
+ = reinterpret_cast<char *> (&e->env->callbacks) + offset;
+ void **callback = reinterpret_cast<void **> (addr);
+ if (e->env->enabled[index] && *callback != NULL)
+ {
+ *enabled = true;
+ _envListLock->readLock ()->unlock ();
+ return;
+ }
}
+
+ _envListLock->readLock ()->unlock ();
}
*enabled = false;
@@ -1102,10 +1747,8 @@ _Jv_JVMTI_SetEventNotificationMode (jvmtiEnv *env, jvmtiEventMode mode,
if (event_thread != NULL)
{
- using namespace java::lang;
- Thread *t = reinterpret_cast<Thread *> (event_thread);
- THREAD_CHECK_VALID (t);
- THREAD_CHECK_IS_ALIVE (t);
+ THREAD_CHECK_VALID (event_thread);
+ THREAD_CHECK_IS_ALIVE (event_thread);
}
bool enabled;
@@ -1421,21 +2064,21 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
UNIMPLEMENTED, // GetTopThreadGroups
UNIMPLEMENTED, // GetThreadGroupInfo
UNIMPLEMENTED, // GetThreadGroupChildren
- UNIMPLEMENTED, // GetFrameCount
- UNIMPLEMENTED, // GetThreadState
+ _Jv_JVMTI_GetFrameCount, // GetFrameCount
+ _Jv_JVMTI_GetThreadState, // GetThreadState
RESERVED, // reserved18
UNIMPLEMENTED, // GetFrameLocation
UNIMPLEMENTED, // NotifyPopFrame
- UNIMPLEMENTED, // GetLocalObject
- UNIMPLEMENTED, // GetLocalInt
- UNIMPLEMENTED, // GetLocalLong
- UNIMPLEMENTED, // GetLocalFloat
- UNIMPLEMENTED, // GetLocalDouble
- UNIMPLEMENTED, // SetLocalObject
- UNIMPLEMENTED, // SetLocalInt
- UNIMPLEMENTED, // SetLocalLong
- UNIMPLEMENTED, // SetLocalFloat
- UNIMPLEMENTED, // SetLocalDouble
+ _Jv_JVMTI_GetLocalObject, // GetLocalObject
+ _Jv_JVMTI_GetLocalInt, // GetLocalInt
+ _Jv_JVMTI_GetLocalLong, // GetLocalLong
+ _Jv_JVMTI_GetLocalFloat, // GetLocalFloat
+ _Jv_JVMTI_GetLocalDouble, // GetLocalDouble
+ _Jv_JVMTI_SetLocalObject, // SetLocalObject
+ _Jv_JVMTI_SetLocalInt, // SetLocalInt
+ _Jv_JVMTI_SetLocalLong, // SetLocalLong
+ _Jv_JVMTI_SetLocalFloat, // SetLocalFloat
+ _Jv_JVMTI_SetLocalDouble, // SetLocalDouble
_Jv_JVMTI_CreateRawMonitor, // CreateRawMonitor
_Jv_JVMTI_DestroyRawMonitor, // DestroyRawMonitor
_Jv_JVMTI_RawMonitorEnter, // RawMonitorEnter
@@ -1454,7 +2097,7 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
_Jv_JVMTI_Allocate, // Allocate
_Jv_JVMTI_Deallocate, // Deallocate
UNIMPLEMENTED, // GetClassSignature
- UNIMPLEMENTED, // GetClassStatus
+ _Jv_JVMTI_GetClassStatus, // GetClassStatus
UNIMPLEMENTED, // GetSourceFileName
_Jv_JVMTI_GetClassModifiers, // GetClassModifiers
_Jv_JVMTI_GetClassMethods, // GetClassMethods
@@ -1469,15 +2112,15 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
UNIMPLEMENTED, // GetFieldDeclaringClass
_Jv_JVMTI_GetFieldModifiers, // GetFieldModifiers
_Jv_JVMTI_IsFieldSynthetic, // IsFieldSynthetic
- UNIMPLEMENTED, // GetMethodName
+ _Jv_JVMTI_GetMethodName, // GetMethodName
_Jv_JVMTI_GetMethodDeclaringClass, // GetMethodDeclaringClass
_Jv_JVMTI_GetMethodModifiers, // GetMethodModifers
RESERVED, // reserved67
- UNIMPLEMENTED, // GetMaxLocals
- UNIMPLEMENTED, // GetArgumentsSize
+ _Jv_JVMTI_GetMaxLocals, // GetMaxLocals
+ _Jv_JVMTI_GetArgumentsSize, // GetArgumentsSize
_Jv_JVMTI_GetLineNumberTable, // GetLineNumberTable
UNIMPLEMENTED, // GetMethodLocation
- UNIMPLEMENTED, // GetLocalVariableTable
+ _Jv_JVMTI_GetLocalVariableTable, // GetLocalVariableTable
RESERVED, // reserved73
RESERVED, // reserved74
UNIMPLEMENTED, // GetBytecodes
@@ -1509,7 +2152,7 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
UNIMPLEMENTED, // GetThreadListStackTraces
UNIMPLEMENTED, // GetThreadLocalStorage
UNIMPLEMENTED, // SetThreadLocalStorage
- UNIMPLEMENTED, // GetStackTrace
+ _Jv_JVMTI_GetStackTrace, // GetStackTrace
RESERVED, // reserved105
UNIMPLEMENTED, // GetTag
UNIMPLEMENTED, // SetTag
@@ -1568,25 +2211,27 @@ _Jv_GetJVMTIEnv (void)
_Jv_JVMTIEnv *env
= (_Jv_JVMTIEnv *) _Jv_MallocUnchecked (sizeof (_Jv_JVMTIEnv));
env->p = &_Jv_JVMTI_Interface;
+ struct jvmti_env_list *element
+ = (struct jvmti_env_list *) _Jv_MallocUnchecked (sizeof (struct jvmti_env_list));
+ element->env = env;
+ element->next = NULL;
- {
- JvSynchronize dummy (_envListLock);
- struct jvmti_env_list *element
- = (struct jvmti_env_list *) _Jv_MallocUnchecked (sizeof (struct jvmti_env_list));
- element->env = env;
- element->next = NULL;
-
- if (_jvmtiEnvironments == NULL)
- _jvmtiEnvironments = element;
- else
- {
- struct jvmti_env_list *e;
- for (e = _jvmtiEnvironments; e->next != NULL; e = e->next)
- ;
- e->next = element;
- }
- }
+ _envListLock->writeLock ()->lock ();
+ if (_jvmtiEnvironments == NULL)
+ _jvmtiEnvironments = element;
+ else
+ {
+ struct jvmti_env_list *e;
+ for (e = _jvmtiEnvironments; e->next != NULL; e = e->next)
+ ;
+ e->next = element;
+ }
+ _envListLock->writeLock ()->unlock ();
+ /* Mark JVMTI active. This is used to force the interpreter
+ to use either debugging or non-debugging code. Once JVMTI
+ has been enabled, the non-debug interpreter cannot be used. */
+ JVMTI::enabled = true;
return env;
}
@@ -1594,7 +2239,8 @@ void
_Jv_JVMTI_Init ()
{
_jvmtiEnvironments = NULL;
- _envListLock = new java::lang::Object ();
+ _envListLock
+ = new java::util::concurrent::locks::ReentrantReadWriteLock ();
// No environments, so this should set all JVMTI:: members to false
check_enabled_events ();
@@ -1958,7 +2604,7 @@ _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...)
va_list args;
va_start (args, event_thread);
- JvSynchronize dummy (_envListLock);
+ _envListLock->readLock ()->lock ();
struct jvmti_env_list *e;
FOREACH_ENVIRONMENT (e)
{
@@ -1974,6 +2620,6 @@ _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...)
post_event (e->env, type, event_thread, args);
}
}
-
+ _envListLock->readLock ()->unlock ();
va_end (args);
}
diff --git a/libjava/link.cc b/libjava/link.cc
index cfcbaf9e31a..1507b01310b 100644
--- a/libjava/link.cc
+++ b/libjava/link.cc
@@ -33,6 +33,8 @@ details. */
#include <limits.h>
#include <java-cpool.h>
#include <execution.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
#include <java/lang/Class.h>
#include <java/lang/String.h>
#include <java/lang/StringBuffer.h>
@@ -1982,33 +1984,35 @@ _Jv_Linker::wait_for_state (jclass klass, int state)
if (klass->state >= state)
return;
- JvSynchronize sync (klass);
-
- // This is similar to the strategy for class initialization. If we
- // already hold the lock, just leave.
java::lang::Thread *self = java::lang::Thread::currentThread();
- while (klass->state <= state
- && klass->thread
- && klass->thread != self)
- klass->wait ();
- java::lang::Thread *save = klass->thread;
- klass->thread = self;
+ {
+ JvSynchronize sync (klass);
- // Allocate memory for static fields and constants.
- if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
- {
- jsize count = klass->field_count;
- if (count)
- {
- _Jv_Field* fields
- = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
- memcpy ((void*)fields,
- (void*)klass->fields,
- count * sizeof (_Jv_Field));
- klass->fields = fields;
- }
- }
+ // This is similar to the strategy for class initialization. If we
+ // already hold the lock, just leave.
+ while (klass->state <= state
+ && klass->thread
+ && klass->thread != self)
+ klass->wait ();
+
+ java::lang::Thread *save = klass->thread;
+ klass->thread = self;
+
+ // Allocate memory for static fields and constants.
+ if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
+ {
+ jsize count = klass->field_count;
+ if (count)
+ {
+ _Jv_Field* fields
+ = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
+ memcpy ((void*)fields,
+ (void*)klass->fields,
+ count * sizeof (_Jv_Field));
+ klass->fields = fields;
+ }
+ }
// Print some debugging info if requested. Interpreted classes are
// handled in defineclass, so we only need to handle the two
@@ -2022,49 +2026,59 @@ _Jv_Linker::wait_for_state (jclass klass, int state)
++gcj::loadedClasses;
}
- try
- {
- if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
- {
- ensure_supers_installed (klass);
- klass->set_state(JV_STATE_LOADING);
- }
+ try
+ {
+ if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
+ {
+ ensure_supers_installed (klass);
+ klass->set_state(JV_STATE_LOADING);
+ }
- if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
- {
- ensure_method_table_complete (klass);
- klass->set_state(JV_STATE_LOADED);
- }
+ if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
+ {
+ ensure_method_table_complete (klass);
+ klass->set_state(JV_STATE_LOADED);
+ }
- if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
- {
- ensure_fields_laid_out (klass);
- make_vtable (klass);
- layout_interface_methods (klass);
- prepare_constant_time_tables (klass);
- klass->set_state(JV_STATE_PREPARED);
- }
+ if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
+ {
+ ensure_fields_laid_out (klass);
+ make_vtable (klass);
+ layout_interface_methods (klass);
+ prepare_constant_time_tables (klass);
+ klass->set_state(JV_STATE_PREPARED);
+ }
- if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
- {
- if (gcj::verifyClasses)
- verify_class (klass);
+ if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
+ {
+ if (gcj::verifyClasses)
+ verify_class (klass);
- ensure_class_linked (klass);
- link_exception_table (klass);
- link_symbol_table (klass);
- klass->set_state(JV_STATE_LINKED);
- }
- }
- catch (java::lang::Throwable *exc)
- {
- klass->thread = save;
- klass->set_state(JV_STATE_ERROR);
- throw exc;
- }
+ ensure_class_linked (klass);
+ link_exception_table (klass);
+ link_symbol_table (klass);
+ klass->set_state(JV_STATE_LINKED);
+ }
+ }
+ catch (java::lang::Throwable *exc)
+ {
+ klass->thread = save;
+ klass->set_state(JV_STATE_ERROR);
+ throw exc;
+ }
+
+ klass->thread = save;
- klass->thread = save;
+ if (klass->state == JV_STATE_ERROR)
+ throw new java::lang::LinkageError;
+ }
- if (klass->state == JV_STATE_ERROR)
- throw new java::lang::LinkageError;
+ if (__builtin_expect (klass->state == JV_STATE_LINKED, false)
+ && state >= JV_STATE_LINKED
+ && JVMTI_REQUESTED_EVENT (ClassPrepare))
+ {
+ JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_PREPARE, self, jni_env,
+ klass);
+ }
}
diff --git a/libjava/nogc.cc b/libjava/nogc.cc
index 126e4de5c2b..079422d0911 100644
--- a/libjava/nogc.cc
+++ b/libjava/nogc.cc
@@ -184,3 +184,9 @@ void
_Jv_ResumeThread (_Jv_Thread_t *thread)
{
}
+
+int
+_Jv_IsThreadSuspended (_Jv_Thread_t *thread)
+{
+ return 0;
+}
diff --git a/libjava/prims.cc b/libjava/prims.cc
index 4f8df34a3ab..bc85bdc2b13 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -1,6 +1,6 @@
// prims.cc - Code for core of runtime environment.
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -32,6 +32,9 @@ details. */
#include <java/lang/ThreadGroup.h>
#endif
+#include <jvmti.h>
+#include "jvmti-int.h"
+
#ifndef DISABLE_GETENV_PROPERTIES
#include <ctype.h>
#include <java-props.h>
@@ -66,8 +69,6 @@ details. */
#include <execution.h>
#include <gnu/classpath/jdwp/Jdwp.h>
#include <gnu/classpath/jdwp/VMVirtualMachine.h>
-#include <gnu/classpath/jdwp/event/VmDeathEvent.h>
-#include <gnu/classpath/jdwp/event/VmInitEvent.h>
#include <gnu/java/lang/MainThread.h>
#ifdef USE_LTDL
@@ -107,6 +108,16 @@ static bool remoteDebug = false;
static char defaultJdwpOptions[] = "";
static char *jdwpOptions = defaultJdwpOptions;
+// Typedefs for JVMTI agent functions.
+typedef jint jvmti_agent_onload_func (JavaVM *vm, char *options,
+ void *reserved);
+typedef jint jvmti_agent_onunload_func (JavaVM *vm);
+
+// JVMTI agent function pointers.
+static jvmti_agent_onload_func *jvmti_agentonload = NULL;
+static jvmti_agent_onunload_func *jvmti_agentonunload = NULL;
+static char *jvmti_agent_opts;
+
// Argument support.
int
_Jv_GetNbArgs (void)
@@ -1357,6 +1368,62 @@ parse_verbose_args (char* option_string,
return 0;
}
+// This function loads the agent functions for JVMTI from the library indicated
+// by name. It returns a negative value on failure, the value of which
+// indicates where ltdl failed, it also prints an error message.
+static jint
+load_jvmti_agent (const char *name)
+{
+#ifdef USE_LTDL
+ if (lt_dlinit ())
+ {
+ fprintf (stderr,
+ "libgcj: Error in ltdl init while loading agent library.\n");
+ return -1;
+ }
+
+ lt_dlhandle lib = lt_dlopenext (name);
+ if (!lib)
+ {
+ fprintf (stderr,
+ "libgcj: Error opening agent library.\n");
+ return -2;
+ }
+
+ if (lib)
+ {
+ jvmti_agentonload
+ = (jvmti_agent_onload_func *) lt_dlsym (lib, "Agent_OnLoad");
+
+ if (!jvmti_agentonload)
+ {
+ fprintf (stderr,
+ "libgcj: Error finding agent function in library %s.\n",
+ name);
+ lt_dlclose (lib);
+ lib = NULL;
+ return -4;
+ }
+ else
+ {
+ jvmti_agentonunload
+ = (jvmti_agent_onunload_func *) lt_dlsym (lib, "Agent_OnUnload");
+
+ return 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "libgcj: Library %s not found in library path.\n", name);
+ return -3;
+ }
+
+#endif /* USE_LTDL */
+
+ // If LTDL cannot be used, return an error code indicating this.
+ return -99;
+}
+
static jint
parse_init_args (JvVMInitArgs* vm_args)
{
@@ -1409,6 +1476,95 @@ parse_init_args (JvVMInitArgs* vm_args)
continue;
}
+ else if (! strncmp (option_string, "-agentlib", sizeof ("-agentlib") - 1))
+ {
+ char *strPtr;
+
+ if (strlen(option_string) > (sizeof ("-agentlib:") - 1))
+ strPtr = &option_string[sizeof ("-agentlib:") - 1];
+ else
+ {
+ fprintf (stderr,
+ "libgcj: Malformed agentlib argument %s: expected lib name\n",
+ option_string);
+ return -1;
+ }
+
+ // These are optional arguments to pass to the agent library.
+ jvmti_agent_opts = strchr (strPtr, '=');
+
+ if (! strncmp (strPtr, "jdwp", 4))
+ {
+ // We want to run JDWP here so set the correct variables.
+ remoteDebug = true;
+ jdwpOptions = ++jvmti_agent_opts;
+ }
+ else
+ {
+ jint nameLength;
+
+ if (jvmti_agent_opts == NULL)
+ nameLength = strlen (strPtr);
+ else
+ {
+ nameLength = jvmti_agent_opts - strPtr;
+ jvmti_agent_opts++;
+ }
+
+ char lib_name[nameLength + 3 + 1];
+ strcpy (lib_name, "lib");
+ strncat (lib_name, strPtr, nameLength);
+
+ jint result = load_jvmti_agent (lib_name);
+
+ if (result < 0)
+ {
+ return -1;
+ }
+ }
+
+ continue;
+ }
+ else if (! strncmp (option_string, "-agentpath:",
+ sizeof ("-agentpath:") - 1))
+ {
+ char *strPtr;
+
+ if (strlen(option_string) > 10)
+ strPtr = &option_string[10];
+ else
+ {
+ fprintf (stderr,
+ "libgcj: Malformed agentlib argument %s: expected lib path\n",
+ option_string);
+ return -1;
+ }
+
+ // These are optional arguments to pass to the agent library.
+ jvmti_agent_opts = strchr (strPtr, '=');
+
+ jint nameLength;
+
+ if (jvmti_agent_opts == NULL)
+ nameLength = strlen (strPtr);
+ else
+ {
+ nameLength = jvmti_agent_opts - strPtr;
+ jvmti_agent_opts++;
+ }
+
+ char lib_name[nameLength + 3 + 1];
+ strcpy (lib_name, "lib");
+ strncat (lib_name, strPtr, nameLength);
+ jint result = load_jvmti_agent (strPtr);
+
+ if (result < 0)
+ {
+ return -1;
+ }
+
+ continue;
+ }
else if (vm_args->ignoreUnrecognized)
{
if (option_string[0] == '_')
@@ -1569,6 +1725,10 @@ _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc,
main_thread = new MainThread (JvNewStringUTF (name),
arg_vec, is_jar);
_Jv_AttachCurrentThread (main_thread);
+
+ // Start JVMTI if an agent function has been found.
+ if (jvmti_agentonload)
+ (*jvmti_agentonload) (_Jv_GetJavaVM (), jvmti_agent_opts, NULL);
// Start JDWP
if (remoteDebug)
@@ -1583,11 +1743,9 @@ _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc,
// Wait for JDWP to initialize and start
jdwp->join ();
}
-
- // Send VmInit
- gnu::classpath::jdwp::event::VmInitEvent *event;
- event = new gnu::classpath::jdwp::event::VmInitEvent (main_thread);
- gnu::classpath::jdwp::Jdwp::notify (event);
+ // Send VMInit
+ if (JVMTI_REQUESTED_EVENT (VMInit))
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_INIT, main_thread);
}
catch (java::lang::Throwable *t)
{
@@ -1602,13 +1760,17 @@ _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc,
_Jv_ThreadRun (main_thread);
- // Notify debugger of VM's death
- if (gnu::classpath::jdwp::Jdwp::isDebugging)
+ // Send VMDeath
+ if (JVMTI_REQUESTED_EVENT (VMDeath))
{
- using namespace gnu::classpath::jdwp;
- event::VmDeathEvent *event = new event::VmDeathEvent ();
- Jdwp::notify (event);
+ java::lang::Thread *thread = java::lang::Thread::currentThread ();
+ JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_DEATH, thread, jni_env);
}
+
+ // Run JVMTI AgentOnUnload if it exists and an agent is loaded.
+ if (jvmti_agentonunload)
+ (*jvmti_agentonunload) (_Jv_GetJavaVM ());
// If we got here then something went wrong, as MainThread is not
// supposed to terminate.
diff --git a/libjava/sources.am b/libjava/sources.am
index 444060e9702..0a6adaa165f 100644
--- a/libjava/sources.am
+++ b/libjava/sources.am
@@ -326,15 +326,19 @@ gnu/classpath/jdwp/event/filters.list: $(gnu_classpath_jdwp_event_filters_source
gnu_classpath_jdwp_exception_source_files = \
+classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java \
classpath/gnu/classpath/jdwp/exception/InvalidClassException.java \
classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java \
classpath/gnu/classpath/jdwp/exception/InvalidCountException.java \
classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java \
classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java \
classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java \
classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java \
classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java \
classpath/gnu/classpath/jdwp/exception/InvalidStringException.java \
+classpath/gnu/classpath/jdwp/exception/InvalidTagException.java \
classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java \
classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java \
classpath/gnu/classpath/jdwp/exception/JdwpException.java \
@@ -342,6 +346,7 @@ classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java \
classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java \
classpath/gnu/classpath/jdwp/exception/NativeMethodException.java \
classpath/gnu/classpath/jdwp/exception/NotImplementedException.java \
+classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java \
classpath/gnu/classpath/jdwp/exception/VmDeadException.java
gnu_classpath_jdwp_exception_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_exception_source_files)))
@@ -361,6 +366,7 @@ classpath/gnu/classpath/jdwp/id/ClassObjectId.java \
classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/JdwpId.java \
+classpath/gnu/classpath/jdwp/id/NullObjectId.java \
classpath/gnu/classpath/jdwp/id/ObjectId.java \
classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java \
classpath/gnu/classpath/jdwp/id/StringId.java \
@@ -429,6 +435,8 @@ classpath/gnu/classpath/jdwp/util/JdwpString.java \
classpath/gnu/classpath/jdwp/util/LineTable.java \
classpath/gnu/classpath/jdwp/util/Location.java \
classpath/gnu/classpath/jdwp/util/MethodResult.java \
+classpath/gnu/classpath/jdwp/util/MonitorInfo.java \
+classpath/gnu/classpath/jdwp/util/NullObject.java \
classpath/gnu/classpath/jdwp/util/Signature.java \
classpath/gnu/classpath/jdwp/util/Value.java \
classpath/gnu/classpath/jdwp/util/VariableTable.java
@@ -442,6 +450,31 @@ gnu/classpath/jdwp/util.list: $(gnu_classpath_jdwp_util_source_files)
-include gnu/classpath/jdwp/util.deps
+gnu_classpath_jdwp_value_source_files = \
+classpath/gnu/classpath/jdwp/value/ArrayValue.java \
+classpath/gnu/classpath/jdwp/value/BooleanValue.java \
+classpath/gnu/classpath/jdwp/value/ByteValue.java \
+classpath/gnu/classpath/jdwp/value/CharValue.java \
+classpath/gnu/classpath/jdwp/value/DoubleValue.java \
+classpath/gnu/classpath/jdwp/value/FloatValue.java \
+classpath/gnu/classpath/jdwp/value/IntValue.java \
+classpath/gnu/classpath/jdwp/value/LongValue.java \
+classpath/gnu/classpath/jdwp/value/ObjectValue.java \
+classpath/gnu/classpath/jdwp/value/ShortValue.java \
+classpath/gnu/classpath/jdwp/value/StringValue.java \
+classpath/gnu/classpath/jdwp/value/Value.java \
+classpath/gnu/classpath/jdwp/value/ValueFactory.java \
+classpath/gnu/classpath/jdwp/value/VoidValue.java
+
+gnu_classpath_jdwp_value_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_classpath_jdwp_value_source_files)))
+
+gnu/classpath/jdwp/value.list: $(gnu_classpath_jdwp_value_source_files)
+ @$(mkinstalldirs) $(dir $@)
+ echo $(srcdir)/classpath/lib/gnu/classpath/jdwp/value/*.class > gnu/classpath/jdwp/value.list
+
+-include gnu/classpath/jdwp/value.deps
+
+
gnu_gcj_source_files = \
gnu/gcj/Core.java \
gnu/gcj/RawData.java \
@@ -8341,6 +8374,7 @@ all_packages_source_files = \
gnu/classpath/jdwp/processor.list \
gnu/classpath/jdwp/transport.list \
gnu/classpath/jdwp/util.list \
+ gnu/classpath/jdwp/value.list \
gnu/gcj.list \
gnu/gcj/convert.list \
gnu/gcj/io.list \
@@ -8585,6 +8619,7 @@ ordinary_header_files = \
$(gnu_classpath_jdwp_processor_header_files) \
$(gnu_classpath_jdwp_transport_header_files) \
$(gnu_classpath_jdwp_util_header_files) \
+ $(gnu_classpath_jdwp_value_header_files) \
$(gnu_gcj_header_files) \
$(gnu_gcj_convert_header_files) \
$(gnu_gcj_io_header_files) \
diff --git a/libjava/stacktrace.cc b/libjava/stacktrace.cc
index 5751e29b5f1..7cf0bf1ae03 100644
--- a/libjava/stacktrace.cc
+++ b/libjava/stacktrace.cc
@@ -1,6 +1,6 @@
// stacktrace.cc - Functions for unwinding & inspecting the call stack.
-/* Copyright (C) 2005, 2006 Free Software Foundation
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@@ -131,9 +131,11 @@ _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
if (func_addr == UNWRAP_FUNCTION_DESCRIPTOR (interp_run))
{
state->frames[pos].type = frame_interpreter;
- state->frames[pos].interp.meth = state->interp_frame->self;
+ _Jv_Frame *frame = static_cast<_Jv_Frame *> (state->interp_frame);
+ state->frames[pos].interp.meth
+ = static_cast<_Jv_InterpMethod *> (frame->self);
state->frames[pos].interp.pc = state->interp_frame->pc;
- state->interp_frame = state->interp_frame->next;
+ state->interp_frame = state->interp_frame->next_interp;
}
else
#endif
@@ -143,7 +145,7 @@ _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
state->frames[pos].type = frame_proxy;
state->frames[pos].proxyClass = state->interp_frame->proxyClass;
state->frames[pos].proxyMethod = state->interp_frame->proxyMethod;
- state->interp_frame = state->interp_frame->next;
+ state->interp_frame = state->interp_frame->next_interp;
}
else
{