/* src/vm/classcache.c - loaded class cache and loading constraints
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
- C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
- E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
- J. Wenninger, Institut f. Computersprachen - TU Wien
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Edwin Steiner
-
- Changes: Christian Thalinger
-
- $Id: classcache.c 4879 2006-05-05 17:34:49Z edwin $
-
*/
#include "config.h"
-#include "vm/types.h"
#include <assert.h>
+#include "vm/types.h"
+
#include "mm/memory.h"
+
+#include "threads/lock.hpp"
+#include "threads/mutex.hpp"
+
+#include "toolbox/hashtable.h"
+#include "toolbox/logging.h"
+
#include "vm/classcache.h"
-#include "vm/exceptions.h"
-#include "vm/hashtable.h"
-#include "vm/stringlocal.h"
+#include "vm/exceptions.hpp"
+#include "vm/options.h"
#include "vm/utf8.h"
/* DEBUG HELPERS */
/*============================================================================*/
-/*#define CLASSCACHE_VERBOSE*/
+/* #define CLASSCACHE_VERBOSE */
/*============================================================================*/
/* STATISTICS */
/* NOT synchronized! */
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-#if defined(USE_THREADS)
-# define CLASSCACHE_LOCK() builtin_monitorenter(lock_hashtable_classcache)
-# define CLASSCACHE_UNLOCK() builtin_monitorexit(lock_hashtable_classcache)
+#if defined(ENABLE_THREADS)
+# define CLASSCACHE_LOCK() Mutex_lock(classcache_hashtable_mutex)
+# define CLASSCACHE_UNLOCK() Mutex_unlock(classcache_hashtable_mutex)
#else
# define CLASSCACHE_LOCK()
# define CLASSCACHE_UNLOCK()
hashtable hashtable_classcache;
-#if defined(USE_THREADS)
-static java_objectheader *lock_hashtable_classcache;
+#if defined(ENABLE_THREADS)
+static Mutex *classcache_hashtable_mutex;
#endif
bool classcache_init(void)
{
+ TRACESUBSYSTEMINITIALIZATION("classcache_init");
+
/* create the hashtable */
hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
-#if defined(USE_THREADS)
- /* create utf hashtable lock object */
+#if defined(ENABLE_THREADS)
+ /* create utf hashtable mutex */
- lock_hashtable_classcache = NEW(java_objectheader);
-
-# if defined(NATIVE_THREADS)
- initObjectLock(lock_hashtable_classcache);
-# endif
+ classcache_hashtable_mutex = Mutex_new();
#endif
/* everything's ok */
*******************************************************************************/
static classcache_loader_entry * classcache_new_loader_entry(
- classloader * loader,
+ classloader_t * loader,
classcache_loader_entry * next)
{
classcache_loader_entry *lden;
sprintf(logbuffer,"classcache_merge_class_entries(%p,%p->%p,%p->%p) ",
(void*)en,(void*)clsenA,(void*)clsenA->classobj,(void*)clsenB,(void*)clsenB->classobj);
if (clsenA->classobj)
- utf_strcat_convert_to_latin1(logbuffer, clsenA->classobj->name);
+ utf_cat_classname(logbuffer, clsenA->classobj->name);
if (clsenB->classobj)
- utf_strcat_convert_to_latin1(logbuffer, clsenB->classobj->name);
- log_text(logbuffer);
+ utf_cat_classname(logbuffer, clsenB->classobj->name);
+ log_println(logbuffer);
#endif
CLASSCACHE_COUNT(stat_merge_class_entries);
*******************************************************************************/
-classinfo *classcache_lookup(classloader *initloader, utf *classname)
+classinfo *classcache_lookup(classloader_t *initloader, utf *classname)
{
classcache_name_entry *en;
classcache_class_entry *clsen;
*******************************************************************************/
-classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
+classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
{
classcache_name_entry *en;
classcache_class_entry *clsen;
*******************************************************************************/
-classinfo *classcache_lookup_defined_or_initiated(classloader *loader,
+classinfo *classcache_lookup_defined_or_initiated(classloader_t *loader,
utf *classname)
{
classcache_name_entry *en;
*******************************************************************************/
-classinfo *classcache_store(classloader *initloader, classinfo *cls,
+classinfo *classcache_store(classloader_t *initloader, classinfo *cls,
bool mayfree)
{
classcache_name_entry *en;
#ifdef CLASSCACHE_VERBOSE
sprintf(logbuffer,"classcache_store (%p,%d,%p=", (void*)initloader,mayfree,(void*)cls);
- utf_strcat_convert_to_latin1(logbuffer, cls->name);
+ utf_cat_classname(logbuffer, cls->name);
strcat(logbuffer,")");
- log_text(logbuffer);
+ log_println(logbuffer);
#endif
en = classcache_new_name(cls->name);
/* A class with the same (initloader,name) pair has been stored already. */
/* We free the given class and return the earlier one. */
#ifdef CLASSCACHE_VERBOSE
- dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
+ log_println("replacing %p with earlier loaded class %p",cls,clsen->classobj);
#endif
assert(clsen->classobj);
if (mayfree)
/* check if is has already been resolved to another class */
if (clsen->classobj != cls) {
/* a loading constraint is violated */
- *exceptionptr = exceptions_new_linkageerror(
- "loading constraint violated: ",cls);
+ exceptions_throw_linkageerror("loading constraint violated: ", cls);
goto return_exception;
}
return_success:
#ifdef CLASSCACHE_VERBOSE
- classcache_debug_dump(stderr,cls->name);
+ classcache_debug_dump(stdout,cls->name);
#endif
CLASSCACHE_UNLOCK();
return cls;
return false;
if (result != cls) {
- *exceptionptr = new_internalerror("class already stored in the class cache");
+ exceptions_throw_internalerror("class already stored in the class cache");
return false;
}
#ifdef CLASSCACHE_VERBOSE
sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
- utf_strcat_convert_to_latin1(logbuffer, cls->name);
+ utf_cat_classname(logbuffer, cls->name);
strcat(logbuffer,")");
- log_text(logbuffer);
+ log_println(logbuffer);
#endif
en = classcache_new_name(cls->name);
/* (if it is a different classinfo) */
if (clsen->classobj != cls) {
#ifdef CLASSCACHE_VERBOSE
- dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
+ log_println("replacing %p with earlier defined class %p",cls,clsen->classobj);
#endif
class_free(cls);
cls = clsen->classobj;
return_success:
#ifdef CLASSCACHE_VERBOSE
- classcache_debug_dump(stderr,cls->name);
+ classcache_debug_dump(stdout,cls->name);
#endif
CLASSCACHE_UNLOCK();
return cls;
static classcache_class_entry * classcache_find_loader(
classcache_name_entry * entry,
- classloader * loader)
+ classloader_t * loader)
{
classcache_class_entry *clsen;
classcache_loader_entry *lden;
}
}
- MFREE(hashtable_classcache.ptr, voidptr, hashtable_classcache.size);
+ MFREE(hashtable_classcache.ptr, void*, hashtable_classcache.size);
hashtable_classcache.size = 0;
hashtable_classcache.entries = 0;
hashtable_classcache.ptr = NULL;
*******************************************************************************/
#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraint(classloader * a,
- classloader * b,
+bool classcache_add_constraint(classloader_t * a,
+ classloader_t * b,
utf * classname)
{
classcache_name_entry *en;
assert(classname);
#ifdef CLASSCACHE_VERBOSE
- fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
- utf_fprint_printable_ascii_classname(stderr, classname);
- fprintf(stderr, ")\n");
+ log_start();
+ log_print("classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
+ utf_fprint_printable_ascii_classname(stdout, classname);
+ log_print(")\n");
+ log_finish();
#endif
/* a constraint with a == b is trivially satisfied */
if (clsenA->classobj && clsenB->classobj
&& clsenA->classobj != clsenB->classobj) {
/* no, the constraint is violated */
- *exceptionptr = exceptions_new_linkageerror(
- "loading constraint violated: ",clsenA->classobj);
+ exceptions_throw_linkageerror("loading constraint violated: ",
+ clsenA->classobj);
goto return_exception;
}
*******************************************************************************/
#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraints_for_params(classloader * a,
- classloader * b,
+bool classcache_add_constraints_for_params(classloader_t * a,
+ classloader_t * b,
methodinfo *m)
{
methoddesc *md;
}
#endif /* defined(ENABLE_VERIFIER) */
+
+/* classcache_number_of_loaded_classes *****************************************
+
+ Counts the number of loaded classes and returns it.
+
+ Note: This function assumes that the CLASSCACHE_LOCK is held by the
+ caller!
+
+*******************************************************************************/
+
+static s4 classcache_number_of_loaded_classes(void)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ s4 number;
+ s4 i;
+
+ /* initialize class counter */
+
+ number = 0;
+
+ for (i = 0; i < hashtable_classcache.size; i++) {
+ /* iterate over hashlink */
+
+ for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+ /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+ if (en->name->text[0] == '$')
+ continue;
+
+ /* iterate over classes with same name */
+
+ for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+ /* get only loaded classes */
+
+ if (clsen->classobj != NULL)
+ number++;
+ }
+ }
+ }
+
+ return number;
+}
+
+
+/* classcache_get_loaded_class_count *******************************************
+
+ Counts the number of loaded classes and returns it.
+
+*******************************************************************************/
+
+s4 classcache_get_loaded_class_count(void)
+{
+ s4 count;
+
+ CLASSCACHE_LOCK();
+
+ count = classcache_number_of_loaded_classes();
+
+ CLASSCACHE_UNLOCK();
+
+ return count;
+}
+
+
+/* classcache_get_loaded_classes ***********************************************
+
+ Returns an array of all loaded classes as array. The array is
+ allocaed on the Java heap.
+
+*******************************************************************************/
+
+#if defined(ENABLE_JVMTI)
+void classcache_get_loaded_classes(s4 *class_count_ptr,
+ classinfo ***classes_ptr)
+{
+ classinfo **classes;
+ s4 class_count;
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ s4 i;
+ s4 j;
+
+ CLASSCACHE_LOCK();
+
+ /* get the number of loaded classes and allocate the array */
+
+ class_count = classcache_number_of_loaded_classes();
+
+ classes = GCMNEW(classinfo*, class_count);
+
+ /* look in every slot of the hashtable */
+
+ for (i = 0, j = 0; i < hashtable_classcache.size; i++) {
+ /* iterate over hashlink */
+
+ for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+ /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+ if (en->name->text[0] == '$')
+ continue;
+
+ /* iterate over classes with same name */
+
+ for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+ /* get only loaded classes */
+
+ if (clsen->classobj != NULL) {
+ classes[j] = clsen->classobj;
+ j++;
+ }
+ }
+ }
+ }
+
+ /* pass the return values */
+
+ *class_count_ptr = class_count;
+ *classes_ptr = classes;
+
+ CLASSCACHE_UNLOCK();
+}
+#endif /* defined(ENABLE_JVMTI) */
+
+
+/* classcache_foreach_loaded_class *********************************************
+
+ Calls the given function for each loaded class.
+
+*******************************************************************************/
+
+void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
+ void *data)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ s4 i;
+
+ CLASSCACHE_LOCK();
+
+ /* look in every slot of the hashtable */
+
+ for (i = 0; i < hashtable_classcache.size; i++) {
+ /* iterate over hashlink */
+
+ for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+ /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+ if (en->name->text[0] == '$')
+ continue;
+
+ /* iterate over classes with same name */
+
+ for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+ /* get only loaded classes */
+
+ if (clsen->classobj != NULL) {
+ (*func)(clsen->classobj, data);
+ }
+ }
+ }
+ }
+
+ CLASSCACHE_UNLOCK();
+}
+
+
/*============================================================================*/
/* DEBUG DUMPS */
/*============================================================================*/
CLASSCACHE_LOCK();
- fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
- fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size);
- fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries);
- fprintf(file, "\n");
+ log_println("=== [loaded class cache] =====================================");
+ log_println("hash size : %d", (int) hashtable_classcache.size);
+ log_println("hash entries: %d", (int) hashtable_classcache.entries);
+ log_println("");
if (only) {
c = classcache_lookup_name(only);
/* iterate over all class entries */
for (clsen = c->classes; clsen; clsen = clsen->next) {
if (clsen->classobj) {
- fprintf(file, " loaded %p\n", (void *) clsen->classobj);
+ log_println(" loaded %p", (void *) clsen->classobj);
}
else {
- fprintf(file, " unresolved\n");
+ log_println(" unresolved");
}
- fprintf(file, " loaders:");
+
+ log_start();
+ log_print(" loaders: ");
for (lden = clsen->loaders; lden; lden = lden->next) {
- fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
+ log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
}
- fprintf(file, "\n constraints:");
+ log_finish();
+
+ log_start();
+ log_print(" constraints: ");
for (lden = clsen->constraints; lden; lden = lden->next) {
- fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
+ log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
}
- fprintf(file, "\n");
+ log_finish();
}
}