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/JDWP GetAllLoadedClasses


This patch implements the JVMTI and JDWP functions to get all loaded classes in the VM. To accomplish this, each class is marked as loaded in _Jv_PushClass, by calling ClassList::add () and stored as a referent to an element of a list of WeakReferences. When retrieving the list of loaded classes, the list is first checked to see if any of the classes has been GCed (there is a WeakReference to null), which will remove its entry from the list before it is returned. In order to avoid problems with circular class loading(try to load a class, then try to add it to the class list, whihc requires WeakReference to be loaded, which needs to be stored in the list, whichi requires WeakReference to be loaded...and so on), until it can be assured that WeakReference is loaded (which is checked in ClassList::setup ()), the classes that have been loaded are stored in a temporary linked list of jclass *. When setup is called, these classes are transferred over to the WeakReference list, and the memory used by this temporary list is freed.

ChangeLog
* jvmti.cc (_Jv_JVMTI_GetLoadedClasses): New method.
* prims.cc (_Jv_CreateJavaVM): Call ClassList::setup ().
* gnu/gcj/jvmti/ClassList.h: New file.
* gnu/gcj/jvmti/natClassList.cc: New file.
* gnu/classpath/jdwp/natVMVirtualMachine.cc (getAllLoadedClasses): Implement.
* java/lang/natClassLosder.cc (_Jv_PushClass): Call ClassList::add ().
* Makefile.am: Add gnu/gcj/jvmti/natClassList.cc.
* Makefile.in: Regenerated.


Questions/comments/concerns?

Thanks,

Kyle
Index: jvmti.cc
===================================================================
--- jvmti.cc	(revision 124076)
+++ jvmti.cc	(working copy)
@@ -24,6 +24,7 @@
 #include <gnu/gcj/runtime/BootClassLoader.h>
 #include <gnu/gcj/jvmti/Breakpoint.h>
 #include <gnu/gcj/jvmti/BreakpointManager.h>
+#include <gnu/gcj/jvmti/ClassList.h>
 
 #include <java/lang/Class.h>
 #include <java/lang/ClassLoader.h>
@@ -34,6 +35,7 @@
 #include <java/lang/VMClassLoader.h>
 #include <java/lang/reflect/Field.h>
 #include <java/lang/reflect/Modifier.h>
+#include <java/util/ArrayList.h>
 #include <java/util/Collection.h>
 #include <java/util/HashMap.h>
 #include <java/util/concurrent/locks/Lock.h>
@@ -1062,6 +1064,34 @@
 }
 
 static jvmtiError JNICALL
