This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] JVMTI Stack Tracing


This patch implments the JVMTI methods GetStackTrace and GetFrameCount. It is fairly complicated, so it warrants some explanation.

This method of tracing the java stack relies on a frame list that is created as methods are called. Is extends the interpreted frame list already used, and creates a composite stack of all interpreted and JNI methods in the stack. To get a stack trace, JVMTI runs through this composite stack counting up the frames and extracting their info. _Jv_NativeFrame class is mostly empty, but could be expanded to contain more information if desired. I have also maintained compatability with the current exception stack tracing mechanism by leaving the purely interpreted list intact. I added a second variable to Thread.java called frame (as opposed to interp_frame) which is the first frame in the composite list.

This method, however, has some limitations, most notably CNI. Since CNI is not called through the VM in the way that JNI is, CNI methods will not show up in this stack trace. As I understand it, however, this is not a problem since CNI cannot be used when running interpreted, but I may be wrong on this point.

I have included a test case for the jvmti-interp.exp file I added yesterday, which shows GetStackTrace in action.

What does everyone think? I am very open to suggestions, but given the nature of CNI and our current goals of interpreted only debugging this seems like a reasonable solution.

Thanks,
Kyle

2007-01-24 Kyle Galloway <kgallowa@redhat.com>

	* include/java-interp.h:  Added _Jv_Frame class and its two
	subclasses _Jv_InterpFrame and _Jv_NativeFrame.  Also moved
	_Jv_FrameType from java-stack.h.
	* include/java-stack.h: Removed _Jv_FrameType.
	* java/lang/Thread.java: Added frame member to hold new
	composite frame stack.
	* java/lang/Thread.h: Regenerated.
	* java/lang/Thread.class: Rebuilt.
	* jni.cc (_Jv_JNIMethod::call): Push a frame onto the stack when
	calling a JNI method.
	* jvmti.cc (_Jv_JVMTI_GetStackTrace): New Method.
	(_Jv_JVMTI_GetFrameCount): New method.
	* stacktrace.cc (UnwindTraceFn): Modified to use new _Jv_Frame
	classes.
	* testsuite/libjava.jvmti/interp/getstacktrace.jar: New test.
	* testsuite/libjava.jvmti/interp/natgetstacktrace.cc: New test.
	* testsuite/libjava.jvmti/interp/getstacktrace.h: New test.
	* testsuite/libjava.jvmti/interp/getstacktrace.jar: New test.
	* testsuite/libjava.jvmti/interp/getstacktrace.out: Output file
	for test.


Index: libjava/stacktrace.cc
===================================================================
--- libjava/stacktrace.cc	(revision 121173)
+++ libjava/stacktrace.cc	(working copy)
@@ -131,9 +131,11 @@
   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 @@
       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 
     {
Index: libjava/classpath/lib/java/lang/Thread.class
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libjava/classpath/lib/java/lang/Thread$State.class
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libjava/include/java-interp.h
===================================================================
--- libjava/include/java-interp.h	(revision 121173)
+++ libjava/include/java-interp.h	(working copy)
@@ -205,11 +205,11 @@
   // 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:
    
   /* Get the line table for this method.
    * start  is the lowest index in the method
@@ -315,38 +315,89 @@
   }
 };
 
-// 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;
+  }
+};
+
+// 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)
+
+  //Debug info for local variables.
+  _Jv_word *locals;
+  char *locals_type;
+
+  _Jv_InterpFrame (void *meth, java::lang::Thread *thr, jclass proxyCls = 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;
   }
 
   ~_Jv_InterpFrame ()
   {
-    thread->interp_frame = (gnu::gcj::RawData *) next;
+    thread->interp_frame = (gnu::gcj::RawData *) next_interp;
   }
 };
 
+// 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)
+  {
+  }
+};
+
 #endif /* INTERPRETER */
 
 #endif /* __JAVA_INTERP_H__ */
Index: libjava/include/java-stack.h
===================================================================
--- libjava/include/java-stack.h	(revision 121173)
+++ libjava/include/java-stack.h	(working copy)
@@ -41,13 +41,6 @@
   }
 }
 
-enum _Jv_FrameType
-{
-  frame_native,
-  frame_interpreter,
-  frame_proxy
-};
-
 #ifdef INTERPRETER
 struct _Jv_InterpFrameInfo
 {
Index: libjava/testsuite/libjava.jvmti/interp/getstacktrace.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: libjava/testsuite/libjava.jvmti/interp/getstacktrace.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Index: libjava/testsuite/libjava.jvmti/interp/getstacktrace.java
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getstacktrace.java	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getstacktrace.java	(revision 0)
@@ -0,0 +1,88 @@
+public class getstacktrace
+  extends Thread
+{
+  public boolean done = false;
+
+  // num_frames is the number of frames > the original run () call so if
+  // num_frames = 1, the thread will have 2 frames, the original Thread.run
+  // call, plus one additional
+  public int num_frames, thread_num;
+
+  public static int num_threads = 1;
+
+  static
+    {
+      System.loadLibrary("natgetstacktrace");
+    }
+
+  public void run ()
+  {
+    thread_num = num_threads++;
+    num_frames = thread_num;
+
+    if (num_frames <= 1)
+      {
+        natRunner ();
+      }
+    else
+      {
+        if (thread_num % 2 == 0)
+          natPlaceholder ();
+        else
+          placeholder ();
+      }
+  }
+
+  public void placeholder ()
+  {
+    num_frames--;
+    if (num_frames <= 1)
+      {
+        if (thread_num % 2 == 1)
+          natRunner ();
+        else
+          runner ();
+      }
+    else
+      {
+        if (thread_num % 2 == 0)
+          natPlaceholder ();
+        else
+          placeholder ();
+      }
+  }
+  
+  public void runner ()
+  {
+    done = true;
+    while (done)
+      yield ();
+  }
+
+  public native void natPlaceholder ();
+  public native void natRunner ();
+
+  public static native int do_getstacktrace_tests (Thread[] threads);
+
+  public static void main (String[] args)
+  {
+    System.out.println ("JVMTI GetStackTrace Interpreted Test");
+
+    getstacktrace[] threads = new getstacktrace[10];
+
+    for (int i = 0; i < threads.length; i++)
+      {
+        threads[i] = new getstacktrace ();
+        threads[i].start ();
+        while (!threads[i].done)
+          yield ();
+      }
+
+    do_getstacktrace_tests (threads);
+
+    for (int i = 0; i < threads.length; i++)
+      {
+        threads[i].done = false;
+      }
+  }
+}
Index: libjava/testsuite/libjava.jvmti/interp/getstacktrace.h
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getstacktrace.h	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getstacktrace.h	(revision 0)
@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __getstacktrace__
+#define __getstacktrace__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT void JNICALL Java_getstacktrace_natPlaceholder (JNIEnv *env, jobject);
+JNIEXPORT void JNICALL Java_getstacktrace_natRunner (JNIEnv *env, jobject);
+JNIEXPORT jint JNICALL Java_getstacktrace_do_1getstacktrace_1tests (JNIEnv *env, jclass, jobjectArray);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __getstacktrace__ */
Index: libjava/testsuite/libjava.jvmti/interp/getstacktrace.out
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getstacktrace.out	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getstacktrace.out	(revision 0)
@@ -0,0 +1,76 @@
+JVMTI GetStackTrace Interpreted Test
+Thread has 2 frames
+Frame 0 is native
+Frame 1 is interpreted
+Thread has 3 frames
+Frame 0 is interpreted
+Frame 1 is native
+Frame 2 is interpreted
+Thread has 4 frames
+Frame 0 is native
+Frame 1 is interpreted
+Frame 2 is interpreted
+Frame 3 is interpreted
+Thread has 5 frames
+Frame 0 is interpreted
+Frame 1 is native
+Frame 2 is native
+Frame 3 is native
+Frame 4 is interpreted
+Thread has 6 frames
+Frame 0 is native
+Frame 1 is interpreted
+Frame 2 is interpreted
+Frame 3 is interpreted
+Frame 4 is interpreted
+Frame 5 is interpreted
+Thread has 7 frames
+Frame 0 is interpreted
+Frame 1 is native
+Frame 2 is native
+Frame 3 is native
+Frame 4 is native
+Frame 5 is native
+Frame 6 is interpreted
+Thread has 8 frames
+Frame 0 is native
+Frame 1 is interpreted
+Frame 2 is interpreted
+Frame 3 is interpreted
+Frame 4 is interpreted
+Frame 5 is interpreted
+Frame 6 is interpreted
+Frame 7 is interpreted
+Thread has 9 frames
+Frame 0 is interpreted
+Frame 1 is native
+Frame 2 is native
+Frame 3 is native
+Frame 4 is native
+Frame 5 is native
+Frame 6 is native
+Frame 7 is native
+Frame 8 is interpreted
+Thread has 10 frames
+Frame 0 is native
+Frame 1 is interpreted
+Frame 2 is interpreted
+Frame 3 is interpreted
+Frame 4 is interpreted
+Frame 5 is interpreted
+Frame 6 is interpreted
+Frame 7 is interpreted
+Frame 8 is interpreted
+Frame 9 is interpreted
+Thread has 11 frames
+Frame 0 is interpreted
+Frame 1 is native
+Frame 2 is native
+Frame 3 is native
+Frame 4 is native
+Frame 5 is native
+Frame 6 is native
+Frame 7 is native
+Frame 8 is native
+Frame 9 is native
+Frame 10 is interpreted
Index: libjava/testsuite/libjava.jvmti/interp/natgetstacktrace.cc
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/natgetstacktrace.cc	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/natgetstacktrace.cc	(revision 0)
@@ -0,0 +1,144 @@
+#include <jni.h>
+
+#include <jvmti.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+#include "getstacktrace.h"
+
+void
+printStackTrace (jvmtiFrameInfo *frames, jint frame_cnt)
+{
+  printf ("Thread has %d frames\n", static_cast<int> (frame_cnt));
+
+  for (int i = 0; i < frame_cnt; i++)
+    {
+      jmethodID method = frames[i].method;
+      jlocation location = frames[i].location;
+
+      if (location == -1)
+        {
+          printf ("Frame %d is native\n", i);
+        }
+      else
+        {
+          printf ("Frame %d is interpreted\n", i);
+        }
+    }
+}
+
+
+JNIEXPORT void JNICALL Java_getstacktrace_natPlaceholder (JNIEnv *env, jobject obj)
+{
+  jclass klass = env->GetObjectClass (obj);
+  jfieldID done_id = env->GetFieldID (klass, "done", "Z");
+  jfieldID num_frames_id = env->GetFieldID (klass, "num_frames", "I");
+  jfieldID thread_num_id = env->GetFieldID (klass, "thread_num", "I");
+
+  // num_frames--
+  jint n_frames = env->GetIntField (obj, num_frames_id);
+  n_frames--;
+  env->SetIntField (obj, num_frames_id, n_frames);
+
+  jint t_num = env->GetIntField (obj, thread_num_id);
+
+  if (n_frames <= 1)
+    {
+      if (t_num % 2 == 1)
+        {
+          jmethodID natRunner_id = env->GetMethodID (klass, "natRunner", "()V");
+          env->CallVoidMethod (obj, natRunner_id);
+        }
+      else
+        {
+          jmethodID runner_id = env->GetMethodID (klass, "runner", "()V");
+          env->CallVoidMethod (obj, runner_id);
+        }
+    }
+  else
+    {
+      if (t_num % 2 == 0)
+        {
+          jmethodID natPlaceholder_id = env->GetMethodID (klass,
+                                        "natPlaceholder",
+                                        "()V");
+          env->CallVoidMethod (obj, natPlaceholder_id);
+        }
+      else
+        {
+          jmethodID placeholder_id = env->GetMethodID (klass, "placeholder",
+                                     "()V");
+          env->CallVoidMethod (obj, placeholder_id);
+        }
+    }
+}
+
+JNIEXPORT void JNICALL Java_getstacktrace_natRunner (JNIEnv *env, jobject obj)
+{
+  jclass klass = env->GetObjectClass (obj);
+  jfieldID done_id = env->GetFieldID (klass, "done", "Z");
+
+
+  jboolean done;
+  done = true;
+  env->SetBooleanField (obj, done_id, done);
+
+  do
+    {
+      done = env->GetBooleanField (obj, done_id);
+      if (done == false)
+        break;
+      usleep (10);
+    }
+  while (done != false);
+}
+
+JNIEXPORT jint JNICALL Java_getstacktrace_do_1getstacktrace_1tests
+(JNIEnv *env, jclass klass, jobjectArray thr_arr)
+{
+  JavaVM *vm;
+  jint err = env->GetJavaVM (&vm);
+  if (err < 0)
+    {
+      fprintf (stderr, "error getting VM\n");
+      exit (1);
+    }
+
+  jvmtiEnv *jvmti = NULL;
+  vm->GetEnv ((void **) &jvmti, JVMTI_VERSION_1_0);
+
+  if (jvmti == NULL)
+    {
+      fprintf (stderr, "error getting jvmti environment\n");
+      exit (1);
+    }
+
+  jint frame_cnt;
+  jvmtiFrameInfo frames[30];
+
+  jvmtiError jerr;
+  jthread thr;
+
+  jsize num_threads = env->GetArrayLength (thr_arr);
+
+  for (int i = 0; i < num_threads; i++)
+    {
+      thr = reinterpret_cast<jthread>
+            (env->GetObjectArrayElement (thr_arr, static_cast<jsize> (i)));
+      fflush (stdout);
+      jerr = jvmti->GetStackTrace (thr, 0, 30, frames, &frame_cnt);
+      if (jerr != JVMTI_ERROR_NONE)
+        {
+          char *error_name;
+          jvmti->GetErrorName (jerr, &error_name);
+          fprintf (stderr, "JVMTI Error: %s\n", error_name);
+          jvmti->Deallocate (reinterpret_cast<unsigned char *> (error_name));
+        }
+      else
+        {
+          printStackTrace (frames, frame_cnt);
+        }
+    }
+}
Index: libjava/jni.cc
===================================================================
--- libjava/jni.cc	(revision 121173)
+++ libjava/jni.cc	(working copy)
@@ -2339,6 +2339,10 @@
 
   // Copy over passed-in arguments.
   memcpy (&real_args[offset], args, _this->args_raw_size);
+  
+  // Add a frame to the composite (interpreted + JNI) call stack
+  java::lang::Thread *thread = java::lang::Thread::currentThread();
+  _Jv_NativeFrame nat_frame (_this, thread);
 
   // The actual call to the JNI function.
 #if FFI_NATIVE_RAW_API
Index: libjava/jvmti.cc
===================================================================
--- libjava/jvmti.cc	(revision 121174)
+++ libjava/jvmti.cc	(working copy)
@@ -242,6 +242,34 @@
 }
 
 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 *thr = reinterpret_cast<Thread *> (thread);