+_Jv_JVMTI_GetLoadedClasses (jvmtiEnv *env, jint *num_classes, jclass **classes)
+{
+  REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+  NULL_CHECK (num_classes);
+  NULL_CHECK (classes);
+  
+  ::java::util::ArrayList *list 
+    = gnu::gcj::jvmti::ClassList::getAllLoadedClasses ();
+  
+  *num_classes = list->size ();
+  
+  jvmtiError jerr = env->Allocate ((*num_classes) * sizeof (jclass),
+                                   reinterpret_cast<unsigned char **>
+                                     (classes));
+  
+  if (jerr != JVMTI_ERROR_NONE)
+    return jerr;
+  
+  for (int i = 0; i < *num_classes; i++)
+    {
+      jclass kls = reinterpret_cast<jclass> (list->get (i));
+      (*classes)[i] = kls;
+    }
+
+  return JVMTI_ERROR_NONE;
+} 
+
+static jvmtiError JNICALL
 _Jv_JVMTI_GetMaxLocals (jvmtiEnv *env, jmethodID method, jint *max_locals)
 {
   REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
@@ -2065,7 +2095,7 @@
   UNIMPLEMENTED,		// GetBytecodes
   _Jv_JVMTI_IsMethodNative,	// IsMethodNative
   _Jv_JVMTI_IsMethodSynthetic,	// IsMethodSynthetic
-  UNIMPLEMENTED,		// GetLoadedClasses
+  _Jv_JVMTI_GetLoadedClasses,	// GetLoadedClasses
   _Jv_JVMTI_GetClassLoaderClasses, // GetClassLoaderClasses
   UNIMPLEMENTED,		// PopFrame
   RESERVED,			// reserved81
Index: prims.cc
===================================================================
--- prims.cc	(revision 124075)
+++ prims.cc	(working copy)
@@ -64,6 +64,7 @@
 #include <java/io/PrintStream.h>
 #include <java/lang/UnsatisfiedLinkError.h>
 #include <java/lang/VirtualMachineError.h>
+#include <gnu/gcj/jvmti/ClassList.h>
 #include <gnu/gcj/runtime/ExtensionClassLoader.h>
 #include <gnu/gcj/runtime/FinalizerThread.h>
 #include <execution.h>
@@ -1646,6 +1647,9 @@
   // Set up the system class loader and the bootstrap class loader.
   gnu::gcj::runtime::ExtensionClassLoader::initialize();
   java::lang::VMClassLoader::initialize(JvNewStringLatin1(TOOLEXECLIBDIR));
+  
+  // Initialize the class list for JVMTI.
+  gnu::gcj::jvmti::ClassList::setup ();
 
   _Jv_RegisterBootstrapPackages();
 
Index: gnu/classpath/jdwp/natVMVirtualMachine.cc
===================================================================
--- gnu/classpath/jdwp/natVMVirtualMachine.cc	(revision 124075)
+++ gnu/classpath/jdwp/natVMVirtualMachine.cc	(working copy)
@@ -449,8 +450,22 @@
 java::util::Collection *
 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
 {
-  using namespace ::java::util;
-  return (Collection *) new ArrayList ();
+  jclass *classes = NULL;
+  jint num_classes;
+  
+  jvmtiError jerr = _jdwp_jvmtiEnv->GetLoadedClasses (&num_classes, &classes);
+  if (jerr != JVMTI_ERROR_NONE)
+    throw_jvmti_error (jerr);
+  
+  ::java::util::ArrayList *cls_lst = new ::java::util::ArrayList (num_classes);
+  for (int i = 0; i < num_classes; i++)
+    {
+      cls_lst->add (reinterpret_cast<jobject> (classes[i]));
+    }
+
+  _jdwp_jvmtiEnv->Deallocate (reinterpret_cast<unsigned char *> (classes));
+  
+  return (::java::util::Collection *) (cls_lst);
 }
 
 jint
Index: gnu/gcj/jvmti/ClassList.h
===================================================================
--- gnu/gcj/jvmti/ClassList.h	(revision 0)
+++ gnu/gcj/jvmti/ClassList.h	(revision 0)
@@ -0,0 +1,57 @@
+#ifndef __gnu_gcj_jvmti_ClassList__
+#define __gnu_gcj_jvmti_ClassList__
+
+#define JDWP_ALL_CLASSES_STATE_LOCK_LIST 0x01
+#define JDWP_ALL_CLASSES_STATE_LOADED 0x02
+
+extern "Java"
+{
+  namespace gnu
+  {
+    namespace gcj
+    {
+      namespace jvmti
+      {
+          class ClassList;
+      }
+    }
+  }
+}
+
+typedef struct _Jv_TempClassListElement
+{
+  ::java::lang::Class *klass;
+  _Jv_TempClassListElement *next;
+} _Jv_TempClassListElement;
+
+typedef struct _Jv_ClassListElement
+{
+  ::java::lang::ref::WeakReference *ref;
+  _Jv_ClassListElement *next;
+} _Jv_ClassListElement;
+
+class gnu::gcj::jvmti::ClassList
+{
+private:
+  static _Jv_ClassListElement *_classes_head;
+  static _Jv_ClassListElement *_classes_tail;
+  static int flags;
+  
+  static _Jv_TempClassListElement *t_list_head;
+  static _Jv_TempClassListElement *t_list_tail;
+  
+  static ::java::lang::Object *mutex;
+  
+  static void t_list_put (::java::lang::Class *klass);
+  
+  static void removeDeadEntries ();
+
+public:  
+  static void setup ();
+  
+  static void add (jclass klass);
+  
+  static ::java::util::ArrayList *getAllLoadedClasses ();
+};
+
+#endif /* __gnu_gcj_jvmti_ClassList__ */
Index: gnu/gcj/jvmti/natClassList.cc
===================================================================
--- gnu/gcj/jvmti/natClassList.cc	(revision 0)
+++ gnu/gcj/jvmti/natClassList.cc	(revision 0)
@@ -0,0 +1,158 @@
+#include <config.h>
+#include <gcj/cni.h>
+#include <gcj/method.h>
+#include <java-interp.h>
+#include <java-insns.h>
+#include <java-assert.h>
+#include <jvmti.h>
+#include <jvmti-int.h>
+
+#include <java/lang/Object.h>
+#include <java/lang/ref/WeakReference.h>
+#include <java/util/ArrayList.h>
+
+#include <gnu/gcj/jvmti/ClassList.h>
+
+// Initialize static variables.
+_Jv_ClassListElement *gnu::gcj::jvmti::ClassList::_classes_head = NULL;
+_Jv_ClassListElement *gnu::gcj::jvmti::ClassList::_classes_tail = NULL;
+int gnu::gcj::jvmti::ClassList::flags = 0;
+_Jv_TempClassListElement *gnu::gcj::jvmti::ClassList::t_list_head = NULL;
+_Jv_TempClassListElement *gnu::gcj::jvmti::ClassList::t_list_tail= NULL;
+::java::lang::Object *gnu::gcj::jvmti::ClassList::mutex = NULL;
+
+void 
+gnu::gcj::jvmti::ClassList::t_list_put (::java::lang::Class *klass)
+{
+  if (t_list_head == NULL)
+    {
+      // Make a new list.
+      t_list_head 
+        = reinterpret_cast<_Jv_TempClassListElement *> 
+            (_Jv_MallocUnchecked (sizeof (_Jv_TempClassListElement)));
+      t_list_tail = t_list_head;
+    }
+  else
+    {
+      // Append to the list.
+      t_list_tail->next
+        = reinterpret_cast<_Jv_TempClassListElement *> 
+            (_Jv_MallocUnchecked (sizeof (_Jv_TempClassListElement)));
+      t_list_tail = t_list_tail->next;
+    }
+  	
+  t_list_tail->klass = klass;
+  t_list_tail->next = NULL; 	    
+}
+
+void 
+gnu::gcj::jvmti::ClassList::setup ()
+{
+  using namespace java::util;
+  using namespace java::lang;
+  
+  // Ensure WeakReference is loaded.
+  _Jv_InitClass (&::java::lang::ref::WeakReference::class$);
+    
+  mutex = new ::java::lang::Object ();
+     
+  JvSynchronize dummy (mutex);
+  flags |= JDWP_ALL_CLASSES_STATE_LOCK_LIST;
+    
+  _Jv_TempClassListElement *t_list_ptr = t_list_head;
+    
+  while (t_list_ptr != NULL)
+    {
+      if (_classes_head == NULL)
+        {
+      	  _classes_head = reinterpret_cast<_Jv_ClassListElement *> 
+  	                    (_Jv_AllocBytes (sizeof (_Jv_ClassListElement)));
+          _classes_tail = _classes_head;
+        }
+      else
+        {
+          _classes_tail->next = reinterpret_cast<_Jv_ClassListElement *> 
+  	                      (_Jv_AllocBytes (sizeof (_Jv_ClassListElement)));
+          _classes_tail = _classes_tail->next;
+        }
+
+      _classes_tail->ref = new ::java::lang::ref::WeakReference (t_list_ptr->klass);
+      _classes_tail->next = NULL;
+      t_list_ptr = t_list_ptr->next;
+      
+      // Free the entry since it is no longer needed.
+      _Jv_Free (t_list_head);
+      t_list_head = t_list_ptr;
+    }
+    
+  t_list_head = NULL;
+  t_list_ptr = NULL;
+      
+  flags |= JDWP_ALL_CLASSES_STATE_LOADED;
+}
+
+void
+gnu::gcj::jvmti::ClassList::add (jclass klass)
+{
+  if (!flags)
+    {
+      t_list_put (klass);
+    }
+  else if (flags & JDWP_ALL_CLASSES_STATE_LOCK_LIST)
+    {
+      JvSynchronize dummy (mutex);
+      	
+      _classes_tail->next = reinterpret_cast<_Jv_ClassListElement *> 
+                              (_Jv_AllocBytes (sizeof (_Jv_ClassListElement)));
+      _classes_tail = _classes_tail->next;
+      _classes_tail->ref = new ::java::lang::ref::WeakReference (klass);
+      _classes_tail->next = NULL;
+    }
+}
+
+void
+gnu::gcj::jvmti::ClassList::removeDeadEntries ()
+{
+  if (flags & JDWP_ALL_CLASSES_STATE_LOADED)
+    {
+      JvSynchronize dummy (mutex);
+  
+      // First remove any dead entries from the front of the list so we know
+      // that the head of the list still contains a valid reference.
+      while (_classes_head != NULL && _classes_head->ref->get () == NULL)
+        _classes_head = _classes_head->next;
+  
+      _Jv_ClassListElement *classes_ptr = _classes_head;
+  
+      // We know that _classes_head points to a valid elelment, so go through
+      // the list removing any entries which reference collected Classes.
+      while (classes_ptr != NULL && classes_ptr->next != NULL)
+        {
+          if (classes_ptr->next->ref->get () == NULL)
+            classes_ptr->next = classes_ptr->next->next;
+          else
+            classes_ptr = classes_ptr->next;
+        }
+    }
+}
+
+::java::util::ArrayList *
+gnu::gcj::jvmti::ClassList::getAllLoadedClasses ()
+{
+  ::java::util::ArrayList *list = new ::java::util::ArrayList ();
+  if (flags & JDWP_ALL_CLASSES_STATE_LOADED)
+    {
+      removeDeadEntries ();
+  
+      JvSynchronize dummy (mutex);
+      _Jv_ClassListElement *classes_ptr = _classes_head;
+  
+      while (classes_ptr != NULL)
+        {
+          list->add (classes_ptr->ref->get ());
+          classes_ptr = classes_ptr->next;
+        }
+    }
+  
+  return list;
+}
Index: java/lang/natClassLoader.cc
===================================================================
--- java/lang/natClassLoader.cc	(revision 124075)
+++ java/lang/natClassLoader.cc	(working copy)
@@ -42,6 +42,7 @@
 #include <java/io/Serializable.h>
 #include <java/lang/Cloneable.h>
 #include <java/util/HashMap.h>
+#include <gnu/gcj/jvmti/ClassList.h>
 #include <gnu/gcj/runtime/BootClassLoader.h>
 #include <gnu/gcj/runtime/SystemClassLoader.h>
 
@@ -654,6 +655,8 @@
 void
 _Jv_PushClass (jclass k)
 {
+  gnu::gcj::jvmti::ClassList::add (k);
+
   JvSynchronize sync (&java::lang::Class::class$);
   jclass tmp = stack_head;
   stack_head = k;
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 124075)
+++ Makefile.am	(working copy)
@@ -851,6 +851,7 @@
 gnu/gcj/io/natSimpleSHSStream.cc \
 gnu/gcj/io/shs.cc \
 gnu/gcj/jvmti/natBreakpoint.cc \
+gnu/gcj/jvmti/natClassList.cc \
 gnu/gcj/jvmti/natExceptionEvent.cc \
 gnu/gcj/runtime/natFinalizerThread.cc \
 gnu/gcj/runtime/natSharedLibLoader.cc \

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