+  THREAD_CHECK_VALID (thr);
+  THREAD_CHECK_IS_ALIVE (thr);
+   
+  _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thr->frame);
+  (*frame_count) = 0;
+  
+  while (frame != NULL)
+    {
+      (*frame_count)++;
+      frame = frame->next;
+    }
+  
+  return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
 _Jv_JVMTI_CreateRawMonitor (MAYBE_UNUSED jvmtiEnv *env, const char *name,
 			    jrawMonitorID *result)
 {
@@ -711,6 +739,82 @@
 }
 
 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 *thr = reinterpret_cast<Thread *> (thread);
+  THREAD_CHECK_VALID (thr);
+  THREAD_CHECK_IS_ALIVE (thr);
+    
+  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 *> (thr->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->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);
@@ -1449,7 +1553,7 @@
   UNIMPLEMENTED,		// GetTopThreadGroups
   UNIMPLEMENTED,		// GetThreadGroupInfo
   UNIMPLEMENTED,		// GetThreadGroupChildren
-  UNIMPLEMENTED,		// GetFrameCount
+  _Jv_JVMTI_GetFrameCount,		// GetFrameCount
   UNIMPLEMENTED,		// GetThreadState
   RESERVED,			// reserved18
   UNIMPLEMENTED,		// GetFrameLocation
@@ -1537,7 +1641,7 @@
   UNIMPLEMENTED,		// GetThreadListStackTraces
   UNIMPLEMENTED,		// GetThreadLocalStorage
   UNIMPLEMENTED,		// SetThreadLocalStorage
-  UNIMPLEMENTED,		// GetStackTrace
+  _Jv_JVMTI_GetStackTrace,		// GetStackTrace
   RESERVED,			// reserved105
   UNIMPLEMENTED,		// GetTag
   UNIMPLEMENTED,		// SetTag
Index: libjava/java/lang/Thread.h
===================================================================
--- libjava/java/lang/Thread.h	(revision 121173)
+++ libjava/java/lang/Thread.h	(working copy)
@@ -144,6 +144,7 @@
   static const jbyte THREAD_PARK_DEAD = 3;
   ::java::lang::Object * accessControlState;
   ::gnu::gcj::RawData * interp_frame;
+  ::gnu::gcj::RawData * frame;
   volatile jint state;
   ::gnu::gcj::RawDataManaged * data;
 public:
Index: libjava/java/lang/Thread.java
===================================================================
--- libjava/java/lang/Thread.java	(revision 121173)
+++ libjava/java/lang/Thread.java	(working copy)
@@ -182,6 +182,9 @@
   
   // 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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]