#include "vm/types.h"
#include "toolbox/list.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* Global Variables ***********************************************************/
#include "threads/thread.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/replace.hpp"
// Includes.
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* function prototypes ********************************************************/
#include "vm/jit/builtin.hpp"
#include "vm/jit/asmpart.h"
#include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "mm/gc.hpp"
#include "toolbox/logging.h"
#include "vm/options.h"
#include "vm/types.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* localref_table **************************************************************
#include "vm/class.hpp"
#include "vm/global.h"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/os.hpp"
#include "vm/utf8.h"
#include "vm/string.hpp"
#include "vm/types.h"
#include "vm/vm.hpp" /* REMOVE ME: temporarily */
-#include "vm/zip.h"
+#include "vm/zip.hpp"
static java_handle_t* zip_read_resource(list_classpath_entry *lce, utf *name)
#include "toolbox/logging.h"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/utf8.h"
#include "vm/vm.hpp"
#include "toolbox/logging.h"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/utf8.h"
#include "vm/vm.hpp"
#include "vm/jit/builtin.hpp"
#include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
#include "vm/initialize.hpp"
#include "vm/statistics.h"
#include "vm/string.hpp"
#include "vm/vm.hpp"
-#include "vm/zip.h"
+#include "vm/zip.hpp"
#include "vm/jit/asmpart.h"
#include "vm/globals.hpp"
#include "vm/initialize.hpp"
#include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/resolve.hpp"
#include "vm/string.hpp"
#include "vm/class.hpp"
#include "vm/initialize.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
#endif
#include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
#include "vm/globals.hpp"
#include "vm/initialize.hpp"
#include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/string.hpp"
#include "native/native.hpp"
#include "vm/field.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
class Reflection {
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
#include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "vm/utf8.h"
#include <stdarg.h>
#include "vm/class.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/utf8.h"
if ENABLE_ZLIB
ZLIB_SOURCES = \
- zip.c \
- zip.h
+ zip.cpp \
+ zip.hpp
endif
noinst_HEADERS = \
$(ASSERTION_SOURCES) \
class.cpp \
class.hpp \
- classcache.c \
- classcache.h \
+ classcache.cpp \
+ classcache.hpp \
$(CYCLES_STATS_SOURCES) \
descriptor.c \
descriptor.h \
linker.h \
loader.cpp \
loader.hpp \
- method.c \
- method.h \
+ method.cpp \
+ method.hpp \
options.c \
options.h \
os.cpp \
#include "vm/exceptions.hpp"
#include "vm/field.hpp"
#include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/stacktrace.hpp"
#include "vm/class.hpp"
#include "vm/field.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* macros *********************************************************************/
#include "vm/field.hpp"
#include "vm/global.h"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* function prototypes ********************************************************/
#include "vm/array.hpp"
#include "vm/jit/builtin.hpp"
#include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
#include "vm/global.h"
#include "vm/linker.h"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/string.hpp"
#include "vm/utf8.h"
+++ /dev/null
-/* src/vm/classcache.c - loaded class cache and loading constraints
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.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.hpp"
-#include "vm/options.h"
-#include "vm/utf8.h"
-
-
-/*************************************************************************
-
- Class Cache
-
- The classcache has two functions:
-
- 1) caching the resolution of class references
- 2) storing and checking loading constraints
-
- We will use the following terms in this description:
-
- N a class name: a utf string
- (N,L) a class reference with initiating loader L and class name N
- C a class (object): the result of resolving a reference (N,L)
- We will write resultion as
- C = *(N,L)
- (N,L1,L2) a loading constraint indicating that (N,L1) and (N,L2) must
- resolve to the same class C. So (N,L1,L2) means
- *(N,L1) = *(N,L2)
-
- The functions of the classcache require:
-
- 1) a mapping (N,L) |--> C for looking up prior resolution results.
- 2) storing the current set of loading constraints { (N,L1,L2) }
-
- These functions can be rearranged like that:
-
- a mapping N |--> (a mapping L |--> C or NULL,
- a set of constraints {(L1,L2)})
-
- Thus we can treat the mapping and constraints for each name N
- separately. The implementation does this by keeping a hash table
- mapping a name N to a `classcache_name_entry` which contains all
- info with respect to N.
-
- For a class name N we can define an equivalence relation ~N~ on
- class loaders:
-
- L1 ~N~ L2 <==> *(N,L1) = *(N,L2)
-
- A loading constraint (N,L1,L2) implies L1 ~N~ L2.
-
- Also, if two references (N,L1) and (N,L2) resolve to the same class C
- we have L1 ~N~ L2 because class loaders are required to return
- consistent resolutions for a name N [XXX].
-
- A `classcache_name_entry` keeps a set of tuples { (Cx,IL,CL) },
- where
- Cx...is a class C or NULL
- IL...is the set of initiating loaders
- CL...is the set of constrained loaders
-
- Such a tuple is called `classcache_class_entry` in the source code.
-
- The following holds for each tuple (Cx,IL,CL):
-
- . (Cx is NULL) implies IL = {}.
-
- . If Cx is a class, IL is the set of loaders that have been
- recorded as initiating loaders for Cx. IL may be the
- empty set {} in case Cx has already been defined but no
- initiating loader has been recorded, yet.
-
- . (IL u CL) is a subset of an equivalence class of ~N~.
-
- (This means that all loaders in IL and CL must resolve
- the name N to the same class.)
-
- The following holds for the set of tuples { (Cx,IL,CL) }:
-
- . For a given class C there is at most one tuple with Cx = C
- in the set. (There may be an arbitrary number of tuples
- with Cx = NULL, however.)
-
- . For a given loader L there is at most one tuple with
- L in (IL u CL).
-
- The implementation stores sets of loaders as linked lists of
- `classcache_loader_entry`s.
-
- Comments about manipulating the classcache can be found in the
- individual functions below.
-
-*************************************************************************/
-
-
-/* initial number of slots in the classcache hash table */
-#define CLASSCACHE_INIT_SIZE 2048
-
-/*============================================================================*/
-/* DEBUG HELPERS */
-/*============================================================================*/
-
-/* #define CLASSCACHE_VERBOSE */
-
-/*============================================================================*/
-/* STATISTICS */
-/*============================================================================*/
-
-/*#define CLASSCACHE_STATS*/
-
-#ifdef CLASSCACHE_STATS
-static int stat_classnames_stored = 0;
-static int stat_classes_stored = 0;
-static int stat_trivial_constraints = 0;
-static int stat_nontriv_constraints = 0;
-static int stat_nontriv_constraints_both = 0;
-static int stat_nontriv_constraints_merged = 0;
-static int stat_nontriv_constraints_one = 0;
-static int stat_nontriv_constraints_none = 0;
-static int stat_new_loader_entry = 0;
-static int stat_merge_class_entries = 0;
-static int stat_merge_loader_entries = 0;
-static int stat_lookup = 0;
-static int stat_lookup_class_entry_checked = 0;
-static int stat_lookup_loader_checked = 0;
-static int stat_lookup_name = 0;
-static int stat_lookup_name_entry = 0;
-static int stat_lookup_name_notfound = 0;
-static int stat_lookup_new_name = 0;
-static int stat_lookup_new_name_entry = 0;
-static int stat_lookup_new_name_collisions = 0;
-static int stat_rehash_names = 0;
-static int stat_rehash_names_collisions = 0;
-
-#define CLASSCACHE_COUNT(cnt) (cnt)++
-#define CLASSCACHE_COUNTIF(cond,cnt) do{if(cond) (cnt)++;} while(0)
-
-void classcache_print_statistics(FILE *file) {
- fprintf(file,"classnames stored : %8d\n",stat_classnames_stored);
- fprintf(file,"classes stored : %8d\n",stat_classes_stored);
- fprintf(file,"trivial constraints : %8d\n",stat_trivial_constraints);
- fprintf(file,"non-triv constraints: %8d\n",stat_nontriv_constraints);
- fprintf(file," both loaders rec.: %8d\n",stat_nontriv_constraints_both);
- fprintf(file," merged : %8d\n",stat_nontriv_constraints_merged);
- fprintf(file," one loader rec. : %8d\n",stat_nontriv_constraints_one);
- fprintf(file," no loaders rec. : %8d\n",stat_nontriv_constraints_none);
- fprintf(file,"new loader entries : %8d\n",stat_new_loader_entry);
- fprintf(file,"merge class entries : %8d\n",stat_merge_class_entries);
- fprintf(file,"merge loader entries: %8d\n",stat_merge_loader_entries);
- fprintf(file,"lookups : %8d\n",stat_lookup);
- fprintf(file," class entries ckd: %8d\n",stat_lookup_class_entry_checked);
- fprintf(file," loader checked : %8d\n",stat_lookup_loader_checked);
- fprintf(file,"lookup name : %8d\n",stat_lookup_name);
- fprintf(file," entries checked : %8d\n",stat_lookup_name_entry);
- fprintf(file," not found : %8d\n",stat_lookup_name_notfound);
- fprintf(file,"lookup (new) name : %8d\n",stat_lookup_new_name);
- fprintf(file," entries checked : %8d\n",stat_lookup_new_name_entry);
- fprintf(file," new collisions : %8d\n",stat_lookup_new_name_collisions);
- fprintf(file,"names rehashed : %8d times\n",stat_rehash_names);
- fprintf(file," collisions : %8d\n",stat_rehash_names_collisions);
-}
-#else
-#define CLASSCACHE_COUNT(cnt)
-#define CLASSCACHE_COUNTIF(cond,cnt)
-#endif
-
-/*============================================================================*/
-/* THREAD-SAFE LOCKING */
-/*============================================================================*/
-
- /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
- /* CAUTION: The static functions below are */
- /* NOT synchronized! */
- /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-#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()
-#endif
-
-/*============================================================================*/
-/* GLOBAL VARIABLES */
-/*============================================================================*/
-
-hashtable hashtable_classcache;
-
-#if defined(ENABLE_THREADS)
-static Mutex *classcache_hashtable_mutex;
-#endif
-
-
-/*============================================================================*/
-/* */
-/*============================================================================*/
-
-/* prototypes */
-
-static void classcache_free_class_entry(classcache_class_entry *clsen);
-static void classcache_remove_class_entry(classcache_name_entry *en,
- classcache_class_entry *clsen);
-
-/* hash function to use */
-
-#define CLASSCACHE_HASH utf_full_hashkey
-
-/* classcache_init *************************************************************
-
- Initialize the class cache
-
- Note: NOT synchronized!
-
-*******************************************************************************/
-
-bool classcache_init(void)
-{
- TRACESUBSYSTEMINITIALIZATION("classcache_init");
-
- /* create the hashtable */
-
- hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
-
-#if defined(ENABLE_THREADS)
- /* create utf hashtable mutex */
-
- classcache_hashtable_mutex = Mutex_new();
-#endif
-
- /* everything's ok */
-
- return true;
-}
-
-/* classcache_new_loader_entry *************************************************
-
- Create a new classcache_loader_entry struct
- (internally used helper function)
-
- IN:
- loader...........the ClassLoader object
- next.............the next classcache_loader_entry
-
- RETURN VALUE:
- the new classcache_loader_entry
-
-*******************************************************************************/
-
-static classcache_loader_entry * classcache_new_loader_entry(
- classloader_t * loader,
- classcache_loader_entry * next)
-{
- classcache_loader_entry *lden;
-
- lden = NEW(classcache_loader_entry);
- lden->loader = loader;
- lden->next = next;
- CLASSCACHE_COUNT(stat_new_loader_entry);
-
- return lden;
-}
-
-/* classcache_merge_loaders ****************************************************
-
- Merge two lists of loaders into one
- (internally used helper function)
-
- IN:
- lista............first list (may be NULL)
- listb............second list (may be NULL)
-
- RETURN VALUE:
- the merged list (may be NULL)
-
- NOTE:
- The lists given as arguments are destroyed!
-
-*******************************************************************************/
-
-static classcache_loader_entry * classcache_merge_loaders(
- classcache_loader_entry * lista,
- classcache_loader_entry * listb)
-{
- classcache_loader_entry *result;
- classcache_loader_entry *ldenA;
- classcache_loader_entry *ldenB;
- classcache_loader_entry **chain;
-
- CLASSCACHE_COUNT(stat_merge_loader_entries);
-
- /* XXX This is a quadratic algorithm. If this ever
- * becomes a problem, the loader lists should be
- * stored as sorted lists and merged in linear time. */
-
- result = NULL;
- chain = &result;
-
- for (ldenA = lista; ldenA; ldenA = ldenA->next) {
-
- for (ldenB = listb; ldenB; ldenB = ldenB->next) {
- if (ldenB->loader == ldenA->loader)
- goto common_element;
- }
-
- /* this loader is only in lista */
- *chain = ldenA;
- chain = &(ldenA->next);
-
- common_element:
- /* XXX free the duplicated element */
- ;
- }
-
- /* concat listb to the result */
- *chain = listb;
-
- return result;
-}
-
-/* classcache_merge_class_entries **********************************************
-
- Merge two `classcache_class_entry`s into one.
- (internally used helper function)
-
- IN:
- en...............the classcache_name_entry containing both class entries
- clsenA...........first class entry, will receive the result
- clsenB...........second class entry
-
- PRE-CONDITION:
- Either both entries must have the same classobj, or one of them has
- classobj == NULL.
-
- NOTE:
- clsenB is freed by this function!
-
-*******************************************************************************/
-
-static void classcache_merge_class_entries(classcache_name_entry *en,
- classcache_class_entry *clsenA,
- classcache_class_entry *clsenB)
-{
-#ifdef CLASSCACHE_VERBOSE
- char logbuffer[1024];
-#endif
-
- assert(en);
- assert(clsenA);
- assert(clsenB);
- assert(!clsenA->classobj || !clsenB->classobj || clsenA->classobj == clsenB->classobj);
-
-#ifdef CLASSCACHE_VERBOSE
- 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_cat_classname(logbuffer, clsenA->classobj->name);
- if (clsenB->classobj)
- utf_cat_classname(logbuffer, clsenB->classobj->name);
- log_println(logbuffer);
-#endif
-
- CLASSCACHE_COUNT(stat_merge_class_entries);
-
- /* clsenB will be merged into clsenA */
- clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
- clsenB->loaders = NULL; /* these have been freed or reused */
-
- clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
- clsenB->constraints);
- clsenB->constraints = NULL; /* these have been freed or reused */
-
- if (!clsenA->classobj)
- clsenA->classobj = clsenB->classobj;
-
- /* remove clsenB from the list of class entries */
- classcache_remove_class_entry(en, clsenB);
-}
-
-
-/* classcache_lookup_name ******************************************************
-
- Lookup a name in the first level of the cache
- (internally used helper function)
-
- IN:
- name.............the name to look up
-
- RETURN VALUE:
- a pointer to the classcache_name_entry for this name, or
- null if no entry was found.
-
-*******************************************************************************/
-
-static classcache_name_entry *classcache_lookup_name(utf *name)
-{
- classcache_name_entry *c; /* hash table element */
- u4 key; /* hashkey computed from classname */
- u4 slot; /* slot in hashtable */
-
- CLASSCACHE_COUNT(stat_lookup_name);
-
- key = CLASSCACHE_HASH(name->text, (u4) name->blength);
- slot = key & (hashtable_classcache.size - 1);
- c = hashtable_classcache.ptr[slot];
-
- /* search external hash chain for the entry */
-
- while (c) {
- /* entry found in hashtable */
- CLASSCACHE_COUNT(stat_lookup_name_entry);
-
- if (c->name == name)
- return c;
-
- c = c->hashlink; /* next element in external chain */
- }
-
- /* not found */
-
- CLASSCACHE_COUNT(stat_lookup_name_notfound);
- return NULL;
-}
-
-
-/* classcache_new_name *********************************************************
-
- Return a classcache_name_entry for the given name. The entry is created
- if it is not already in the cache.
- (internally used helper function)
-
- IN:
- name.............the name to look up / create an entry for
-
- RETURN VALUE:
- a pointer to the classcache_name_entry for this name
-
-*******************************************************************************/
-
-static classcache_name_entry *classcache_new_name(utf *name)
-{
- classcache_name_entry *c; /* hash table element */
- u4 key; /* hashkey computed from classname */
- u4 slot; /* slot in hashtable */
- u4 i;
-
- CLASSCACHE_COUNT(stat_lookup_new_name);
-
- key = CLASSCACHE_HASH(name->text, (u4) name->blength);
- slot = key & (hashtable_classcache.size - 1);
- c = hashtable_classcache.ptr[slot];
-
- /* search external hash chain for the entry */
-
- while (c) {
- /* entry found in hashtable */
- CLASSCACHE_COUNT(stat_lookup_new_name_entry);
-
- if (c->name == name)
- return c;
-
- c = c->hashlink; /* next element in external chain */
- }
-
- /* location in hashtable found, create new entry */
-
- c = NEW(classcache_name_entry);
-
- c->name = name;
- c->classes = NULL;
-
- /* insert entry into hashtable */
- c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
- CLASSCACHE_COUNTIF(c->hashlink,stat_lookup_new_name_collisions);
- hashtable_classcache.ptr[slot] = c;
-
- /* update number of hashtable-entries */
- hashtable_classcache.entries++;
- CLASSCACHE_COUNT(stat_classnames_stored);
-
- if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
- /* reorganization of hashtable */
-
- classcache_name_entry *c2;
- hashtable newhash; /* the new hashtable */
-
- CLASSCACHE_COUNT(stat_rehash_names);
-
- /* create new hashtable, double the size */
-
- hashtable_create(&newhash, hashtable_classcache.size * 2);
- newhash.entries = hashtable_classcache.entries;
-
- /* transfer elements to new hashtable */
-
- for (i = 0; i < hashtable_classcache.size; i++) {
- c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
- while (c2) {
- classcache_name_entry *nextc = c2->hashlink;
- u4 newslot =
- (CLASSCACHE_HASH(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
-
- c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
- CLASSCACHE_COUNTIF(c2->hashlink,stat_rehash_names_collisions);
- newhash.ptr[newslot] = c2;
-
- c2 = nextc;
- }
- }
-
- /* dispose old table */
-
- MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
- hashtable_classcache = newhash;
- }
-
- return c;
-}
-
-
-/* classcache_lookup ***********************************************************
-
- Lookup a possibly loaded class
-
- IN:
- initloader.......initiating loader for resolving the class name
- classname........class name to look up
-
- RETURN VALUE:
- The return value is a pointer to the cached class object,
- or NULL, if the class is not in the cache.
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-classinfo *classcache_lookup(classloader_t *initloader, utf *classname)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsen;
- classcache_loader_entry *lden;
- classinfo *cls = NULL;
-
- CLASSCACHE_LOCK();
-
- CLASSCACHE_COUNT(stat_lookup);
- en = classcache_lookup_name(classname);
-
- if (en) {
- /* iterate over all class entries */
-
- for (clsen = en->classes; clsen; clsen = clsen->next) {
- CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
- /* check if this entry has been loaded by initloader */
-
- for (lden = clsen->loaders; lden; lden = lden->next) {
- CLASSCACHE_COUNT(stat_lookup_loader_checked);
- if (lden->loader == initloader) {
- /* found the loaded class entry */
-
- assert(clsen->classobj);
- cls = clsen->classobj;
- goto found;
- }
- }
- }
- }
-
- found:
- CLASSCACHE_UNLOCK();
- return cls;
-}
-
-
-/* classcache_lookup_defined ***************************************************
-
- Lookup a class with the given name and defining loader
-
- IN:
- defloader........defining loader
- classname........class name
-
- RETURN VALUE:
- The return value is a pointer to the cached class object,
- or NULL, if the class is not in the cache.
-
-*******************************************************************************/
-
-classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsen;
- classinfo *cls = NULL;
-
- CLASSCACHE_LOCK();
-
- en = classcache_lookup_name(classname);
-
- if (en) {
- /* iterate over all class entries */
- for (clsen = en->classes; clsen; clsen = clsen->next) {
- if (!clsen->classobj)
- continue;
-
- /* check if this entry has been defined by defloader */
- if (clsen->classobj->classloader == defloader) {
- cls = clsen->classobj;
- goto found;
- }
- }
- }
-
- found:
- CLASSCACHE_UNLOCK();
- return cls;
-}
-
-
-/* classcache_lookup_defined_or_initiated **************************************
-
- Lookup a class that has been defined or initiated by the given loader
-
- IN:
- loader...........defining or initiating loader
- classname........class name to look up
-
- RETURN VALUE:
- The return value is a pointer to the cached class object,
- or NULL, if the class is not in the cache.
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-classinfo *classcache_lookup_defined_or_initiated(classloader_t *loader,
- utf *classname)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsen;
- classcache_loader_entry *lden;
- classinfo *cls = NULL;
-
- CLASSCACHE_LOCK();
-
- en = classcache_lookup_name(classname);
-
- if (en) {
- /* iterate over all class entries */
-
- for (clsen = en->classes; clsen; clsen = clsen->next) {
-
- /* check if this entry has been defined by loader */
- if (clsen->classobj && clsen->classobj->classloader == loader) {
- cls = clsen->classobj;
- goto found;
- }
-
- /* check if this entry has been initiated by loader */
- for (lden = clsen->loaders; lden; lden = lden->next) {
- if (lden->loader == loader) {
- /* found the loaded class entry */
-
- assert(clsen->classobj);
- cls = clsen->classobj;
- goto found;
- }
- }
- }
- }
-
- found:
- CLASSCACHE_UNLOCK();
- return cls;
-}
-
-
-/* classcache_store ************************************************************
-
- Store a loaded class. If a class of the same name has already been stored
- with the same initiating loader, then the given class CLS is freed (if
- possible) and the previously stored class is returned.
-
- IN:
- initloader.......initiating loader used to load the class
- (may be NULL indicating the bootstrap loader)
- cls..............class object to cache
- mayfree..........true if CLS may be freed in case another class is
- returned
-
- RETURN VALUE:
- cls..............everything ok, the class was stored in the cache,
- other classinfo..another class with the same (initloader,name) has been
- stored earlier. CLS has been freed[1] and the earlier
- stored class is returned.
- NULL.............an exception has been thrown.
-
- Note: synchronized with global tablelock
-
- [1]...in case MAYFREE is true
-
-*******************************************************************************/
-
-classinfo *classcache_store(classloader_t *initloader, classinfo *cls,
- bool mayfree)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsen;
- classcache_class_entry *clsenB;
- classcache_loader_entry *lden;
-#ifdef CLASSCACHE_VERBOSE
- char logbuffer[1024];
-#endif
-
- assert(cls);
- assert(cls->state & CLASS_LOADED);
-
- CLASSCACHE_LOCK();
-
-#ifdef CLASSCACHE_VERBOSE
- sprintf(logbuffer,"classcache_store (%p,%d,%p=", (void*)initloader,mayfree,(void*)cls);
- utf_cat_classname(logbuffer, cls->name);
- strcat(logbuffer,")");
- log_println(logbuffer);
-#endif
-
- en = classcache_new_name(cls->name);
-
- assert(en);
-
- /* iterate over all class entries */
- for (clsen = en->classes; clsen; clsen = clsen->next) {
-
- /* check if this entry has already been loaded by initloader */
- for (lden = clsen->loaders; lden; lden = lden->next) {
- if (lden->loader == initloader) {
- if (clsen->classobj != cls) {
- /* 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
- log_println("replacing %p with earlier loaded class %p",cls,clsen->classobj);
-#endif
- assert(clsen->classobj);
- if (mayfree)
- class_free(cls);
- cls = clsen->classobj;
- }
- goto return_success;
- }
- }
-
- /* {This entry has not been resolved with initloader} */
-
- /* check if initloader is constrained to this entry */
- for (lden = clsen->constraints; lden; lden = lden->next) {
- if (lden->loader == initloader) {
- /* we have to use this entry. check if it has been resolved */
- if (clsen->classobj) {
- /* check if is has already been resolved to another class */
- if (clsen->classobj != cls) {
- /* a loading constraint is violated */
- exceptions_throw_linkageerror("loading constraint violated: ", cls);
- goto return_exception;
- }
-
- /* record initloader as initiating loader */
- clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
- goto return_success;
- }
-
- /* {this is the first resolution for this entry} */
- /* record initloader as initiating loader */
- clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
-
- /* maybe we can merge this entry with another one */
- for (clsenB = en->classes; clsenB; clsenB = clsenB->next) {
- /* we dont want the entry that we have already */
- if (clsenB->classobj == cls) {
- /* this entry has the same classobj. let's merge them */
- classcache_merge_class_entries(en,clsen,clsenB);
- goto return_success;
- }
- }
-
- /* record the loaded class object */
- clsen->classobj = cls;
- CLASSCACHE_COUNT(stat_classes_stored);
-
- /* done */
- goto return_success;
- }
- }
-
- }
-
- /* {There is no class entry containing initloader as initiating
- * or constrained loader.} */
-
- /* we look for a class entry with the same classobj we want to store */
- for (clsen = en->classes; clsen; clsen = clsen->next) {
- if (clsen->classobj == cls) {
- /* this entry is about the same classobj. let's use it */
- /* check if this entry has already been loaded by initloader */
- for (lden = clsen->loaders; lden; lden = lden->next) {
- if (lden->loader == initloader)
- goto return_success;
- }
- clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
- goto return_success;
- }
- }
-
- /* create a new class entry for this class object with */
- /* initiating loader initloader */
-
- clsen = NEW(classcache_class_entry);
- clsen->classobj = cls;
- clsen->loaders = classcache_new_loader_entry(initloader, NULL);
- clsen->constraints = NULL;
-
- clsen->next = en->classes;
- en->classes = clsen;
- CLASSCACHE_COUNT(stat_classes_stored);
-
- return_success:
-#ifdef CLASSCACHE_VERBOSE
- classcache_debug_dump(stdout,cls->name);
-#endif
- CLASSCACHE_UNLOCK();
- return cls;
-
- return_exception:
- CLASSCACHE_UNLOCK();
- return NULL; /* exception */
-}
-
-/* classcache_store_unique *****************************************************
-
- Store a loaded class as loaded by the bootstrap loader. This is a wrapper
- aroung classcache_store that throws an exception if a class with the same
- name has already been loaded by the bootstrap loader.
-
- This function is used to register a few special classes during startup.
- It should not be used otherwise.
-
- IN:
- cls..............class object to cache
-
- RETURN VALUE:
- true.............everything ok, the class was stored.
- false............an exception has been thrown.
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-bool classcache_store_unique(classinfo *cls)
-{
- classinfo *result;
-
- result = classcache_store(NULL,cls,false);
- if (result == NULL)
- return false;
-
- if (result != cls) {
- exceptions_throw_internalerror("class already stored in the class cache");
- return false;
- }
-
- return true;
-}
-
-/* classcache_store_defined ****************************************************
-
- Store a loaded class after it has been defined. If the class has already
- been defined by the same defining loader in another thread, free the given
- class and returned the one which has been defined earlier.
-
- IN:
- cls..............class object to store. classloader must be set
- (classloader may be NULL, for bootloader)
-
- RETURN VALUE:
- cls..............everything ok, the class was stored the cache,
- other classinfo..the class had already been defined, CLS was freed, the
- class which was defined earlier is returned,
- NULL.............an exception has been thrown.
-
-*******************************************************************************/
-
-classinfo *classcache_store_defined(classinfo *cls)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsen;
-#ifdef CLASSCACHE_VERBOSE
- char logbuffer[1024];
-#endif
-
- assert(cls);
- assert(cls->state & CLASS_LOADED);
-
- CLASSCACHE_LOCK();
-
-#ifdef CLASSCACHE_VERBOSE
- sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
- utf_cat_classname(logbuffer, cls->name);
- strcat(logbuffer,")");
- log_println(logbuffer);
-#endif
-
- en = classcache_new_name(cls->name);
-
- assert(en);
-
- /* iterate over all class entries */
- for (clsen = en->classes; clsen; clsen = clsen->next) {
-
- /* check if this class has been defined by the same classloader */
- if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
- /* we found an earlier definition, delete the newer one */
- /* (if it is a different classinfo) */
- if (clsen->classobj != cls) {
-#ifdef CLASSCACHE_VERBOSE
- log_println("replacing %p with earlier defined class %p",cls,clsen->classobj);
-#endif
- class_free(cls);
- cls = clsen->classobj;
- }
- goto return_success;
- }
- }
-
- /* create a new class entry for this class object */
- /* the list of initiating loaders is empty at this point */
-
- clsen = NEW(classcache_class_entry);
- clsen->classobj = cls;
- clsen->loaders = NULL;
- clsen->constraints = NULL;
-
- clsen->next = en->classes;
- en->classes = clsen;
- CLASSCACHE_COUNT(stat_classes_stored);
-
-return_success:
-#ifdef CLASSCACHE_VERBOSE
- classcache_debug_dump(stdout,cls->name);
-#endif
- CLASSCACHE_UNLOCK();
- return cls;
-}
-
-/* classcache_find_loader ******************************************************
-
- Find the class entry loaded by or constrained to a given loader
- (internally used helper function)
-
- IN:
- entry............the classcache_name_entry
- loader...........the loader to look for
-
- RETURN VALUE:
- the classcache_class_entry for the given loader, or
- NULL if no entry was found
-
-*******************************************************************************/
-
-static classcache_class_entry * classcache_find_loader(
- classcache_name_entry * entry,
- classloader_t * loader)
-{
- classcache_class_entry *clsen;
- classcache_loader_entry *lden;
-
- assert(entry);
-
- /* iterate over all class entries */
- for (clsen = entry->classes; clsen; clsen = clsen->next) {
-
- /* check if this entry has already been loaded by initloader */
- for (lden = clsen->loaders; lden; lden = lden->next) {
- if (lden->loader == loader)
- return clsen; /* found */
- }
-
- /* check if loader is constrained to this entry */
- for (lden = clsen->constraints; lden; lden = lden->next) {
- if (lden->loader == loader)
- return clsen; /* found */
- }
- }
-
- /* not found */
- return NULL;
-}
-
-/* classcache_free_class_entry *************************************************
-
- Free the memory used by a class entry
-
- IN:
- clsen............the classcache_class_entry to free
-
-*******************************************************************************/
-
-static void classcache_free_class_entry(classcache_class_entry * clsen)
-{
- classcache_loader_entry *lden;
- classcache_loader_entry *next;
-
- assert(clsen);
-
- for (lden = clsen->loaders; lden; lden = next) {
- next = lden->next;
- FREE(lden, classcache_loader_entry);
- }
- for (lden = clsen->constraints; lden; lden = next) {
- next = lden->next;
- FREE(lden, classcache_loader_entry);
- }
-
- FREE(clsen, classcache_class_entry);
-}
-
-/* classcache_remove_class_entry ***********************************************
-
- Remove a classcache_class_entry from the list of possible resolution of
- a name entry
- (internally used helper function)
-
- IN:
- entry............the classcache_name_entry
- clsen............the classcache_class_entry to remove
-
-*******************************************************************************/
-
-static void classcache_remove_class_entry(classcache_name_entry * entry,
- classcache_class_entry * clsen)
-{
- classcache_class_entry **chain;
-
- assert(entry);
- assert(clsen);
-
- chain = &(entry->classes);
- while (*chain) {
- if (*chain == clsen) {
- *chain = clsen->next;
- classcache_free_class_entry(clsen);
- return;
- }
- chain = &((*chain)->next);
- }
-}
-
-/* classcache_free_name_entry **************************************************
-
- Free the memory used by a name entry
-
- IN:
- entry............the classcache_name_entry to free
-
-*******************************************************************************/
-
-static void classcache_free_name_entry(classcache_name_entry * entry)
-{
- classcache_class_entry *clsen;
- classcache_class_entry *next;
-
- assert(entry);
-
- for (clsen = entry->classes; clsen; clsen = next) {
- next = clsen->next;
- classcache_free_class_entry(clsen);
- }
-
- FREE(entry, classcache_name_entry);
-}
-
-/* classcache_free *************************************************************
-
- Free the memory used by the class cache
-
- NOTE:
- The class cache may not be used any more after this call, except
- when it is reinitialized with classcache_init.
-
- Note: NOT synchronized!
-
-*******************************************************************************/
-
-void classcache_free(void)
-{
- u4 slot;
- classcache_name_entry *entry;
- classcache_name_entry *next;
-
- for (slot = 0; slot < hashtable_classcache.size; ++slot) {
- for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
- next = entry->hashlink;
- classcache_free_name_entry(entry);
- }
- }
-
- MFREE(hashtable_classcache.ptr, void*, hashtable_classcache.size);
- hashtable_classcache.size = 0;
- hashtable_classcache.entries = 0;
- hashtable_classcache.ptr = NULL;
-}
-
-/* classcache_add_constraint ***************************************************
-
- Add a loading constraint
-
- IN:
- a................first initiating loader
- b................second initiating loader
- classname........class name
-
- RETURN VALUE:
- true.............everything ok, the constraint has been added,
- false............an exception has been thrown.
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraint(classloader_t * a,
- classloader_t * b,
- utf * classname)
-{
- classcache_name_entry *en;
- classcache_class_entry *clsenA;
- classcache_class_entry *clsenB;
-
- assert(classname);
-
-#ifdef CLASSCACHE_VERBOSE
- 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 (a == b) {
- CLASSCACHE_COUNT(stat_trivial_constraints);
- return true;
- }
-
- CLASSCACHE_LOCK();
-
- en = classcache_new_name(classname);
-
- assert(en);
- CLASSCACHE_COUNT(stat_nontriv_constraints);
-
- /* find the entry loaded by / constrained to each loader */
- clsenA = classcache_find_loader(en, a);
- clsenB = classcache_find_loader(en, b);
-
- if (clsenA && clsenB) {
- /* { both loaders have corresponding entries } */
- CLASSCACHE_COUNT(stat_nontriv_constraints_both);
-
- /* if the entries are the same, the constraint is already recorded */
- if (clsenA == clsenB)
- goto return_success;
-
- /* check if the entries can be merged */
- if (clsenA->classobj && clsenB->classobj
- && clsenA->classobj != clsenB->classobj) {
- /* no, the constraint is violated */
- exceptions_throw_linkageerror("loading constraint violated: ",
- clsenA->classobj);
- goto return_exception;
- }
-
- /* yes, merge the entries */
- classcache_merge_class_entries(en,clsenA,clsenB);
- CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
- }
- else {
- /* { at most one of the loaders has a corresponding entry } */
-
- /* set clsenA to the single class entry we have */
- if (!clsenA)
- clsenA = clsenB;
-
- if (!clsenA) {
- /* { no loader has a corresponding entry } */
- CLASSCACHE_COUNT(stat_nontriv_constraints_none);
-
- /* create a new class entry with the constraint (a,b,en->name) */
- clsenA = NEW(classcache_class_entry);
- clsenA->classobj = NULL;
- clsenA->loaders = NULL;
- clsenA->constraints = classcache_new_loader_entry(b, NULL);
- clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
-
- clsenA->next = en->classes;
- en->classes = clsenA;
- }
- else {
- CLASSCACHE_COUNT(stat_nontriv_constraints_one);
-
- /* make b the loader that has no corresponding entry */
- if (clsenB)
- b = a;
-
- /* loader b must be added to entry clsenA */
- clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
- }
- }
-
- return_success:
- CLASSCACHE_UNLOCK();
- return true;
-
- return_exception:
- CLASSCACHE_UNLOCK();
- return false; /* exception */
-}
-#endif /* defined(ENABLE_VERIFIER) */
-
-/* classcache_add_constraints_for_params ***************************************
-
- Add loading constraints for the parameters and return type of
- the given method.
-
- IN:
- a................first initiating loader
- b................second initiating loader
- m................methodinfo
-
- RETURN VALUE:
- true.............everything ok, the constraints have been added,
- false............an exception has been thrown.
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraints_for_params(classloader_t * a,
- classloader_t * b,
- methodinfo *m)
-{
- methoddesc *md;
- typedesc *td;
- s4 i;
-
- /* a constraint with a == b is trivially satisfied */
-
- if (a == b) {
- return true;
- }
-
- /* get the parsed descriptor */
-
- assert(m);
- md = m->parseddesc;
- assert(md);
-
- /* constrain the return type */
-
- if (md->returntype.type == TYPE_ADR) {
- if (!classcache_add_constraint(a, b, md->returntype.classref->name))
- return false; /* exception */
- }
-
- /* constrain each reference type used in the parameters */
-
- td = md->paramtypes;
- i = md->paramcount;
- for (; i--; td++) {
- if (td->type != TYPE_ADR)
- continue;
-
- if (!classcache_add_constraint(a, b, td->classref->name))
- return false; /* exception */
- }
-
- /* everything ok */
- return true;
-}
-#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_debug_dump *******************************************************
-
- Print the contents of the loaded class cache to a stream
-
- IN:
- file.............output stream
- only.............if != NULL, only print entries for this name
- (Currently we print also the rest of the hash chain to
- get a feel for the average length of hash chains.)
-
- Note: synchronized with global tablelock
-
-*******************************************************************************/
-
-#ifndef NDEBUG
-void classcache_debug_dump(FILE * file,utf *only)
-{
- classcache_name_entry *c;
- classcache_class_entry *clsen;
- classcache_loader_entry *lden;
- u4 slot;
-
- CLASSCACHE_LOCK();
-
- 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);
- slot = 0; /* avoid compiler warning */
- goto dump_it;
- }
-
- for (slot = 0; slot < hashtable_classcache.size; ++slot) {
- c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
-
-dump_it:
- for (; c; c = c->hashlink) {
- utf_fprint_printable_ascii_classname(file, c->name);
- fprintf(file, "\n");
-
- /* iterate over all class entries */
- for (clsen = c->classes; clsen; clsen = clsen->next) {
- if (clsen->classobj) {
- log_println(" loaded %p", (void *) clsen->classobj);
- }
- else {
- log_println(" unresolved");
- }
-
- log_start();
- log_print(" loaders: ");
- for (lden = clsen->loaders; lden; lden = lden->next) {
- log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
- }
- log_finish();
-
- log_start();
- log_print(" constraints: ");
- for (lden = clsen->constraints; lden; lden = lden->next) {
- log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
- }
- log_finish();
- }
- }
-
- if (only)
- break;
- }
- fprintf(file, "\n==============================================================\n\n");
-
- CLASSCACHE_UNLOCK();
-}
-#endif /* NDEBUG */
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/classcache.cpp - loaded class cache and loading constraints
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.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.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/options.h"
+#include "vm/utf8.h"
+
+
+/*************************************************************************
+
+ Class Cache
+
+ The classcache has two functions:
+
+ 1) caching the resolution of class references
+ 2) storing and checking loading constraints
+
+ We will use the following terms in this description:
+
+ N a class name: a utf string
+ (N,L) a class reference with initiating loader L and class name N
+ C a class (object): the result of resolving a reference (N,L)
+ We will write resultion as
+ C = *(N,L)
+ (N,L1,L2) a loading constraint indicating that (N,L1) and (N,L2) must
+ resolve to the same class C. So (N,L1,L2) means
+ *(N,L1) = *(N,L2)
+
+ The functions of the classcache require:
+
+ 1) a mapping (N,L) |--> C for looking up prior resolution results.
+ 2) storing the current set of loading constraints { (N,L1,L2) }
+
+ These functions can be rearranged like that:
+
+ a mapping N |--> (a mapping L |--> C or NULL,
+ a set of constraints {(L1,L2)})
+
+ Thus we can treat the mapping and constraints for each name N
+ separately. The implementation does this by keeping a hash table
+ mapping a name N to a `classcache_name_entry` which contains all
+ info with respect to N.
+
+ For a class name N we can define an equivalence relation ~N~ on
+ class loaders:
+
+ L1 ~N~ L2 <==> *(N,L1) = *(N,L2)
+
+ A loading constraint (N,L1,L2) implies L1 ~N~ L2.
+
+ Also, if two references (N,L1) and (N,L2) resolve to the same class C
+ we have L1 ~N~ L2 because class loaders are required to return
+ consistent resolutions for a name N [XXX].
+
+ A `classcache_name_entry` keeps a set of tuples { (Cx,IL,CL) },
+ where
+ Cx...is a class C or NULL
+ IL...is the set of initiating loaders
+ CL...is the set of constrained loaders
+
+ Such a tuple is called `classcache_class_entry` in the source code.
+
+ The following holds for each tuple (Cx,IL,CL):
+
+ . (Cx is NULL) implies IL = {}.
+
+ . If Cx is a class, IL is the set of loaders that have been
+ recorded as initiating loaders for Cx. IL may be the
+ empty set {} in case Cx has already been defined but no
+ initiating loader has been recorded, yet.
+
+ . (IL u CL) is a subset of an equivalence class of ~N~.
+
+ (This means that all loaders in IL and CL must resolve
+ the name N to the same class.)
+
+ The following holds for the set of tuples { (Cx,IL,CL) }:
+
+ . For a given class C there is at most one tuple with Cx = C
+ in the set. (There may be an arbitrary number of tuples
+ with Cx = NULL, however.)
+
+ . For a given loader L there is at most one tuple with
+ L in (IL u CL).
+
+ The implementation stores sets of loaders as linked lists of
+ `classcache_loader_entry`s.
+
+ Comments about manipulating the classcache can be found in the
+ individual functions below.
+
+*************************************************************************/
+
+
+/* initial number of slots in the classcache hash table */
+#define CLASSCACHE_INIT_SIZE 2048
+
+/*============================================================================*/
+/* DEBUG HELPERS */
+/*============================================================================*/
+
+/* #define CLASSCACHE_VERBOSE */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*============================================================================*/
+/* STATISTICS */
+/*============================================================================*/
+
+/*#define CLASSCACHE_STATS*/
+
+#ifdef CLASSCACHE_STATS
+static int stat_classnames_stored = 0;
+static int stat_classes_stored = 0;
+static int stat_trivial_constraints = 0;
+static int stat_nontriv_constraints = 0;
+static int stat_nontriv_constraints_both = 0;
+static int stat_nontriv_constraints_merged = 0;
+static int stat_nontriv_constraints_one = 0;
+static int stat_nontriv_constraints_none = 0;
+static int stat_new_loader_entry = 0;
+static int stat_merge_class_entries = 0;
+static int stat_merge_loader_entries = 0;
+static int stat_lookup = 0;
+static int stat_lookup_class_entry_checked = 0;
+static int stat_lookup_loader_checked = 0;
+static int stat_lookup_name = 0;
+static int stat_lookup_name_entry = 0;
+static int stat_lookup_name_notfound = 0;
+static int stat_lookup_new_name = 0;
+static int stat_lookup_new_name_entry = 0;
+static int stat_lookup_new_name_collisions = 0;
+static int stat_rehash_names = 0;
+static int stat_rehash_names_collisions = 0;
+
+#define CLASSCACHE_COUNT(cnt) (cnt)++
+#define CLASSCACHE_COUNTIF(cond,cnt) do{if(cond) (cnt)++;} while(0)
+
+void classcache_print_statistics(FILE *file) {
+ fprintf(file,"classnames stored : %8d\n",stat_classnames_stored);
+ fprintf(file,"classes stored : %8d\n",stat_classes_stored);
+ fprintf(file,"trivial constraints : %8d\n",stat_trivial_constraints);
+ fprintf(file,"non-triv constraints: %8d\n",stat_nontriv_constraints);
+ fprintf(file," both loaders rec.: %8d\n",stat_nontriv_constraints_both);
+ fprintf(file," merged : %8d\n",stat_nontriv_constraints_merged);
+ fprintf(file," one loader rec. : %8d\n",stat_nontriv_constraints_one);
+ fprintf(file," no loaders rec. : %8d\n",stat_nontriv_constraints_none);
+ fprintf(file,"new loader entries : %8d\n",stat_new_loader_entry);
+ fprintf(file,"merge class entries : %8d\n",stat_merge_class_entries);
+ fprintf(file,"merge loader entries: %8d\n",stat_merge_loader_entries);
+ fprintf(file,"lookups : %8d\n",stat_lookup);
+ fprintf(file," class entries ckd: %8d\n",stat_lookup_class_entry_checked);
+ fprintf(file," loader checked : %8d\n",stat_lookup_loader_checked);
+ fprintf(file,"lookup name : %8d\n",stat_lookup_name);
+ fprintf(file," entries checked : %8d\n",stat_lookup_name_entry);
+ fprintf(file," not found : %8d\n",stat_lookup_name_notfound);
+ fprintf(file,"lookup (new) name : %8d\n",stat_lookup_new_name);
+ fprintf(file," entries checked : %8d\n",stat_lookup_new_name_entry);
+ fprintf(file," new collisions : %8d\n",stat_lookup_new_name_collisions);
+ fprintf(file,"names rehashed : %8d times\n",stat_rehash_names);
+ fprintf(file," collisions : %8d\n",stat_rehash_names_collisions);
+}
+#else
+#define CLASSCACHE_COUNT(cnt)
+#define CLASSCACHE_COUNTIF(cond,cnt)
+#endif
+
+/*============================================================================*/
+/* THREAD-SAFE LOCKING */
+/*============================================================================*/
+
+ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+ /* CAUTION: The static functions below are */
+ /* NOT synchronized! */
+ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+#if defined(ENABLE_THREADS)
+# define CLASSCACHE_LOCK() classcache_hashtable_mutex->lock();
+# define CLASSCACHE_UNLOCK() classcache_hashtable_mutex->unlock();
+#else
+# define CLASSCACHE_LOCK()
+# define CLASSCACHE_UNLOCK()
+#endif
+
+/*============================================================================*/
+/* GLOBAL VARIABLES */
+/*============================================================================*/
+
+hashtable hashtable_classcache;
+
+#if defined(ENABLE_THREADS)
+static Mutex *classcache_hashtable_mutex;
+#endif
+
+
+/*============================================================================*/
+/* */
+/*============================================================================*/
+
+/* prototypes */
+
+static void classcache_free_class_entry(classcache_class_entry *clsen);
+static void classcache_remove_class_entry(classcache_name_entry *en,
+ classcache_class_entry *clsen);
+
+/* hash function to use */
+
+#define CLASSCACHE_HASH utf_full_hashkey
+
+/* classcache_init *************************************************************
+
+ Initialize the class cache
+
+ Note: NOT synchronized!
+
+*******************************************************************************/
+
+bool classcache_init(void)
+{
+ TRACESUBSYSTEMINITIALIZATION("classcache_init");
+
+ /* create the hashtable */
+
+ hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
+
+#if defined(ENABLE_THREADS)
+ /* create utf hashtable mutex */
+
+ classcache_hashtable_mutex = new Mutex();
+#endif
+
+ /* everything's ok */
+
+ return true;
+}
+
+/* classcache_new_loader_entry *************************************************
+
+ Create a new classcache_loader_entry struct
+ (internally used helper function)
+
+ IN:
+ loader...........the ClassLoader object
+ next.............the next classcache_loader_entry
+
+ RETURN VALUE:
+ the new classcache_loader_entry
+
+*******************************************************************************/
+
+static classcache_loader_entry * classcache_new_loader_entry(
+ classloader_t * loader,
+ classcache_loader_entry * next)
+{
+ classcache_loader_entry *lden;
+
+ lden = NEW(classcache_loader_entry);
+ lden->loader = loader;
+ lden->next = next;
+ CLASSCACHE_COUNT(stat_new_loader_entry);
+
+ return lden;
+}
+
+/* classcache_merge_loaders ****************************************************
+
+ Merge two lists of loaders into one
+ (internally used helper function)
+
+ IN:
+ lista............first list (may be NULL)
+ listb............second list (may be NULL)
+
+ RETURN VALUE:
+ the merged list (may be NULL)
+
+ NOTE:
+ The lists given as arguments are destroyed!
+
+*******************************************************************************/
+
+static classcache_loader_entry * classcache_merge_loaders(
+ classcache_loader_entry * lista,
+ classcache_loader_entry * listb)
+{
+ classcache_loader_entry *result;
+ classcache_loader_entry *ldenA;
+ classcache_loader_entry *ldenB;
+ classcache_loader_entry **chain;
+
+ CLASSCACHE_COUNT(stat_merge_loader_entries);
+
+ /* XXX This is a quadratic algorithm. If this ever
+ * becomes a problem, the loader lists should be
+ * stored as sorted lists and merged in linear time. */
+
+ result = NULL;
+ chain = &result;
+
+ for (ldenA = lista; ldenA; ldenA = ldenA->next) {
+
+ for (ldenB = listb; ldenB; ldenB = ldenB->next) {
+ if (ldenB->loader == ldenA->loader)
+ goto common_element;
+ }
+
+ /* this loader is only in lista */
+ *chain = ldenA;
+ chain = &(ldenA->next);
+
+ common_element:
+ /* XXX free the duplicated element */
+ ;
+ }
+
+ /* concat listb to the result */
+ *chain = listb;
+
+ return result;
+}
+
+/* classcache_merge_class_entries **********************************************
+
+ Merge two `classcache_class_entry`s into one.
+ (internally used helper function)
+
+ IN:
+ en...............the classcache_name_entry containing both class entries
+ clsenA...........first class entry, will receive the result
+ clsenB...........second class entry
+
+ PRE-CONDITION:
+ Either both entries must have the same classobj, or one of them has
+ classobj == NULL.
+
+ NOTE:
+ clsenB is freed by this function!
+
+*******************************************************************************/
+
+static void classcache_merge_class_entries(classcache_name_entry *en,
+ classcache_class_entry *clsenA,
+ classcache_class_entry *clsenB)
+{
+#ifdef CLASSCACHE_VERBOSE
+ char logbuffer[1024];
+#endif
+
+ assert(en);
+ assert(clsenA);
+ assert(clsenB);
+ assert(!clsenA->classobj || !clsenB->classobj || clsenA->classobj == clsenB->classobj);
+
+#ifdef CLASSCACHE_VERBOSE
+ 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_cat_classname(logbuffer, clsenA->classobj->name);
+ if (clsenB->classobj)
+ utf_cat_classname(logbuffer, clsenB->classobj->name);
+ log_println(logbuffer);
+#endif
+
+ CLASSCACHE_COUNT(stat_merge_class_entries);
+
+ /* clsenB will be merged into clsenA */
+ clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
+ clsenB->loaders = NULL; /* these have been freed or reused */
+
+ clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
+ clsenB->constraints);
+ clsenB->constraints = NULL; /* these have been freed or reused */
+
+ if (!clsenA->classobj)
+ clsenA->classobj = clsenB->classobj;
+
+ /* remove clsenB from the list of class entries */
+ classcache_remove_class_entry(en, clsenB);
+}
+
+
+/* classcache_lookup_name ******************************************************
+
+ Lookup a name in the first level of the cache
+ (internally used helper function)
+
+ IN:
+ name.............the name to look up
+
+ RETURN VALUE:
+ a pointer to the classcache_name_entry for this name, or
+ null if no entry was found.
+
+*******************************************************************************/
+
+static classcache_name_entry *classcache_lookup_name(utf *name)
+{
+ classcache_name_entry *c; /* hash table element */
+ u4 key; /* hashkey computed from classname */
+ u4 slot; /* slot in hashtable */
+
+ CLASSCACHE_COUNT(stat_lookup_name);
+
+ key = CLASSCACHE_HASH(name->text, (u4) name->blength);
+ slot = key & (hashtable_classcache.size - 1);
+ c = (classcache_name_entry*) hashtable_classcache.ptr[slot];
+
+ /* search external hash chain for the entry */
+
+ while (c) {
+ /* entry found in hashtable */
+ CLASSCACHE_COUNT(stat_lookup_name_entry);
+
+ if (c->name == name)
+ return c;
+
+ c = c->hashlink; /* next element in external chain */
+ }
+
+ /* not found */
+
+ CLASSCACHE_COUNT(stat_lookup_name_notfound);
+ return NULL;
+}
+
+
+/* classcache_new_name *********************************************************
+
+ Return a classcache_name_entry for the given name. The entry is created
+ if it is not already in the cache.
+ (internally used helper function)
+
+ IN:
+ name.............the name to look up / create an entry for
+
+ RETURN VALUE:
+ a pointer to the classcache_name_entry for this name
+
+*******************************************************************************/
+
+static classcache_name_entry *classcache_new_name(utf *name)
+{
+ classcache_name_entry *c; /* hash table element */
+ u4 key; /* hashkey computed from classname */
+ u4 slot; /* slot in hashtable */
+ u4 i;
+
+ CLASSCACHE_COUNT(stat_lookup_new_name);
+
+ key = CLASSCACHE_HASH(name->text, (u4) name->blength);
+ slot = key & (hashtable_classcache.size - 1);
+ c = (classcache_name_entry*) hashtable_classcache.ptr[slot];
+
+ /* search external hash chain for the entry */
+
+ while (c) {
+ /* entry found in hashtable */
+ CLASSCACHE_COUNT(stat_lookup_new_name_entry);
+
+ if (c->name == name)
+ return c;
+
+ c = c->hashlink; /* next element in external chain */
+ }
+
+ /* location in hashtable found, create new entry */
+
+ c = NEW(classcache_name_entry);
+
+ c->name = name;
+ c->classes = NULL;
+
+ /* insert entry into hashtable */
+ c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
+ CLASSCACHE_COUNTIF(c->hashlink,stat_lookup_new_name_collisions);
+ hashtable_classcache.ptr[slot] = c;
+
+ /* update number of hashtable-entries */
+ hashtable_classcache.entries++;
+ CLASSCACHE_COUNT(stat_classnames_stored);
+
+ if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
+ /* reorganization of hashtable */
+
+ classcache_name_entry *c2;
+ hashtable newhash; /* the new hashtable */
+
+ CLASSCACHE_COUNT(stat_rehash_names);
+
+ /* create new hashtable, double the size */
+
+ hashtable_create(&newhash, hashtable_classcache.size * 2);
+ newhash.entries = hashtable_classcache.entries;
+
+ /* transfer elements to new hashtable */
+
+ for (i = 0; i < hashtable_classcache.size; i++) {
+ c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
+ while (c2) {
+ classcache_name_entry *nextc = c2->hashlink;
+ u4 newslot =
+ (CLASSCACHE_HASH(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
+
+ c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
+ CLASSCACHE_COUNTIF(c2->hashlink,stat_rehash_names_collisions);
+ newhash.ptr[newslot] = c2;
+
+ c2 = nextc;
+ }
+ }
+
+ /* dispose old table */
+
+ MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
+ hashtable_classcache = newhash;
+ }
+
+ return c;
+}
+
+
+/* classcache_lookup ***********************************************************
+
+ Lookup a possibly loaded class
+
+ IN:
+ initloader.......initiating loader for resolving the class name
+ classname........class name to look up
+
+ RETURN VALUE:
+ The return value is a pointer to the cached class object,
+ or NULL, if the class is not in the cache.
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+classinfo *classcache_lookup(classloader_t *initloader, utf *classname)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ classcache_loader_entry *lden;
+ classinfo *cls = NULL;
+
+ CLASSCACHE_LOCK();
+
+ CLASSCACHE_COUNT(stat_lookup);
+ en = classcache_lookup_name(classname);
+
+ if (en) {
+ /* iterate over all class entries */
+
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+ CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
+ /* check if this entry has been loaded by initloader */
+
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ CLASSCACHE_COUNT(stat_lookup_loader_checked);
+ if (lden->loader == initloader) {
+ /* found the loaded class entry */
+
+ assert(clsen->classobj);
+ cls = clsen->classobj;
+ goto found;
+ }
+ }
+ }
+ }
+
+ found:
+ CLASSCACHE_UNLOCK();
+ return cls;
+}
+
+
+/* classcache_lookup_defined ***************************************************
+
+ Lookup a class with the given name and defining loader
+
+ IN:
+ defloader........defining loader
+ classname........class name
+
+ RETURN VALUE:
+ The return value is a pointer to the cached class object,
+ or NULL, if the class is not in the cache.
+
+*******************************************************************************/
+
+classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ classinfo *cls = NULL;
+
+ CLASSCACHE_LOCK();
+
+ en = classcache_lookup_name(classname);
+
+ if (en) {
+ /* iterate over all class entries */
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+ if (!clsen->classobj)
+ continue;
+
+ /* check if this entry has been defined by defloader */
+ if (clsen->classobj->classloader == defloader) {
+ cls = clsen->classobj;
+ goto found;
+ }
+ }
+ }
+
+ found:
+ CLASSCACHE_UNLOCK();
+ return cls;
+}
+
+
+/* classcache_lookup_defined_or_initiated **************************************
+
+ Lookup a class that has been defined or initiated by the given loader
+
+ IN:
+ loader...........defining or initiating loader
+ classname........class name to look up
+
+ RETURN VALUE:
+ The return value is a pointer to the cached class object,
+ or NULL, if the class is not in the cache.
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+classinfo *classcache_lookup_defined_or_initiated(classloader_t *loader,
+ utf *classname)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ classcache_loader_entry *lden;
+ classinfo *cls = NULL;
+
+ CLASSCACHE_LOCK();
+
+ en = classcache_lookup_name(classname);
+
+ if (en) {
+ /* iterate over all class entries */
+
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+
+ /* check if this entry has been defined by loader */
+ if (clsen->classobj && clsen->classobj->classloader == loader) {
+ cls = clsen->classobj;
+ goto found;
+ }
+
+ /* check if this entry has been initiated by loader */
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ if (lden->loader == loader) {
+ /* found the loaded class entry */
+
+ assert(clsen->classobj);
+ cls = clsen->classobj;
+ goto found;
+ }
+ }
+ }
+ }
+
+ found:
+ CLASSCACHE_UNLOCK();
+ return cls;
+}
+
+
+/* classcache_store ************************************************************
+
+ Store a loaded class. If a class of the same name has already been stored
+ with the same initiating loader, then the given class CLS is freed (if
+ possible) and the previously stored class is returned.
+
+ IN:
+ initloader.......initiating loader used to load the class
+ (may be NULL indicating the bootstrap loader)
+ cls..............class object to cache
+ mayfree..........true if CLS may be freed in case another class is
+ returned
+
+ RETURN VALUE:
+ cls..............everything ok, the class was stored in the cache,
+ other classinfo..another class with the same (initloader,name) has been
+ stored earlier. CLS has been freed[1] and the earlier
+ stored class is returned.
+ NULL.............an exception has been thrown.
+
+ Note: synchronized with global tablelock
+
+ [1]...in case MAYFREE is true
+
+*******************************************************************************/
+
+classinfo *classcache_store(classloader_t *initloader, classinfo *cls,
+ bool mayfree)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+ classcache_class_entry *clsenB;
+ classcache_loader_entry *lden;
+#ifdef CLASSCACHE_VERBOSE
+ char logbuffer[1024];
+#endif
+
+ assert(cls);
+ assert(cls->state & CLASS_LOADED);
+
+ CLASSCACHE_LOCK();
+
+#ifdef CLASSCACHE_VERBOSE
+ sprintf(logbuffer,"classcache_store (%p,%d,%p=", (void*)initloader,mayfree,(void*)cls);
+ utf_cat_classname(logbuffer, cls->name);
+ strcat(logbuffer,")");
+ log_println(logbuffer);
+#endif
+
+ en = classcache_new_name(cls->name);
+
+ assert(en);
+
+ /* iterate over all class entries */
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+
+ /* check if this entry has already been loaded by initloader */
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ if (lden->loader == initloader) {
+ if (clsen->classobj != cls) {
+ /* 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
+ log_println("replacing %p with earlier loaded class %p",cls,clsen->classobj);
+#endif
+ assert(clsen->classobj);
+ if (mayfree)
+ class_free(cls);
+ cls = clsen->classobj;
+ }
+ goto return_success;
+ }
+ }
+
+ /* {This entry has not been resolved with initloader} */
+
+ /* check if initloader is constrained to this entry */
+ for (lden = clsen->constraints; lden; lden = lden->next) {
+ if (lden->loader == initloader) {
+ /* we have to use this entry. check if it has been resolved */
+ if (clsen->classobj) {
+ /* check if is has already been resolved to another class */
+ if (clsen->classobj != cls) {
+ /* a loading constraint is violated */
+ exceptions_throw_linkageerror("loading constraint violated: ", cls);
+ goto return_exception;
+ }
+
+ /* record initloader as initiating loader */
+ clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+ goto return_success;
+ }
+
+ /* {this is the first resolution for this entry} */
+ /* record initloader as initiating loader */
+ clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+
+ /* maybe we can merge this entry with another one */
+ for (clsenB = en->classes; clsenB; clsenB = clsenB->next) {
+ /* we dont want the entry that we have already */
+ if (clsenB->classobj == cls) {
+ /* this entry has the same classobj. let's merge them */
+ classcache_merge_class_entries(en,clsen,clsenB);
+ goto return_success;
+ }
+ }
+
+ /* record the loaded class object */
+ clsen->classobj = cls;
+ CLASSCACHE_COUNT(stat_classes_stored);
+
+ /* done */
+ goto return_success;
+ }
+ }
+
+ }
+
+ /* {There is no class entry containing initloader as initiating
+ * or constrained loader.} */
+
+ /* we look for a class entry with the same classobj we want to store */
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+ if (clsen->classobj == cls) {
+ /* this entry is about the same classobj. let's use it */
+ /* check if this entry has already been loaded by initloader */
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ if (lden->loader == initloader)
+ goto return_success;
+ }
+ clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+ goto return_success;
+ }
+ }
+
+ /* create a new class entry for this class object with */
+ /* initiating loader initloader */
+
+ clsen = NEW(classcache_class_entry);
+ clsen->classobj = cls;
+ clsen->loaders = classcache_new_loader_entry(initloader, NULL);
+ clsen->constraints = NULL;
+
+ clsen->next = en->classes;
+ en->classes = clsen;
+ CLASSCACHE_COUNT(stat_classes_stored);
+
+ return_success:
+#ifdef CLASSCACHE_VERBOSE
+ classcache_debug_dump(stdout,cls->name);
+#endif
+ CLASSCACHE_UNLOCK();
+ return cls;
+
+ return_exception:
+ CLASSCACHE_UNLOCK();
+ return NULL; /* exception */
+}
+
+/* classcache_store_unique *****************************************************
+
+ Store a loaded class as loaded by the bootstrap loader. This is a wrapper
+ aroung classcache_store that throws an exception if a class with the same
+ name has already been loaded by the bootstrap loader.
+
+ This function is used to register a few special classes during startup.
+ It should not be used otherwise.
+
+ IN:
+ cls..............class object to cache
+
+ RETURN VALUE:
+ true.............everything ok, the class was stored.
+ false............an exception has been thrown.
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+bool classcache_store_unique(classinfo *cls)
+{
+ classinfo *result;
+
+ result = classcache_store(NULL,cls,false);
+ if (result == NULL)
+ return false;
+
+ if (result != cls) {
+ exceptions_throw_internalerror("class already stored in the class cache");
+ return false;
+ }
+
+ return true;
+}
+
+/* classcache_store_defined ****************************************************
+
+ Store a loaded class after it has been defined. If the class has already
+ been defined by the same defining loader in another thread, free the given
+ class and returned the one which has been defined earlier.
+
+ IN:
+ cls..............class object to store. classloader must be set
+ (classloader may be NULL, for bootloader)
+
+ RETURN VALUE:
+ cls..............everything ok, the class was stored the cache,
+ other classinfo..the class had already been defined, CLS was freed, the
+ class which was defined earlier is returned,
+ NULL.............an exception has been thrown.
+
+*******************************************************************************/
+
+classinfo *classcache_store_defined(classinfo *cls)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsen;
+#ifdef CLASSCACHE_VERBOSE
+ char logbuffer[1024];
+#endif
+
+ assert(cls);
+ assert(cls->state & CLASS_LOADED);
+
+ CLASSCACHE_LOCK();
+
+#ifdef CLASSCACHE_VERBOSE
+ sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
+ utf_cat_classname(logbuffer, cls->name);
+ strcat(logbuffer,")");
+ log_println(logbuffer);
+#endif
+
+ en = classcache_new_name(cls->name);
+
+ assert(en);
+
+ /* iterate over all class entries */
+ for (clsen = en->classes; clsen; clsen = clsen->next) {
+
+ /* check if this class has been defined by the same classloader */
+ if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
+ /* we found an earlier definition, delete the newer one */
+ /* (if it is a different classinfo) */
+ if (clsen->classobj != cls) {
+#ifdef CLASSCACHE_VERBOSE
+ log_println("replacing %p with earlier defined class %p",cls,clsen->classobj);
+#endif
+ class_free(cls);
+ cls = clsen->classobj;
+ }
+ goto return_success;
+ }
+ }
+
+ /* create a new class entry for this class object */
+ /* the list of initiating loaders is empty at this point */
+
+ clsen = NEW(classcache_class_entry);
+ clsen->classobj = cls;
+ clsen->loaders = NULL;
+ clsen->constraints = NULL;
+
+ clsen->next = en->classes;
+ en->classes = clsen;
+ CLASSCACHE_COUNT(stat_classes_stored);
+
+return_success:
+#ifdef CLASSCACHE_VERBOSE
+ classcache_debug_dump(stdout,cls->name);
+#endif
+ CLASSCACHE_UNLOCK();
+ return cls;
+}
+
+/* classcache_find_loader ******************************************************
+
+ Find the class entry loaded by or constrained to a given loader
+ (internally used helper function)
+
+ IN:
+ entry............the classcache_name_entry
+ loader...........the loader to look for
+
+ RETURN VALUE:
+ the classcache_class_entry for the given loader, or
+ NULL if no entry was found
+
+*******************************************************************************/
+
+static classcache_class_entry * classcache_find_loader(
+ classcache_name_entry * entry,
+ classloader_t * loader)
+{
+ classcache_class_entry *clsen;
+ classcache_loader_entry *lden;
+
+ assert(entry);
+
+ /* iterate over all class entries */
+ for (clsen = entry->classes; clsen; clsen = clsen->next) {
+
+ /* check if this entry has already been loaded by initloader */
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ if (lden->loader == loader)
+ return clsen; /* found */
+ }
+
+ /* check if loader is constrained to this entry */
+ for (lden = clsen->constraints; lden; lden = lden->next) {
+ if (lden->loader == loader)
+ return clsen; /* found */
+ }
+ }
+
+ /* not found */
+ return NULL;
+}
+
+/* classcache_free_class_entry *************************************************
+
+ Free the memory used by a class entry
+
+ IN:
+ clsen............the classcache_class_entry to free
+
+*******************************************************************************/
+
+static void classcache_free_class_entry(classcache_class_entry * clsen)
+{
+ classcache_loader_entry *lden;
+ classcache_loader_entry *next;
+
+ assert(clsen);
+
+ for (lden = clsen->loaders; lden; lden = next) {
+ next = lden->next;
+ FREE(lden, classcache_loader_entry);
+ }
+ for (lden = clsen->constraints; lden; lden = next) {
+ next = lden->next;
+ FREE(lden, classcache_loader_entry);
+ }
+
+ FREE(clsen, classcache_class_entry);
+}
+
+/* classcache_remove_class_entry ***********************************************
+
+ Remove a classcache_class_entry from the list of possible resolution of
+ a name entry
+ (internally used helper function)
+
+ IN:
+ entry............the classcache_name_entry
+ clsen............the classcache_class_entry to remove
+
+*******************************************************************************/
+
+static void classcache_remove_class_entry(classcache_name_entry * entry,
+ classcache_class_entry * clsen)
+{
+ classcache_class_entry **chain;
+
+ assert(entry);
+ assert(clsen);
+
+ chain = &(entry->classes);
+ while (*chain) {
+ if (*chain == clsen) {
+ *chain = clsen->next;
+ classcache_free_class_entry(clsen);
+ return;
+ }
+ chain = &((*chain)->next);
+ }
+}
+
+/* classcache_free_name_entry **************************************************
+
+ Free the memory used by a name entry
+
+ IN:
+ entry............the classcache_name_entry to free
+
+*******************************************************************************/
+
+static void classcache_free_name_entry(classcache_name_entry * entry)
+{
+ classcache_class_entry *clsen;
+ classcache_class_entry *next;
+
+ assert(entry);
+
+ for (clsen = entry->classes; clsen; clsen = next) {
+ next = clsen->next;
+ classcache_free_class_entry(clsen);
+ }
+
+ FREE(entry, classcache_name_entry);
+}
+
+/* classcache_free *************************************************************
+
+ Free the memory used by the class cache
+
+ NOTE:
+ The class cache may not be used any more after this call, except
+ when it is reinitialized with classcache_init.
+
+ Note: NOT synchronized!
+
+*******************************************************************************/
+
+void classcache_free(void)
+{
+ u4 slot;
+ classcache_name_entry *entry;
+ classcache_name_entry *next;
+
+ for (slot = 0; slot < hashtable_classcache.size; ++slot) {
+ for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
+ next = entry->hashlink;
+ classcache_free_name_entry(entry);
+ }
+ }
+
+ MFREE(hashtable_classcache.ptr, void*, hashtable_classcache.size);
+ hashtable_classcache.size = 0;
+ hashtable_classcache.entries = 0;
+ hashtable_classcache.ptr = NULL;
+}
+
+/* classcache_add_constraint ***************************************************
+
+ Add a loading constraint
+
+ IN:
+ a................first initiating loader
+ b................second initiating loader
+ classname........class name
+
+ RETURN VALUE:
+ true.............everything ok, the constraint has been added,
+ false............an exception has been thrown.
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraint(classloader_t * a,
+ classloader_t * b,
+ utf * classname)
+{
+ classcache_name_entry *en;
+ classcache_class_entry *clsenA;
+ classcache_class_entry *clsenB;
+
+ assert(classname);
+
+#ifdef CLASSCACHE_VERBOSE
+ 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 (a == b) {
+ CLASSCACHE_COUNT(stat_trivial_constraints);
+ return true;
+ }
+
+ CLASSCACHE_LOCK();
+
+ en = classcache_new_name(classname);
+
+ assert(en);
+ CLASSCACHE_COUNT(stat_nontriv_constraints);
+
+ /* find the entry loaded by / constrained to each loader */
+ clsenA = classcache_find_loader(en, a);
+ clsenB = classcache_find_loader(en, b);
+
+ if (clsenA && clsenB) {
+ /* { both loaders have corresponding entries } */
+ CLASSCACHE_COUNT(stat_nontriv_constraints_both);
+
+ /* if the entries are the same, the constraint is already recorded */
+ if (clsenA == clsenB)
+ goto return_success;
+
+ /* check if the entries can be merged */
+ if (clsenA->classobj && clsenB->classobj
+ && clsenA->classobj != clsenB->classobj) {
+ /* no, the constraint is violated */
+ exceptions_throw_linkageerror("loading constraint violated: ",
+ clsenA->classobj);
+ goto return_exception;
+ }
+
+ /* yes, merge the entries */
+ classcache_merge_class_entries(en,clsenA,clsenB);
+ CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
+ }
+ else {
+ /* { at most one of the loaders has a corresponding entry } */
+
+ /* set clsenA to the single class entry we have */
+ if (!clsenA)
+ clsenA = clsenB;
+
+ if (!clsenA) {
+ /* { no loader has a corresponding entry } */
+ CLASSCACHE_COUNT(stat_nontriv_constraints_none);
+
+ /* create a new class entry with the constraint (a,b,en->name) */
+ clsenA = NEW(classcache_class_entry);
+ clsenA->classobj = NULL;
+ clsenA->loaders = NULL;
+ clsenA->constraints = classcache_new_loader_entry(b, NULL);
+ clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
+
+ clsenA->next = en->classes;
+ en->classes = clsenA;
+ }
+ else {
+ CLASSCACHE_COUNT(stat_nontriv_constraints_one);
+
+ /* make b the loader that has no corresponding entry */
+ if (clsenB)
+ b = a;
+
+ /* loader b must be added to entry clsenA */
+ clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
+ }
+ }
+
+ return_success:
+ CLASSCACHE_UNLOCK();
+ return true;
+
+ return_exception:
+ CLASSCACHE_UNLOCK();
+ return false; /* exception */
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+/* classcache_add_constraints_for_params ***************************************
+
+ Add loading constraints for the parameters and return type of
+ the given method.
+
+ IN:
+ a................first initiating loader
+ b................second initiating loader
+ m................methodinfo
+
+ RETURN VALUE:
+ true.............everything ok, the constraints have been added,
+ false............an exception has been thrown.
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraints_for_params(classloader_t * a,
+ classloader_t * b,
+ methodinfo *m)
+{
+ methoddesc *md;
+ typedesc *td;
+ s4 i;
+
+ /* a constraint with a == b is trivially satisfied */
+
+ if (a == b) {
+ return true;
+ }
+
+ /* get the parsed descriptor */
+
+ assert(m);
+ md = m->parseddesc;
+ assert(md);
+
+ /* constrain the return type */
+
+ if (md->returntype.type == TYPE_ADR) {
+ if (!classcache_add_constraint(a, b, md->returntype.classref->name))
+ return false; /* exception */
+ }
+
+ /* constrain each reference type used in the parameters */
+
+ td = md->paramtypes;
+ i = md->paramcount;
+ for (; i--; td++) {
+ if (td->type != TYPE_ADR)
+ continue;
+
+ if (!classcache_add_constraint(a, b, td->classref->name))
+ return false; /* exception */
+ }
+
+ /* everything ok */
+ return true;
+}
+#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 = (classcache_name_entry*) 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 = (classcache_name_entry*) 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_debug_dump *******************************************************
+
+ Print the contents of the loaded class cache to a stream
+
+ IN:
+ file.............output stream
+ only.............if != NULL, only print entries for this name
+ (Currently we print also the rest of the hash chain to
+ get a feel for the average length of hash chains.)
+
+ Note: synchronized with global tablelock
+
+*******************************************************************************/
+
+#ifndef NDEBUG
+void classcache_debug_dump(FILE * file,utf *only)
+{
+ classcache_name_entry *c;
+ classcache_class_entry *clsen;
+ classcache_loader_entry *lden;
+ u4 slot;
+
+ CLASSCACHE_LOCK();
+
+ 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);
+ slot = 0; /* avoid compiler warning */
+ goto dump_it;
+ }
+
+ for (slot = 0; slot < hashtable_classcache.size; ++slot) {
+ c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
+
+dump_it:
+ for (; c; c = c->hashlink) {
+ utf_fprint_printable_ascii_classname(file, c->name);
+ fprintf(file, "\n");
+
+ /* iterate over all class entries */
+ for (clsen = c->classes; clsen; clsen = clsen->next) {
+ if (clsen->classobj) {
+ log_println(" loaded %p", (void *) clsen->classobj);
+ }
+ else {
+ log_println(" unresolved");
+ }
+
+ log_start();
+ log_print(" loaders: ");
+ for (lden = clsen->loaders; lden; lden = lden->next) {
+ log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
+ }
+ log_finish();
+
+ log_start();
+ log_print(" constraints: ");
+ for (lden = clsen->constraints; lden; lden = lden->next) {
+ log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
+ }
+ log_finish();
+ }
+ }
+
+ if (only)
+ break;
+ }
+ fprintf(file, "\n==============================================================\n\n");
+
+ CLASSCACHE_UNLOCK();
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* NDEBUG */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+++ /dev/null
-/* src/vm/classcache.h - loaded class cache and loading constraints
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _CLASSCACHE_H
-#define _CLASSCACHE_H
-
-#include "config.h"
-
-#include "vm/types.h"
-
-#include <stdio.h> /* for FILE */
-
-#include "toolbox/hashtable.h"
-
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/loader.hpp"
-#include "vm/references.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* forward declarations *******************************************************/
-
-typedef struct classcache_name_entry classcache_name_entry;
-typedef struct classcache_class_entry classcache_class_entry;
-typedef struct classcache_loader_entry classcache_loader_entry;
-
-/* global variables ***********************************************************/
-
-extern hashtable hashtable_classcache;
-
-
-/* structs ********************************************************************/
-
-/*----------------------------------------------------------------------------*/
-/* The Loaded Class Cache */
-/* */
-/* The loaded class cache is implemented as a two-level data structure. */
-/* */
-/* The first level is a hash table indexed by class names. For each class */
-/* name in the cache there is a classcache_name_entry, which collects all */
-/* information about classes with this class name. */
-/* */
-/* Second level: For each classcache_name_entry there is a list of */
-/* classcache_class_entry:s representing the possible different resolutions */
-/* of the class name. */
-/* */
-/* A classcache_class_entry records the following: */
-/* */
-/* - the loaded class object, if this entry has been resolved, otherwise NULL */
-/* - the list of initiating loaders which have resolved the class name to */
-/* this class object */
-/* - the list of initiating loaders which are constrained to resolve this */
-/* class name to this class object in the future */
-/* */
-/* The classcache_class_entry:s approximate the equivalence classes created */
-/* by the loading constraints and the equivalence of loaded classes. */
-/* */
-/* When a loading constraint (loaderA,loaderB,NAME) is added, then the */
-/* classcache_class_entry:s for NAME containing loaderA and loaderB resp. */
-/* must be merged into one entry. If this is impossible, because the entries */
-/* have already been resolved to different class objects, then the constraint */
-/* is violated and an expception must be thrown. */
-/*----------------------------------------------------------------------------*/
-
-
-/* classcache_name_entry
- *
- * For each classname a classcache_name_entry struct is created.
- */
-
-struct classcache_name_entry
-{
- utf *name; /* class name */
- classcache_name_entry *hashlink; /* link for external chaining */
- classcache_class_entry *classes; /* equivalence classes for this name*/
-};
-
-struct classcache_class_entry
-{
- classinfo *classobj; /* the loaded class object, or NULL */
- classcache_loader_entry *loaders;
- classcache_loader_entry *constraints;
- classcache_class_entry *next; /* next class entry for same name */
-};
-
-struct classcache_loader_entry
-{
- classloader_t *loader; /* class loader object */
- classcache_loader_entry *next; /* next loader entry in the list */
-};
-
-
-/* callback function type for classcache_foreach_loaded_class */
-
-typedef void (*classcache_foreach_functionptr_t)(classinfo *, void *);
-
-
-/* function prototypes ********************************************************/
-
-/* initialize the loaded class cache */
-bool classcache_init(void);
-void classcache_free(void);
-
-classinfo * classcache_lookup(classloader_t *initloader,utf *classname);
-classinfo * classcache_lookup_defined(classloader_t *defloader,utf *classname);
-classinfo * classcache_lookup_defined_or_initiated(classloader_t *loader,utf *classname);
-
-bool classcache_store_unique(classinfo *cls);
-classinfo * classcache_store(classloader_t *initloader,classinfo *cls,bool mayfree);
-classinfo * classcache_store_defined(classinfo *cls);
-
-#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraint(classloader_t *a,classloader_t *b,utf *classname);
-bool classcache_add_constraints_for_params(classloader_t *a,classloader_t *b,
- methodinfo *m);
-#endif
-
-s4 classcache_get_loaded_class_count(void);
-
-void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
- void *data);
-
-#if defined(ENABLE_JVMTI)
-void classcache_get_loaded_classes(s4 *class_count_ptr,
- classinfo ***classes_ptr);
-#endif
-
-#ifndef NDEBUG
-void classcache_debug_dump(FILE *file,utf *only);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _CLASSCACHE_H */
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
-
--- /dev/null
+/* src/vm/classcache.hpp - loaded class cache and loading constraints
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _CLASSCACHE_H
+#define _CLASSCACHE_H
+
+#include "config.h"
+
+#include "vm/types.h"
+
+#include <stdio.h> /* for FILE */
+
+#include "toolbox/hashtable.h"
+
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/loader.hpp"
+#include "vm/references.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* forward declarations *******************************************************/
+
+typedef struct classcache_name_entry classcache_name_entry;
+typedef struct classcache_class_entry classcache_class_entry;
+typedef struct classcache_loader_entry classcache_loader_entry;
+
+/* global variables ***********************************************************/
+
+extern hashtable hashtable_classcache;
+
+
+/* structs ********************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* The Loaded Class Cache */
+/* */
+/* The loaded class cache is implemented as a two-level data structure. */
+/* */
+/* The first level is a hash table indexed by class names. For each class */
+/* name in the cache there is a classcache_name_entry, which collects all */
+/* information about classes with this class name. */
+/* */
+/* Second level: For each classcache_name_entry there is a list of */
+/* classcache_class_entry:s representing the possible different resolutions */
+/* of the class name. */
+/* */
+/* A classcache_class_entry records the following: */
+/* */
+/* - the loaded class object, if this entry has been resolved, otherwise NULL */
+/* - the list of initiating loaders which have resolved the class name to */
+/* this class object */
+/* - the list of initiating loaders which are constrained to resolve this */
+/* class name to this class object in the future */
+/* */
+/* The classcache_class_entry:s approximate the equivalence classes created */
+/* by the loading constraints and the equivalence of loaded classes. */
+/* */
+/* When a loading constraint (loaderA,loaderB,NAME) is added, then the */
+/* classcache_class_entry:s for NAME containing loaderA and loaderB resp. */
+/* must be merged into one entry. If this is impossible, because the entries */
+/* have already been resolved to different class objects, then the constraint */
+/* is violated and an expception must be thrown. */
+/*----------------------------------------------------------------------------*/
+
+
+/* classcache_name_entry
+ *
+ * For each classname a classcache_name_entry struct is created.
+ */
+
+struct classcache_name_entry
+{
+ utf *name; /* class name */
+ classcache_name_entry *hashlink; /* link for external chaining */
+ classcache_class_entry *classes; /* equivalence classes for this name*/
+};
+
+struct classcache_class_entry
+{
+ classinfo *classobj; /* the loaded class object, or NULL */
+ classcache_loader_entry *loaders;
+ classcache_loader_entry *constraints;
+ classcache_class_entry *next; /* next class entry for same name */
+};
+
+struct classcache_loader_entry
+{
+ classloader_t *loader; /* class loader object */
+ classcache_loader_entry *next; /* next loader entry in the list */
+};
+
+
+/* callback function type for classcache_foreach_loaded_class */
+
+typedef void (*classcache_foreach_functionptr_t)(classinfo *, void *);
+
+
+/* function prototypes ********************************************************/
+
+/* initialize the loaded class cache */
+bool classcache_init(void);
+void classcache_free(void);
+
+classinfo * classcache_lookup(classloader_t *initloader,utf *classname);
+classinfo * classcache_lookup_defined(classloader_t *defloader,utf *classname);
+classinfo * classcache_lookup_defined_or_initiated(classloader_t *loader,utf *classname);
+
+bool classcache_store_unique(classinfo *cls);
+classinfo * classcache_store(classloader_t *initloader,classinfo *cls,bool mayfree);
+classinfo * classcache_store_defined(classinfo *cls);
+
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraint(classloader_t *a,classloader_t *b,utf *classname);
+bool classcache_add_constraints_for_params(classloader_t *a,classloader_t *b,
+ methodinfo *m);
+#endif
+
+s4 classcache_get_loaded_class_count(void);
+
+void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
+ void *data);
+
+#if defined(ENABLE_JVMTI)
+void classcache_get_loaded_classes(s4 *class_count_ptr,
+ classinfo ***classes_ptr);
+#endif
+
+#ifndef NDEBUG
+void classcache_debug_dump(FILE *file,utf *only);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CLASSCACHE_H */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+
#include "vm/class.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/utf8.h"
#include "vm/globals.hpp"
#include "vm/javaobjects.hpp"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
#include "vm/string.hpp"
#include "vm/global.h"
#include "vm/references.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* function prototypes ********************************************************/
#include "vm/field.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#ifdef __cplusplus
#include "vm/jit/builtin.hpp"
#include "vm/exceptions.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/resolve.hpp"
#include "vm/jit/codegen-common.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/builtin.hpp"
#include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/resolve.hpp"
#include "vm/string.hpp"
#include "vm/array.hpp"
#include "vm/descriptor.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/primitive.hpp"
#include "vm/resolve.hpp"
#include "vm/vm.hpp"
#include <stdint.h>
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* function prototypes ********************************************************/
#include "toolbox/list.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/exceptiontable.h"
#if defined (ENABLE_JITCACHE)
#include "vm/jit/builtin.hpp"
#include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "vm/jit/builtin.hpp"
#include "vm/descriptor.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/jit/dseg.h"
#include "vm/class.hpp"
#include "vm/global.h"
#include "vm/initialize.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/statistics.h"
#include "vm/class.hpp"
#include "vm/global.h"
#include "vm/linker.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/resolve.hpp"
#include "vm/globals.hpp"
#include "vm/initialize.hpp"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/rt-timing.h"
#include "vm/statistics.h"
#include "vm/types.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/resolve.hpp"
#include "mm/memory.h"
#include "mm/codememory.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/resolve.hpp"
#include "vm/types.h"
#include <stdint.h>
#include "vm/class.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
typedef enum cachedreftype {
CRT_CODEINFO,
#include "toolbox/list.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/code.hpp"
#include "config.h"
#include "vm/types.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/loop/loop.h"
#include "vm/types.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/jit.hpp"
#include "vm/descriptor.h"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/abi.h"
#include "vm/jit/stack.h"
extern "C" {
-#include "vm/method.h"
+#include "vm/method.hpp"
#include <opagent.h>
}
#include "config.h"
#include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/optimizing/escape.h"
#define _VM_JIT_OPTIMIZING_ESCAPE_H
#include "vm/jit/jit.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
typedef enum {
ESCAPE_UNKNOWN,
#include "vm/types.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/vm.hpp"
#include "vm/jit/codegen-common.hpp"
#include "vm/statistics.h"
#include "vm/options.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/abi.h"
#include "vm/jit/reg.h"
#include "vm/jit/builtin.hpp"
#include "vm/class.hpp"
-#include "vm/classcache.h"
-#include "vm/method.h"
+#include "vm/classcache.hpp"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "threads/mutex.hpp"
#include "threads/thread.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "threads/condition.hpp"
#include "threads/mutex.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#ifdef __cplusplus
#include "toolbox/logging.h"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/globals.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "arch.h"
#include "md-abi.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/stacktrace.hpp"
#include "vm/globals.hpp"
#include "vm/javaobjects.hpp"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "vm/vm.hpp"
#include "mm/dumpmemory.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/jit/abi.h"
#include <stdint.h>
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/jit/code.hpp"
#include <stdint.h>
-#include "vm/method.h"
+#include "vm/method.hpp"
#if !defined(NDEBUG)
#include "vm/access.h"
#include "vm/array.hpp"
#include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
#include "vm/loader.hpp"
#include "toolbox/logging.h"
#include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/field.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
#include "vm/linker.h"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/package.hpp"
#include "vm/primitive.hpp"
#endif
#if defined(ENABLE_ZLIB)
-# include "vm/zip.h"
+# include "vm/zip.hpp"
#endif
#include "vm/jit/stubs.hpp"
#include "vm/descriptor.h"
#include "vm/class.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/utf8.h"
+++ /dev/null
-/* src/vm/method.c - method functions
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/llni.h"
-
-#include "threads/mutex.hpp"
-
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/class.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/method.h"
-#include "vm/options.h"
-#include "vm/resolve.hpp"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-#include "vm/vm.hpp"
-
-#include "vm/jit/code.hpp"
-#include "vm/jit/methodheader.h"
-#include "vm/jit/stubs.hpp"
-
-
-#if !defined(NDEBUG) && defined(ENABLE_INLINING)
-#define INLINELOG(code) do { if (opt_TraceInlining) { code } } while (0)
-#else
-#define INLINELOG(code)
-#endif
-
-
-/* global variables ***********************************************************/
-
-methodinfo *method_java_lang_reflect_Method_invoke;
-
-
-/* method_init *****************************************************************
-
- Initialize method subsystem.
-
-*******************************************************************************/
-
-void method_init(void)
-{
-#if defined(ENABLE_JAVASE)
- /* Sanity check. */
-
- if (class_java_lang_reflect_Method == NULL)
- vm_abort("method_init: class_java_lang_reflect_Method is NULL");
-
- /* Cache java.lang.reflect.Method.invoke() */
-
- method_java_lang_reflect_Method_invoke =
- class_findmethod(class_java_lang_reflect_Method, utf_invoke, NULL);
-
- if (method_java_lang_reflect_Method_invoke == NULL)
- vm_abort("method_init: Could not resolve method java.lang.reflect.Method.invoke().");
-#endif
-}
-
-
-/* method_load *****************************************************************
-
- Loads a method from the class file and fills an existing methodinfo
- structure.
-
- method_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attribute_count];
- }
-
- attribute_info {
- u2 attribute_name_index;
- u4 attribute_length;
- u1 info[attribute_length];
- }
-
- LineNumberTable_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 line_number_table_length;
- {
- u2 start_pc;
- u2 line_number;
- } line_number_table[line_number_table_length];
- }
-
-*******************************************************************************/
-
-bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
-{
- classinfo *c;
- int argcount;
- s4 i, j, k, l;
- utf *u;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- u2 attribute_name_index;
- utf *attribute_name;
- u2 code_attributes_count;
- u2 code_attribute_name_index;
- utf *code_attribute_name;
-
- /* get classinfo */
-
- c = cb->clazz;
-
- m->mutex = Mutex_new();
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- count_all_methods++;
-#endif
-
- /* all fields of m have been zeroed in load_class_from_classbuffer */
-
- m->clazz = c;
-
- if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
- return false;
-
- /* access flags */
-
- m->flags = suck_u2(cb);
-
- /* name */
-
- name_index = suck_u2(cb);
-
- if (!(u = class_getconstant(c, name_index, CONSTANT_Utf8)))
- return false;
-
- m->name = u;
-
- /* descriptor */
-
- descriptor_index = suck_u2(cb);
-
- if (!(u = class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
- return false;
-
- m->descriptor = u;
-
- if (!descriptor_pool_add(descpool, u, &argcount))
- return false;
-
-#ifdef ENABLE_VERIFIER
- if (opt_verify) {
- if (!is_valid_name_utf(m->name)) {
- exceptions_throw_classformaterror(c, "Method with invalid name");
- return false;
- }
-
- if (m->name->text[0] == '<' &&
- m->name != utf_init && m->name != utf_clinit) {
- exceptions_throw_classformaterror(c, "Method with invalid special name");
- return false;
- }
- }
-#endif /* ENABLE_VERIFIER */
-
- if (!(m->flags & ACC_STATIC))
- argcount++; /* count the 'this' argument */
-
-#ifdef ENABLE_VERIFIER
- if (opt_verify) {
- if (argcount > 255) {
- exceptions_throw_classformaterror(c, "Too many arguments in signature");
- return false;
- }
-
- /* check flag consistency */
- if (m->name != utf_clinit) {
- i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
-
- if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
-
- if (m->flags & ACC_ABSTRACT) {
- if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
- ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
- }
-
- if (c->flags & ACC_INTERFACE) {
- if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
- }
-
- if (m->name == utf_init) {
- if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
- ACC_NATIVE | ACC_ABSTRACT)) {
- exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
- return false;
- }
- }
- }
- }
-#endif /* ENABLE_VERIFIER */
-
- /* mark the method as monomorphic until further notice */
-
- m->flags |= ACC_METHOD_MONOMORPHIC;
-
- /* non-abstract methods have an implementation in this class */
-
- if (!(m->flags & ACC_ABSTRACT))
- m->flags |= ACC_METHOD_IMPLEMENTED;
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* attributes count */
-
- attributes_count = suck_u2(cb);
-
- for (i = 0; i < attributes_count; i++) {
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* attribute name index */
-
- attribute_name_index = suck_u2(cb);
-
- attribute_name =
- class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
-
- if (attribute_name == NULL)
- return false;
-
- if (attribute_name == utf_Code) {
- /* Code */
-
- if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
- exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
- return false;
- }
-
- if (m->jcode) {
- exceptions_throw_classformaterror(c, "Multiple Code attributes");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
- return false;
-
- suck_u4(cb);
- m->maxstack = suck_u2(cb);
- m->maxlocals = suck_u2(cb);
-
- if (m->maxlocals < argcount) {
- exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, 4))
- return false;
-
- m->jcodelength = suck_u4(cb);
-
- if (m->jcodelength == 0) {
- exceptions_throw_classformaterror(c, "Code of a method has length 0");
- return false;
- }
-
- if (m->jcodelength > 65535) {
- exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, m->jcodelength))
- return false;
-
- m->jcode = MNEW(u1, m->jcodelength);
- suck_nbytes(m->jcode, cb, m->jcodelength);
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- m->rawexceptiontablelength = suck_u2(cb);
- if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
- return false;
-
- m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat) {
- count_vmcode_len += m->jcodelength + 18;
- count_extable_len +=
- m->rawexceptiontablelength * sizeof(raw_exception_entry);
- }
-#endif
-
- for (j = 0; j < m->rawexceptiontablelength; j++) {
- u4 idx;
- m->rawexceptiontable[j].startpc = suck_u2(cb);
- m->rawexceptiontable[j].endpc = suck_u2(cb);
- m->rawexceptiontable[j].handlerpc = suck_u2(cb);
-
- idx = suck_u2(cb);
-
- if (!idx) {
- m->rawexceptiontable[j].catchtype.any = NULL;
- }
- else {
- /* the classref is created later */
- if (!(m->rawexceptiontable[j].catchtype.any =
- (utf *) class_getconstant(c, idx, CONSTANT_Class)))
- return false;
- }
- }
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* code attributes count */
-
- code_attributes_count = suck_u2(cb);
-
- for (k = 0; k < code_attributes_count; k++) {
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* code attribute name index */
-
- code_attribute_name_index = suck_u2(cb);
-
- code_attribute_name =
- class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8);
-
- if (code_attribute_name == NULL)
- return false;
-
- /* check which code attribute */
-
- if (code_attribute_name == utf_LineNumberTable) {
- /* LineNumberTable */
-
- if (!suck_check_classbuffer_size(cb, 4 + 2))
- return false;
-
- /* attribute length */
-
- (void) suck_u4(cb);
-
- /* line number table length */
-
- m->linenumbercount = suck_u2(cb);
-
- if (!suck_check_classbuffer_size(cb,
- (2 + 2) * m->linenumbercount))
- return false;
-
- m->linenumbers = MNEW(lineinfo, m->linenumbercount);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
-#endif
-
- for (l = 0; l < m->linenumbercount; l++) {
- m->linenumbers[l].start_pc = suck_u2(cb);
- m->linenumbers[l].line_number = suck_u2(cb);
- }
- }
-#if defined(ENABLE_JAVASE)
- else if (code_attribute_name == utf_StackMapTable) {
- /* StackTableMap */
-
- if (!stackmap_load_attribute_stackmaptable(cb, m))
- return false;
- }
-#endif
- else {
- /* unknown code attribute */
-
- if (!loader_skip_attribute_body(cb))
- return false;
- }
- }
- }
- else if (attribute_name == utf_Exceptions) {
- /* Exceptions */
-
- if (m->thrownexceptions != NULL) {
- exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, 4 + 2))
- return false;
-
- /* attribute length */
-
- (void) suck_u4(cb);
-
- m->thrownexceptionscount = suck_u2(cb);
-
- if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
- return false;
-
- m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
-
- for (j = 0; j < m->thrownexceptionscount; j++) {
- /* the classref is created later */
- if (!((m->thrownexceptions)[j].any =
- (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
- return false;
- }
- }
-#if defined(ENABLE_JAVASE)
- else if (attribute_name == utf_Signature) {
- /* Signature */
-
- if (!loader_load_attribute_signature(cb, &(m->signature)))
- return false;
- }
-
-#if defined(ENABLE_ANNOTATIONS)
- else if (attribute_name == utf_RuntimeVisibleAnnotations) {
- /* RuntimeVisibleAnnotations */
- if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
- return false;
- }
- else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
- /* RuntimeInvisibleAnnotations */
- if (!annotation_load_method_attribute_runtimeinvisibleannotations(cb, m))
- return false;
- }
- else if (attribute_name == utf_RuntimeVisibleParameterAnnotations) {
- /* RuntimeVisibleParameterAnnotations */
- if (!annotation_load_method_attribute_runtimevisibleparameterannotations(cb, m))
- return false;
- }
- else if (attribute_name == utf_RuntimeInvisibleParameterAnnotations) {
- /* RuntimeInvisibleParameterAnnotations */
- if (!annotation_load_method_attribute_runtimeinvisibleparameterannotations(cb, m))
- return false;
- }
- else if (attribute_name == utf_AnnotationDefault) {
- /* AnnotationDefault */
- if (!annotation_load_method_attribute_annotationdefault(cb, m))
- return false;
- }
-#endif
-#endif
- else {
- /* unknown attribute */
-
- if (!loader_skip_attribute_body(cb))
- return false;
- }
- }
-
- if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
- exceptions_throw_classformaterror(c, "Missing Code attribute");
- return false;
- }
-
-#if defined(ENABLE_REPLACEMENT)
- /* initialize the hit countdown field */
-
- m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
-#endif
-
- /* everything was ok */
-
- return true;
-}
-
-
-/* method_free *****************************************************************
-
- Frees all memory that was allocated for this method.
-
-*******************************************************************************/
-
-void method_free(methodinfo *m)
-{
- if (m->mutex)
- Mutex_delete(m->mutex);
-
- if (m->jcode)
- MFREE(m->jcode, u1, m->jcodelength);
-
- if (m->rawexceptiontable)
- MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
-
- code_free_code_of_method(m);
-
- if (m->stubroutine) {
- if (m->flags & ACC_NATIVE) {
- NativeStub_remove(m->stubroutine);
- }
- else {
- CompilerStub_remove(m->stubroutine);
- }
- }
-}
-
-
-/* method_canoverwrite *********************************************************
-
- Check if m and old are identical with respect to type and
- name. This means that old can be overwritten with m.
-
-*******************************************************************************/
-
-bool method_canoverwrite(methodinfo *m, methodinfo *old)
-{
- if (m->name != old->name)
- return false;
-
- if (m->descriptor != old->descriptor)
- return false;
-
- if (m->flags & ACC_STATIC)
- return false;
-
- return true;
-}
-
-
-/* method_new_builtin **********************************************************
-
- Creates a minimal methodinfo structure for builtins. This comes handy
- when dealing with builtin stubs or stacktraces.
-
-*******************************************************************************/
-
-methodinfo *method_new_builtin(builtintable_entry *bte)
-{
- methodinfo *m;
-
- /* allocate the methodinfo structure */
-
- m = NEW(methodinfo);
-
- /* initialize methodinfo structure */
-
- MZERO(m, methodinfo, 1);
-
- m->mutex = Mutex_new();
- m->flags = ACC_METHOD_BUILTIN;
- m->parseddesc = bte->md;
- m->name = bte->name;
- m->descriptor = bte->descriptor;
-
- /* return the newly created methodinfo */
-
- return m;
-}
-
-
-/* method_vftbl_lookup *********************************************************
-
- Does a method lookup in the passed virtual function table. This
- function does exactly the same thing as JIT, but additionally
- relies on the fact, that the methodinfo pointer is at the first
- data segment slot (even for compiler stubs).
-
-*******************************************************************************/
-
-methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
-{
- methodptr mptr;
- methodptr *pmptr;
- methodinfo *resm; /* pointer to new resolved method */
-
- /* If the method is not an instance method, just return it. */
-
- if (m->flags & ACC_STATIC)
- return m;
-
- assert(vftbl);
-
- /* Get the method from the virtual function table. Is this an
- interface method? */
-
- if (m->clazz->flags & ACC_INTERFACE) {
- pmptr = vftbl->interfacetable[-(m->clazz->index)];
- mptr = pmptr[(m - m->clazz->methods)];
- }
- else {
- mptr = vftbl->table[m->vftblindex];
- }
-
- /* and now get the codeinfo pointer from the first data segment slot */
-
- resm = code_get_methodinfo_for_pv(mptr);
-
- return resm;
-}
-
-
-/* method_get_parametercount **************************************************
-
- Use the descriptor of a method to determine the number of parameters
- of the method. The this pointer of non-static methods is not counted.
-
- IN:
- m........the method of which the parameters should be counted
-
- RETURN VALUE:
- The parameter count or -1 on error.
-
-*******************************************************************************/
-
-int32_t method_get_parametercount(methodinfo *m)
-{
- methoddesc *md; /* method descriptor of m */
- int32_t paramcount = 0; /* the parameter count of m */
-
- md = m->parseddesc;
-
- /* is the descriptor fully parsed? */
-
- if (md->params == NULL) {
- if (!descriptor_params_from_paramtypes(md, m->flags)) {
- return -1;
- }
- }
-
- paramcount = md->paramcount;
-
- /* skip `this' pointer */
-
- if (!(m->flags & ACC_STATIC)) {
- --paramcount;
- }
-
- return paramcount;
-}
-
-
-/* method_get_parametertypearray ***********************************************
-
- Use the descriptor of a method to generate a java.lang.Class array
- which contains the classes of the parametertypes of the method.
-
- This function is called by java.lang.reflect.{Constructor,Method}.
-
-*******************************************************************************/
-
-java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m)
-{
- methoddesc *md;
- typedesc *paramtypes;
- int32_t paramcount;
- java_handle_objectarray_t *oa;
- int32_t i;
- classinfo *c;
-
- md = m->parseddesc;
-
- /* is the descriptor fully parsed? */
-
- if (m->parseddesc->params == NULL)
- if (!descriptor_params_from_paramtypes(md, m->flags))
- return NULL;
-
- paramtypes = md->paramtypes;
- paramcount = md->paramcount;
-
- /* skip `this' pointer */
-
- if (!(m->flags & ACC_STATIC)) {
- paramtypes++;
- paramcount--;
- }
-
- /* create class-array */
-
- oa = builtin_anewarray(paramcount, class_java_lang_Class);
-
- if (oa == NULL)
- return NULL;
-
- /* get classes */
-
- for (i = 0; i < paramcount; i++) {
- if (!resolve_class_from_typedesc(¶mtypes[i], true, false, &c))
- return NULL;
-
- LLNI_array_direct(oa, i) = (java_object_t *) c;
- }
-
- return oa;
-}
-
-
-/* method_get_exceptionarray ***************************************************
-
- Get the exceptions which can be thrown by a method.
-
-*******************************************************************************/
-
-java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m)
-{
- java_handle_objectarray_t *oa;
- classinfo *c;
- s4 i;
-
- /* create class-array */
-
- oa = builtin_anewarray(m->thrownexceptionscount, class_java_lang_Class);
-
- if (oa == NULL)
- return NULL;
-
- /* iterate over all exceptions and store the class in the array */
-
- for (i = 0; i < m->thrownexceptionscount; i++) {
- c = resolve_classref_or_classinfo_eager(m->thrownexceptions[i], true);
-
- if (c == NULL)
- return NULL;
-
- LLNI_array_direct(oa, i) = (java_object_t *) c;
- }
-
- return oa;
-}
-
-
-/* method_returntype_get *******************************************************
-
- Get the return type of the method.
-
-*******************************************************************************/
-
-classinfo *method_returntype_get(methodinfo *m)
-{
- typedesc *td;
- classinfo *c;
-
- td = &(m->parseddesc->returntype);
-
- if (!resolve_class_from_typedesc(td, true, false, &c))
- return NULL;
-
- return c;
-}
-
-
-/* method_count_implementations ************************************************
-
- Count the implementations of a method in a class cone (a class and all its
- subclasses.)
-
- IN:
- m................the method to count
- c................class at which to start the counting (this class and
- all its subclasses will be searched)
-
- OUT:
- *found...........if found != NULL, *found receives the method
- implementation that was found. This value is only
- meaningful if the return value is 1.
-
- RETURN VALUE:
- the number of implementations found
-
-*******************************************************************************/
-
-s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
-{
- s4 count;
- methodinfo *mp;
- methodinfo *mend;
- classinfo *child;
-
- count = 0;
-
- mp = c->methods;
- mend = mp + c->methodscount;
-
- for (; mp < mend; ++mp) {
- if (method_canoverwrite(mp, m)) {
- if (found)
- *found = mp;
- count++;
- break;
- }
- }
-
- for (child = c->sub; child != NULL; child = child->nextsub) {
- count += method_count_implementations(m, child, found);
- }
-
- return count;
-}
-
-
-/* method_get_annotations ******************************************************
-
- Get a methods' unparsed annotations in a byte array.
-
- IN:
- m........the method of which the annotations should be returned
-
- RETURN VALUE:
- The unparsed annotations in a byte array (or NULL if there aren't any).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_annotations(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
- classinfo *c; /* methods' declaring class */
- int slot; /* methods' slot */
- java_handle_t *annotations; /* methods' unparsed annotations */
- java_handle_t *method_annotations; /* all methods' unparsed annotations */
- /* of the declaring class */
-
- c = m->clazz;
- slot = m - c->methods;
- annotations = NULL;
-
- LLNI_classinfo_field_get(c, method_annotations, method_annotations);
-
- /* the method_annotations array might be shorter then the method
- * count if the methods above a certain index have no annotations.
- */
- if (method_annotations != NULL &&
- array_length_get(method_annotations) > slot) {
- annotations = array_objectarray_element_get(
- (java_handle_objectarray_t*)method_annotations, slot);
- }
-
- return (java_handle_bytearray_t*)annotations;
-#else
- return NULL;
-#endif
-}
-
-
-/* method_get_parameterannotations ********************************************
-
- Get a methods' unparsed parameter annotations in an array of byte
- arrays.
-
- IN:
- m........the method of which the parameter annotations should be
- returned
-
- RETURN VALUE:
- The unparsed parameter annotations in a byte array (or NULL if
- there aren't any).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
- classinfo *c; /* methods' declaring class */
- int slot; /* methods' slot */
- java_handle_t *parameterAnnotations; /* methods' unparsed */
- /* parameter annotations */
- java_handle_t *method_parameterannotations; /* all methods' unparsed */
- /* parameter annotations of */
- /* the declaring class */
-
- c = m->clazz;
- slot = m - c->methods;
- parameterAnnotations = NULL;
-
- LLNI_classinfo_field_get(
- c, method_parameterannotations, method_parameterannotations);
-
- /* the method_annotations array might be shorter then the method
- * count if the methods above a certain index have no annotations.
- */
- if (method_parameterannotations != NULL &&
- array_length_get(method_parameterannotations) > slot) {
- parameterAnnotations = array_objectarray_element_get(
- (java_handle_objectarray_t*)method_parameterannotations,
- slot);
- }
-
- return (java_handle_bytearray_t*)parameterAnnotations;
-#else
- return NULL;
-#endif
-}
-
-
-/* method_get_annotationdefault ***********************************************
-
- Get a methods' unparsed annotation default value in a byte array.
-
- IN:
- m........the method of which the annotation default value should be
- returned
-
- RETURN VALUE:
- The unparsed annotation default value in a byte array (or NULL if
- there isn't one).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
- classinfo *c; /* methods' declaring class */
- int slot; /* methods' slot */
- java_handle_t *annotationDefault; /* methods' unparsed */
- /* annotation default value */
- java_handle_t *method_annotationdefaults; /* all methods' unparsed */
- /* annotation default values of */
- /* the declaring class */
-
- c = m->clazz;
- slot = m - c->methods;
- annotationDefault = NULL;
-
- LLNI_classinfo_field_get(
- c, method_annotationdefaults, method_annotationdefaults);
-
- /* the method_annotations array might be shorter then the method
- * count if the methods above a certain index have no annotations.
- */
- if (method_annotationdefaults != NULL &&
- array_length_get(method_annotationdefaults) > slot) {
- annotationDefault = array_objectarray_element_get(
- (java_handle_objectarray_t*)method_annotationdefaults, slot);
- }
-
- return (java_handle_bytearray_t*)annotationDefault;
-#else
- return NULL;
-#endif
-}
-
-
-/* method_add_to_worklist ******************************************************
-
- Add the method to the given worklist. If the method already occurs in
- the worklist, the worklist remains unchanged.
-
-*******************************************************************************/
-
-static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
-{
- method_worklist *wi;
-
- for (wi = *wl; wi != NULL; wi = wi->next)
- if (wi->m == m)
- return;
-
- wi = NEW(method_worklist);
- wi->next = *wl;
- wi->m = m;
-
- *wl = wi;
-}
-
-
-/* method_add_assumption_monomorphic *******************************************
-
- Record the assumption that the method is monomorphic.
-
- IN:
- m.................the method
- caller............the caller making the assumption
-
-*******************************************************************************/
-
-void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
-{
- method_assumption *as;
-
- /* XXX LOCKING FOR THIS FUNCTION? */
-
- /* check if we already have registered this assumption */
-
- for (as = m->assumptions; as != NULL; as = as->next) {
- if (as->context == caller)
- return;
- }
-
- /* register the assumption */
-
- as = NEW(method_assumption);
- as->next = m->assumptions;
- as->context = caller;
-
- m->assumptions = as;
-}
-
-/* method_break_assumption_monomorphic *****************************************
-
- Break the assumption that this method is monomorphic. All callers that
- have registered this assumption are added to the worklist.
-
- IN:
- m.................the method
- wl................worklist where to add invalidated callers
-
-*******************************************************************************/
-
-void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
-{
- method_assumption *as;
-
- /* XXX LOCKING FOR THIS FUNCTION? */
-
- for (as = m->assumptions; as != NULL; as = as->next) {
- INLINELOG(
- printf("ASSUMPTION BROKEN (monomorphism): ");
- method_print(m);
- printf(" in ");
- method_println(as->context);
- );
-
- method_add_to_worklist(as->context, wl);
-
-#if defined(ENABLE_TLH) && 0
- /* XXX hack */
- method_assumption *as2;
- as2 = m->assumptions;
- m->assumptions = NULL;
- method_break_assumption_monomorphic(as->context, wl);
- /*
- assert(m->assumptions == NULL);
- m->assumptions = as2;*/
-#endif
-
- }
-}
-
-/* method_printflags ***********************************************************
-
- Prints the flags of a method to stdout like.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_printflags(methodinfo *m)
-{
- if (m == NULL) {
- printf("NULL");
- return;
- }
-
- if (m->flags & ACC_PUBLIC) printf(" PUBLIC");
- if (m->flags & ACC_PRIVATE) printf(" PRIVATE");
- if (m->flags & ACC_PROTECTED) printf(" PROTECTED");
- if (m->flags & ACC_STATIC) printf(" STATIC");
- if (m->flags & ACC_FINAL) printf(" FINAL");
- if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
- if (m->flags & ACC_VOLATILE) printf(" VOLATILE");
- if (m->flags & ACC_TRANSIENT) printf(" TRANSIENT");
- if (m->flags & ACC_NATIVE) printf(" NATIVE");
- if (m->flags & ACC_INTERFACE) printf(" INTERFACE");
- if (m->flags & ACC_ABSTRACT) printf(" ABSTRACT");
- if (m->flags & ACC_METHOD_BUILTIN) printf(" (builtin)");
- if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
- if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_print ****************************************************************
-
- Prints a method to stdout like:
-
- java.lang.Object.<init>()V
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_print(methodinfo *m)
-{
- if (m == NULL) {
- printf("NULL");
- return;
- }
-
- if (m->clazz != NULL)
- utf_display_printable_ascii_classname(m->clazz->name);
- else
- printf("NULL");
- printf(".");
- utf_display_printable_ascii(m->name);
- utf_display_printable_ascii(m->descriptor);
-
- method_printflags(m);
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_println **************************************************************
-
- Prints a method plus new line to stdout like:
-
- java.lang.Object.<init>()V
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_println(methodinfo *m)
-{
- if (opt_debugcolor) printf("\033[31m"); /* red */
- method_print(m);
- if (opt_debugcolor) printf("\033[m");
- printf("\n");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_methodref_print ******************************************************
-
- Prints a method reference to stdout.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_methodref_print(constant_FMIref *mr)
-{
- if (!mr) {
- printf("(constant_FMIref *)NULL");
- return;
- }
-
- if (IS_FMIREF_RESOLVED(mr)) {
- printf("<method> ");
- method_print(mr->p.method);
- }
- else {
- printf("<methodref> ");
- utf_display_printable_ascii_classname(mr->p.classref->name);
- printf(".");
- utf_display_printable_ascii(mr->name);
- utf_display_printable_ascii(mr->descriptor);
- }
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_methodref_println ****************************************************
-
- Prints a method reference to stdout, followed by a newline.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_methodref_println(constant_FMIref *mr)
-{
- method_methodref_print(mr);
- printf("\n");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/method.cpp - method functions
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/linker.h"
+#include "vm/loader.hpp"
+#include "vm/method.hpp"
+#include "vm/options.h"
+#include "vm/resolve.hpp"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+
+#include "vm/jit/code.hpp"
+#include "vm/jit/methodheader.h"
+#include "vm/jit/stubs.hpp"
+
+
+#if !defined(NDEBUG) && defined(ENABLE_INLINING)
+#define INLINELOG(code) do { if (opt_TraceInlining) { code } } while (0)
+#else
+#define INLINELOG(code)
+#endif
+
+/* global variables ***********************************************************/
+
+methodinfo *method_java_lang_reflect_Method_invoke;
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* method_init *****************************************************************
+
+ Initialize method subsystem.
+
+*******************************************************************************/
+
+void method_init(void)
+{
+#if defined(ENABLE_JAVASE)
+ /* Sanity check. */
+
+ if (class_java_lang_reflect_Method == NULL)
+ vm_abort("method_init: class_java_lang_reflect_Method is NULL");
+
+ /* Cache java.lang.reflect.Method.invoke() */
+
+ method_java_lang_reflect_Method_invoke =
+ class_findmethod(class_java_lang_reflect_Method, utf_invoke, NULL);
+
+ if (method_java_lang_reflect_Method_invoke == NULL)
+ vm_abort("method_init: Could not resolve method java.lang.reflect.Method.invoke().");
+#endif
+}
+
+
+/* method_load *****************************************************************
+
+ Loads a method from the class file and fills an existing methodinfo
+ structure.
+
+ method_info {
+ u2 access_flags;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ attribute_info attributes[attribute_count];
+ }
+
+ attribute_info {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u1 info[attribute_length];
+ }
+
+ LineNumberTable_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 line_number_table_length;
+ {
+ u2 start_pc;
+ u2 line_number;
+ } line_number_table[line_number_table_length];
+ }
+
+*******************************************************************************/
+
+bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
+{
+ classinfo *c;
+ int argcount;
+ s4 i, j, k, l;
+ utf *u;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ u2 attribute_name_index;
+ utf *attribute_name;
+ u2 code_attributes_count;
+ u2 code_attribute_name_index;
+ utf *code_attribute_name;
+
+ /* get classinfo */
+
+ c = cb->clazz;
+
+ m->mutex = new Mutex();
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_all_methods++;
+#endif
+
+ /* all fields of m have been zeroed in load_class_from_classbuffer */
+
+ m->clazz = c;
+
+ if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
+ return false;
+
+ /* access flags */
+
+ m->flags = suck_u2(cb);
+
+ /* name */
+
+ name_index = suck_u2(cb);
+
+ if (!(u = (utf*) class_getconstant(c, name_index, CONSTANT_Utf8)))
+ return false;
+
+ m->name = u;
+
+ /* descriptor */
+
+ descriptor_index = suck_u2(cb);
+
+ if (!(u = (utf*) class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
+ return false;
+
+ m->descriptor = u;
+
+ if (!descriptor_pool_add(descpool, u, &argcount))
+ return false;
+
+#ifdef ENABLE_VERIFIER
+ if (opt_verify) {
+ if (!is_valid_name_utf(m->name)) {
+ exceptions_throw_classformaterror(c, "Method with invalid name");
+ return false;
+ }
+
+ if (m->name->text[0] == '<' &&
+ m->name != utf_init && m->name != utf_clinit) {
+ exceptions_throw_classformaterror(c, "Method with invalid special name");
+ return false;
+ }
+ }
+#endif /* ENABLE_VERIFIER */
+
+ if (!(m->flags & ACC_STATIC))
+ argcount++; /* count the 'this' argument */
+
+#ifdef ENABLE_VERIFIER
+ if (opt_verify) {
+ if (argcount > 255) {
+ exceptions_throw_classformaterror(c, "Too many arguments in signature");
+ return false;
+ }
+
+ /* check flag consistency */
+ if (m->name != utf_clinit) {
+ i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
+
+ if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+
+ if (m->flags & ACC_ABSTRACT) {
+ if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
+ ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+ }
+
+ if (c->flags & ACC_INTERFACE) {
+ if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+ }
+
+ if (m->name == utf_init) {
+ if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_NATIVE | ACC_ABSTRACT)) {
+ exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
+ return false;
+ }
+ }
+ }
+ }
+#endif /* ENABLE_VERIFIER */
+
+ /* mark the method as monomorphic until further notice */
+
+ m->flags |= ACC_METHOD_MONOMORPHIC;
+
+ /* non-abstract methods have an implementation in this class */
+
+ if (!(m->flags & ACC_ABSTRACT))
+ m->flags |= ACC_METHOD_IMPLEMENTED;
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* attributes count */
+
+ attributes_count = suck_u2(cb);
+
+ for (i = 0; i < attributes_count; i++) {
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* attribute name index */
+
+ attribute_name_index = suck_u2(cb);
+
+ attribute_name =
+ (utf*) class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
+
+ if (attribute_name == NULL)
+ return false;
+
+ if (attribute_name == utf_Code) {
+ /* Code */
+
+ if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
+ exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
+ return false;
+ }
+
+ if (m->jcode) {
+ exceptions_throw_classformaterror(c, "Multiple Code attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
+ return false;
+
+ suck_u4(cb);
+ m->maxstack = suck_u2(cb);
+ m->maxlocals = suck_u2(cb);
+
+ if (m->maxlocals < argcount) {
+ exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4))
+ return false;
+
+ m->jcodelength = suck_u4(cb);
+
+ if (m->jcodelength == 0) {
+ exceptions_throw_classformaterror(c, "Code of a method has length 0");
+ return false;
+ }
+
+ if (m->jcodelength > 65535) {
+ exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, m->jcodelength))
+ return false;
+
+ m->jcode = MNEW(u1, m->jcodelength);
+ suck_nbytes(m->jcode, cb, m->jcodelength);
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ m->rawexceptiontablelength = suck_u2(cb);
+ if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
+ return false;
+
+ m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat) {
+ count_vmcode_len += m->jcodelength + 18;
+ count_extable_len +=
+ m->rawexceptiontablelength * sizeof(raw_exception_entry);
+ }
+#endif
+
+ for (j = 0; j < m->rawexceptiontablelength; j++) {
+ u4 idx;
+ m->rawexceptiontable[j].startpc = suck_u2(cb);
+ m->rawexceptiontable[j].endpc = suck_u2(cb);
+ m->rawexceptiontable[j].handlerpc = suck_u2(cb);
+
+ idx = suck_u2(cb);
+
+ if (!idx) {
+ m->rawexceptiontable[j].catchtype.any = NULL;
+ }
+ else {
+ /* the classref is created later */
+ if (!(m->rawexceptiontable[j].catchtype.any =
+ (utf *) class_getconstant(c, idx, CONSTANT_Class)))
+ return false;
+ }
+ }
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* code attributes count */
+
+ code_attributes_count = suck_u2(cb);
+
+ for (k = 0; k < code_attributes_count; k++) {
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* code attribute name index */
+
+ code_attribute_name_index = suck_u2(cb);
+
+ code_attribute_name =
+ (utf*) class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8);
+
+ if (code_attribute_name == NULL)
+ return false;
+
+ /* check which code attribute */
+
+ if (code_attribute_name == utf_LineNumberTable) {
+ /* LineNumberTable */
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* attribute length */
+
+ (void) suck_u4(cb);
+
+ /* line number table length */
+
+ m->linenumbercount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb,
+ (2 + 2) * m->linenumbercount))
+ return false;
+
+ m->linenumbers = MNEW(lineinfo, m->linenumbercount);
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
+#endif
+
+ for (l = 0; l < m->linenumbercount; l++) {
+ m->linenumbers[l].start_pc = suck_u2(cb);
+ m->linenumbers[l].line_number = suck_u2(cb);
+ }
+ }
+#if defined(ENABLE_JAVASE)
+ else if (code_attribute_name == utf_StackMapTable) {
+ /* StackTableMap */
+
+ if (!stackmap_load_attribute_stackmaptable(cb, m))
+ return false;
+ }
+#endif
+ else {
+ /* unknown code attribute */
+
+ if (!loader_skip_attribute_body(cb))
+ return false;
+ }
+ }
+ }
+ else if (attribute_name == utf_Exceptions) {
+ /* Exceptions */
+
+ if (m->thrownexceptions != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* attribute length */
+
+ (void) suck_u4(cb);
+
+ m->thrownexceptionscount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
+ return false;
+
+ m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
+
+ for (j = 0; j < m->thrownexceptionscount; j++) {
+ /* the classref is created later */
+ if (!((m->thrownexceptions)[j].any =
+ (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
+ return false;
+ }
+ }
+#if defined(ENABLE_JAVASE)
+ else if (attribute_name == utf_Signature) {
+ /* Signature */
+
+ if (!loader_load_attribute_signature(cb, &(m->signature)))
+ return false;
+ }
+
+#if defined(ENABLE_ANNOTATIONS)
+ else if (attribute_name == utf_RuntimeVisibleAnnotations) {
+ /* RuntimeVisibleAnnotations */
+ if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
+ /* RuntimeInvisibleAnnotations */
+ if (!annotation_load_method_attribute_runtimeinvisibleannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeVisibleParameterAnnotations) {
+ /* RuntimeVisibleParameterAnnotations */
+ if (!annotation_load_method_attribute_runtimevisibleparameterannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeInvisibleParameterAnnotations) {
+ /* RuntimeInvisibleParameterAnnotations */
+ if (!annotation_load_method_attribute_runtimeinvisibleparameterannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_AnnotationDefault) {
+ /* AnnotationDefault */
+ if (!annotation_load_method_attribute_annotationdefault(cb, m))
+ return false;
+ }
+#endif
+#endif
+ else {
+ /* unknown attribute */
+
+ if (!loader_skip_attribute_body(cb))
+ return false;
+ }
+ }
+
+ if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
+ exceptions_throw_classformaterror(c, "Missing Code attribute");
+ return false;
+ }
+
+#if defined(ENABLE_REPLACEMENT)
+ /* initialize the hit countdown field */
+
+ m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
+#endif
+
+ /* everything was ok */
+
+ return true;
+}
+
+
+/* method_free *****************************************************************
+
+ Frees all memory that was allocated for this method.
+
+*******************************************************************************/
+
+void method_free(methodinfo *m)
+{
+ if (m->mutex)
+ delete m->mutex;
+
+ if (m->jcode)
+ MFREE(m->jcode, u1, m->jcodelength);
+
+ if (m->rawexceptiontable)
+ MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
+
+ code_free_code_of_method(m);
+
+ if (m->stubroutine) {
+ if (m->flags & ACC_NATIVE) {
+ NativeStub::remove(m->stubroutine);
+ }
+ else {
+ CompilerStub::remove(m->stubroutine);
+ }
+ }
+}
+
+
+/* method_canoverwrite *********************************************************
+
+ Check if m and old are identical with respect to type and
+ name. This means that old can be overwritten with m.
+
+*******************************************************************************/
+
+bool method_canoverwrite(methodinfo *m, methodinfo *old)
+{
+ if (m->name != old->name)
+ return false;
+
+ if (m->descriptor != old->descriptor)
+ return false;
+
+ if (m->flags & ACC_STATIC)
+ return false;
+
+ return true;
+}
+
+
+/* method_new_builtin **********************************************************
+
+ Creates a minimal methodinfo structure for builtins. This comes handy
+ when dealing with builtin stubs or stacktraces.
+
+*******************************************************************************/
+
+methodinfo *method_new_builtin(builtintable_entry *bte)
+{
+ methodinfo *m;
+
+ /* allocate the methodinfo structure */
+
+ m = NEW(methodinfo);
+
+ /* initialize methodinfo structure */
+
+ MZERO(m, methodinfo, 1);
+
+ m->mutex = new Mutex();
+ m->flags = ACC_METHOD_BUILTIN;
+ m->parseddesc = bte->md;
+ m->name = bte->name;
+ m->descriptor = bte->descriptor;
+
+ /* return the newly created methodinfo */
+
+ return m;
+}
+
+
+/* method_vftbl_lookup *********************************************************
+
+ Does a method lookup in the passed virtual function table. This
+ function does exactly the same thing as JIT, but additionally
+ relies on the fact, that the methodinfo pointer is at the first
+ data segment slot (even for compiler stubs).
+
+*******************************************************************************/
+
+methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
+{
+ methodptr mptr;
+ methodptr *pmptr;
+ methodinfo *resm; /* pointer to new resolved method */
+
+ /* If the method is not an instance method, just return it. */
+
+ if (m->flags & ACC_STATIC)
+ return m;
+
+ assert(vftbl);
+
+ /* Get the method from the virtual function table. Is this an
+ interface method? */
+
+ if (m->clazz->flags & ACC_INTERFACE) {
+ pmptr = vftbl->interfacetable[-(m->clazz->index)];
+ mptr = pmptr[(m - m->clazz->methods)];
+ }
+ else {
+ mptr = vftbl->table[m->vftblindex];
+ }
+
+ /* and now get the codeinfo pointer from the first data segment slot */
+
+ resm = code_get_methodinfo_for_pv(mptr);
+
+ return resm;
+}
+
+
+/* method_get_parametercount **************************************************
+
+ Use the descriptor of a method to determine the number of parameters
+ of the method. The this pointer of non-static methods is not counted.
+
+ IN:
+ m........the method of which the parameters should be counted
+
+ RETURN VALUE:
+ The parameter count or -1 on error.
+
+*******************************************************************************/
+
+int32_t method_get_parametercount(methodinfo *m)
+{
+ methoddesc *md; /* method descriptor of m */
+ int32_t paramcount = 0; /* the parameter count of m */
+
+ md = m->parseddesc;
+
+ /* is the descriptor fully parsed? */
+
+ if (md->params == NULL) {
+ if (!descriptor_params_from_paramtypes(md, m->flags)) {
+ return -1;
+ }
+ }
+
+ paramcount = md->paramcount;
+
+ /* skip `this' pointer */
+
+ if (!(m->flags & ACC_STATIC)) {
+ --paramcount;
+ }
+
+ return paramcount;
+}
+
+
+/* method_get_parametertypearray ***********************************************
+
+ Use the descriptor of a method to generate a java.lang.Class array
+ which contains the classes of the parametertypes of the method.
+
+ This function is called by java.lang.reflect.{Constructor,Method}.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m)
+{
+ methoddesc *md;
+ typedesc *paramtypes;
+ int32_t paramcount;
+ java_handle_objectarray_t *oa;
+ int32_t i;
+ classinfo *c;
+
+ md = m->parseddesc;
+
+ /* is the descriptor fully parsed? */
+
+ if (m->parseddesc->params == NULL)
+ if (!descriptor_params_from_paramtypes(md, m->flags))
+ return NULL;
+
+ paramtypes = md->paramtypes;
+ paramcount = md->paramcount;
+
+ /* skip `this' pointer */
+
+ if (!(m->flags & ACC_STATIC)) {
+ paramtypes++;
+ paramcount--;
+ }
+
+ /* create class-array */
+
+ oa = builtin_anewarray(paramcount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* get classes */
+
+ for (i = 0; i < paramcount; i++) {
+ if (!resolve_class_from_typedesc(¶mtypes[i], true, false, &c))
+ return NULL;
+
+ LLNI_array_direct(oa, i) = (java_object_t *) c;
+ }
+
+ return oa;
+}
+
+
+/* method_get_exceptionarray ***************************************************
+
+ Get the exceptions which can be thrown by a method.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m)
+{
+ java_handle_objectarray_t *oa;
+ classinfo *c;
+ s4 i;
+
+ /* create class-array */
+
+ oa = builtin_anewarray(m->thrownexceptionscount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* iterate over all exceptions and store the class in the array */
+
+ for (i = 0; i < m->thrownexceptionscount; i++) {
+ c = resolve_classref_or_classinfo_eager(m->thrownexceptions[i], true);
+
+ if (c == NULL)
+ return NULL;
+
+ LLNI_array_direct(oa, i) = (java_object_t *) c;
+ }
+
+ return oa;
+}
+
+
+/* method_returntype_get *******************************************************
+
+ Get the return type of the method.
+
+*******************************************************************************/
+
+classinfo *method_returntype_get(methodinfo *m)
+{
+ typedesc *td;
+ classinfo *c;
+
+ td = &(m->parseddesc->returntype);
+
+ if (!resolve_class_from_typedesc(td, true, false, &c))
+ return NULL;
+
+ return c;
+}
+
+
+/* method_count_implementations ************************************************
+
+ Count the implementations of a method in a class cone (a class and all its
+ subclasses.)
+
+ IN:
+ m................the method to count
+ c................class at which to start the counting (this class and
+ all its subclasses will be searched)
+
+ OUT:
+ *found...........if found != NULL, *found receives the method
+ implementation that was found. This value is only
+ meaningful if the return value is 1.
+
+ RETURN VALUE:
+ the number of implementations found
+
+*******************************************************************************/
+
+s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
+{
+ s4 count;
+ methodinfo *mp;
+ methodinfo *mend;
+ classinfo *child;
+
+ count = 0;
+
+ mp = c->methods;
+ mend = mp + c->methodscount;
+
+ for (; mp < mend; ++mp) {
+ if (method_canoverwrite(mp, m)) {
+ if (found)
+ *found = mp;
+ count++;
+ break;
+ }
+ }
+
+ for (child = c->sub; child != NULL; child = child->nextsub) {
+ count += method_count_implementations(m, child, found);
+ }
+
+ return count;
+}
+
+
+/* method_get_annotations ******************************************************
+
+ Get a methods' unparsed annotations in a byte array.
+
+ IN:
+ m........the method of which the annotations should be returned
+
+ RETURN VALUE:
+ The unparsed annotations in a byte array (or NULL if there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *annotations; /* methods' unparsed annotations */
+ java_handle_t *method_annotations; /* all methods' unparsed annotations */
+ /* of the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ annotations = NULL;
+
+ LLNI_classinfo_field_get(c, method_annotations, method_annotations);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_annotations != NULL &&
+ array_length_get(method_annotations) > slot) {
+ annotations = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_annotations, slot);
+ }
+
+ return (java_handle_bytearray_t*)annotations;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_get_parameterannotations ********************************************
+
+ Get a methods' unparsed parameter annotations in an array of byte
+ arrays.
+
+ IN:
+ m........the method of which the parameter annotations should be
+ returned
+
+ RETURN VALUE:
+ The unparsed parameter annotations in a byte array (or NULL if
+ there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *parameterAnnotations; /* methods' unparsed */
+ /* parameter annotations */
+ java_handle_t *method_parameterannotations; /* all methods' unparsed */
+ /* parameter annotations of */
+ /* the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ parameterAnnotations = NULL;
+
+ LLNI_classinfo_field_get(
+ c, method_parameterannotations, method_parameterannotations);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_parameterannotations != NULL &&
+ array_length_get(method_parameterannotations) > slot) {
+ parameterAnnotations = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_parameterannotations,
+ slot);
+ }
+
+ return (java_handle_bytearray_t*)parameterAnnotations;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_get_annotationdefault ***********************************************
+
+ Get a methods' unparsed annotation default value in a byte array.
+
+ IN:
+ m........the method of which the annotation default value should be
+ returned
+
+ RETURN VALUE:
+ The unparsed annotation default value in a byte array (or NULL if
+ there isn't one).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *annotationDefault; /* methods' unparsed */
+ /* annotation default value */
+ java_handle_t *method_annotationdefaults; /* all methods' unparsed */
+ /* annotation default values of */
+ /* the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ annotationDefault = NULL;
+
+ LLNI_classinfo_field_get(
+ c, method_annotationdefaults, method_annotationdefaults);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_annotationdefaults != NULL &&
+ array_length_get(method_annotationdefaults) > slot) {
+ annotationDefault = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_annotationdefaults, slot);
+ }
+
+ return (java_handle_bytearray_t*)annotationDefault;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_add_to_worklist ******************************************************
+
+ Add the method to the given worklist. If the method already occurs in
+ the worklist, the worklist remains unchanged.
+
+*******************************************************************************/
+
+static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
+{
+ method_worklist *wi;
+
+ for (wi = *wl; wi != NULL; wi = wi->next)
+ if (wi->m == m)
+ return;
+
+ wi = NEW(method_worklist);
+ wi->next = *wl;
+ wi->m = m;
+
+ *wl = wi;
+}
+
+
+/* method_add_assumption_monomorphic *******************************************
+
+ Record the assumption that the method is monomorphic.
+
+ IN:
+ m.................the method
+ caller............the caller making the assumption
+
+*******************************************************************************/
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
+{
+ method_assumption *as;
+
+ /* XXX LOCKING FOR THIS FUNCTION? */
+
+ /* check if we already have registered this assumption */
+
+ for (as = m->assumptions; as != NULL; as = as->next) {
+ if (as->context == caller)
+ return;
+ }
+
+ /* register the assumption */
+
+ as = NEW(method_assumption);
+ as->next = m->assumptions;
+ as->context = caller;
+
+ m->assumptions = as;
+}
+
+/* method_break_assumption_monomorphic *****************************************
+
+ Break the assumption that this method is monomorphic. All callers that
+ have registered this assumption are added to the worklist.
+
+ IN:
+ m.................the method
+ wl................worklist where to add invalidated callers
+
+*******************************************************************************/
+
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
+{
+ method_assumption *as;
+
+ /* XXX LOCKING FOR THIS FUNCTION? */
+
+ for (as = m->assumptions; as != NULL; as = as->next) {
+ INLINELOG(
+ printf("ASSUMPTION BROKEN (monomorphism): ");
+ method_print(m);
+ printf(" in ");
+ method_println(as->context);
+ );
+
+ method_add_to_worklist(as->context, wl);
+
+#if defined(ENABLE_TLH) && 0
+ /* XXX hack */
+ method_assumption *as2;
+ as2 = m->assumptions;
+ m->assumptions = NULL;
+ method_break_assumption_monomorphic(as->context, wl);
+ /*
+ assert(m->assumptions == NULL);
+ m->assumptions = as2;*/
+#endif
+
+ }
+}
+
+/* method_printflags ***********************************************************
+
+ Prints the flags of a method to stdout like.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_printflags(methodinfo *m)
+{
+ if (m == NULL) {
+ printf("NULL");
+ return;
+ }
+
+ if (m->flags & ACC_PUBLIC) printf(" PUBLIC");
+ if (m->flags & ACC_PRIVATE) printf(" PRIVATE");
+ if (m->flags & ACC_PROTECTED) printf(" PROTECTED");
+ if (m->flags & ACC_STATIC) printf(" STATIC");
+ if (m->flags & ACC_FINAL) printf(" FINAL");
+ if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
+ if (m->flags & ACC_VOLATILE) printf(" VOLATILE");
+ if (m->flags & ACC_TRANSIENT) printf(" TRANSIENT");
+ if (m->flags & ACC_NATIVE) printf(" NATIVE");
+ if (m->flags & ACC_INTERFACE) printf(" INTERFACE");
+ if (m->flags & ACC_ABSTRACT) printf(" ABSTRACT");
+ if (m->flags & ACC_METHOD_BUILTIN) printf(" (builtin)");
+ if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
+ if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_print ****************************************************************
+
+ Prints a method to stdout like:
+
+ java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_print(methodinfo *m)
+{
+ if (m == NULL) {
+ printf("NULL");
+ return;
+ }
+
+ if (m->clazz != NULL)
+ utf_display_printable_ascii_classname(m->clazz->name);
+ else
+ printf("NULL");
+ printf(".");
+ utf_display_printable_ascii(m->name);
+ utf_display_printable_ascii(m->descriptor);
+
+ method_printflags(m);
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_println **************************************************************
+
+ Prints a method plus new line to stdout like:
+
+ java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_println(methodinfo *m)
+{
+ if (opt_debugcolor) printf("\033[31m"); /* red */
+ method_print(m);
+ if (opt_debugcolor) printf("\033[m");
+ printf("\n");
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_methodref_print ******************************************************
+
+ Prints a method reference to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_print(constant_FMIref *mr)
+{
+ if (!mr) {
+ printf("(constant_FMIref *)NULL");
+ return;
+ }
+
+ if (IS_FMIREF_RESOLVED(mr)) {
+ printf("<method> ");
+ method_print(mr->p.method);
+ }
+ else {
+ printf("<methodref> ");
+ utf_display_printable_ascii_classname(mr->p.classref->name);
+ printf(".");
+ utf_display_printable_ascii(mr->name);
+ utf_display_printable_ascii(mr->descriptor);
+ }
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_methodref_println ****************************************************
+
+ Prints a method reference to stdout, followed by a newline.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_println(constant_FMIref *mr)
+{
+ method_methodref_print(mr);
+ printf("\n");
+}
+#endif /* !defined(NDEBUG) */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+++ /dev/null
-/* src/vm/method.h - method functions header
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _METHOD_H
-#define _METHOD_H
-
-/* forward typedefs ***********************************************************/
-
-typedef struct methodinfo methodinfo;
-typedef struct raw_exception_entry raw_exception_entry;
-typedef struct lineinfo lineinfo;
-typedef struct method_assumption method_assumption;
-typedef struct method_worklist method_worklist;
-typedef struct codeinfo codeinfo;
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "threads/mutex.hpp"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/descriptor.h"
-#include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/references.h"
-
-#if defined(ENABLE_JAVASE)
-# include "vm/stackmap.h"
-#endif
-
-#include "vm/utf8.h"
-
-
-#if defined(ENABLE_REPLACEMENT)
-/* Initial value for the hit countdown field of each method. */
-#define METHOD_INITIAL_HIT_COUNTDOWN 1000
-#endif
-
-
-/* methodinfo *****************************************************************/
-
-struct methodinfo { /* method structure */
- Mutex *mutex; /* we need this in jit's locking */
- s4 flags; /* ACC flags */
- utf *name; /* name of method */
- utf *descriptor; /* JavaVM descriptor string of method */
-#if defined(ENABLE_JAVASE)
- utf *signature; /* Signature attribute */
- stack_map_t *stack_map; /* StackMapTable attribute */
-#endif
-
- methoddesc *parseddesc; /* parsed descriptor */
-
- classinfo *clazz; /* class, the method belongs to */
- s4 vftblindex; /* index of method in virtual function */
- /* table (if it is a virtual method) */
- s4 maxstack; /* maximum stack depth of method */
- s4 maxlocals; /* maximum number of local variables */
- s4 jcodelength; /* length of JavaVM code */
- u1 *jcode; /* pointer to JavaVM code */
-
- s4 rawexceptiontablelength; /* exceptiontable length */
- raw_exception_entry *rawexceptiontable; /* the exceptiontable */
-
- u2 thrownexceptionscount; /* number of exceptions attribute */
- classref_or_classinfo *thrownexceptions; /* except. a method may throw */
-
- u2 linenumbercount; /* number of linenumber attributes */
- lineinfo *linenumbers; /* array of lineinfo items */
-
- u1 *stubroutine; /* stub for compiling or calling natives */
- codeinfo *code; /* current code of this method */
-
-#if defined(ENABLE_LSRA)
- s4 maxlifetimes; /* helper for lsra */
-#endif
-
- methodinfo *overwrites; /* method that is directly overwritten */
- method_assumption *assumptions; /* list of assumptions about this method */
-
-#if defined(ENABLE_REPLACEMENT)
- s4 hitcountdown; /* decreased for each hit */
-#endif
-
-#if defined(ENABLE_DEBUG_FILTER)
- u1 filtermatches; /* flags indicating which filters the method matches */
-#endif
-
-#if defined(ENABLE_ESCAPE)
- u1 *paramescape;
-#endif
-};
-
-/* method_assumption ***********************************************************
-
- This struct is used for registering assumptions about methods.
-
-*******************************************************************************/
-
-struct method_assumption {
- method_assumption *next;
- methodinfo *context;
-};
-
-
-/* method_worklist *************************************************************
-
- List node used for method worklists.
-
-*******************************************************************************/
-
-struct method_worklist {
- method_worklist *next;
- methodinfo *m;
-};
-
-
-/* raw_exception_entry ********************************************************/
-
-/* exception table entry read by the loader */
-
-struct raw_exception_entry { /* exceptiontable entry in a method */
- classref_or_classinfo catchtype; /* catchtype of exc. (0 == catchall) */
- u2 startpc; /* start pc of guarded area (inclusive) */
- u2 endpc; /* end pc of guarded area (exklusive) */
- u2 handlerpc; /* pc of exception handler */
-};
-
-
-/* lineinfo *******************************************************************/
-
-struct lineinfo {
- u2 start_pc;
- u2 line_number;
-};
-
-
-/* global variables ***********************************************************/
-
-extern methodinfo *method_java_lang_reflect_Method_invoke;
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* inline functions ***********************************************************/
-
-inline static bool method_is_builtin(methodinfo* m)
-{
- return m->flags & ACC_METHOD_BUILTIN;
-}
-
-
-/* function prototypes ********************************************************/
-
-void method_init(void);
-
-bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool);
-void method_free(methodinfo *m);
-bool method_canoverwrite(methodinfo *m, methodinfo *old);
-
-methodinfo *method_new_builtin(builtintable_entry *bte);
-
-methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m);
-
-int32_t method_get_parametercount(methodinfo *m);
-java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m);
-java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m);
-classinfo *method_returntype_get(methodinfo *m);
-
-void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller);
-void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl);
-
-s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found);
-
-java_handle_bytearray_t *method_get_annotations(methodinfo *m);
-java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m);
-java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m);
-
-#if !defined(NDEBUG)
-void method_printflags(methodinfo *m);
-void method_print(methodinfo *m);
-void method_println(methodinfo *m);
-void method_methodref_print(constant_FMIref *mr);
-void method_methodref_println(constant_FMIref *mr);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _METHOD_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/method.hpp - method functions header
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _METHOD_H
+#define _METHOD_H
+
+/* forward typedefs ***********************************************************/
+
+typedef struct methodinfo methodinfo;
+typedef struct raw_exception_entry raw_exception_entry;
+typedef struct lineinfo lineinfo;
+typedef struct method_assumption method_assumption;
+typedef struct method_worklist method_worklist;
+typedef struct codeinfo codeinfo;
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/descriptor.h"
+#include "vm/global.h"
+#include "vm/linker.h"
+#include "vm/loader.hpp"
+#include "vm/references.h"
+
+#if defined(ENABLE_JAVASE)
+# include "vm/stackmap.h"
+#endif
+
+#include "vm/utf8.h"
+
+
+#if defined(ENABLE_REPLACEMENT)
+/* Initial value for the hit countdown field of each method. */
+#define METHOD_INITIAL_HIT_COUNTDOWN 1000
+#endif
+
+/* methodinfo *****************************************************************/
+
+struct methodinfo { /* method structure */
+ Mutex *mutex; /* we need this in jit's locking */
+ s4 flags; /* ACC flags */
+ utf *name; /* name of method */
+ utf *descriptor; /* JavaVM descriptor string of method */
+#if defined(ENABLE_JAVASE)
+ utf *signature; /* Signature attribute */
+ stack_map_t *stack_map; /* StackMapTable attribute */
+#endif
+
+ methoddesc *parseddesc; /* parsed descriptor */
+
+ classinfo *clazz; /* class, the method belongs to */
+ s4 vftblindex; /* index of method in virtual function */
+ /* table (if it is a virtual method) */
+ s4 maxstack; /* maximum stack depth of method */
+ s4 maxlocals; /* maximum number of local variables */
+ s4 jcodelength; /* length of JavaVM code */
+ u1 *jcode; /* pointer to JavaVM code */
+
+ s4 rawexceptiontablelength; /* exceptiontable length */
+ raw_exception_entry *rawexceptiontable; /* the exceptiontable */
+
+ u2 thrownexceptionscount; /* number of exceptions attribute */
+ classref_or_classinfo *thrownexceptions; /* except. a method may throw */
+
+ u2 linenumbercount; /* number of linenumber attributes */
+ lineinfo *linenumbers; /* array of lineinfo items */
+
+ u1 *stubroutine; /* stub for compiling or calling natives */
+ codeinfo *code; /* current code of this method */
+
+#if defined(ENABLE_LSRA)
+ s4 maxlifetimes; /* helper for lsra */
+#endif
+
+ methodinfo *overwrites; /* method that is directly overwritten */
+ method_assumption *assumptions; /* list of assumptions about this method */
+
+#if defined(ENABLE_REPLACEMENT)
+ s4 hitcountdown; /* decreased for each hit */
+#endif
+
+#if defined(ENABLE_DEBUG_FILTER)
+ u1 filtermatches; /* flags indicating which filters the method matches */
+#endif
+
+#if defined(ENABLE_ESCAPE)
+ u1 *paramescape;
+#endif
+};
+
+/* method_assumption ***********************************************************
+
+ This struct is used for registering assumptions about methods.
+
+*******************************************************************************/
+
+struct method_assumption {
+ method_assumption *next;
+ methodinfo *context;
+};
+
+
+/* method_worklist *************************************************************
+
+ List node used for method worklists.
+
+*******************************************************************************/
+
+struct method_worklist {
+ method_worklist *next;
+ methodinfo *m;
+};
+
+
+/* raw_exception_entry ********************************************************/
+
+/* exception table entry read by the loader */
+
+struct raw_exception_entry { /* exceptiontable entry in a method */
+ classref_or_classinfo catchtype; /* catchtype of exc. (0 == catchall) */
+ u2 startpc; /* start pc of guarded area (inclusive) */
+ u2 endpc; /* end pc of guarded area (exklusive) */
+ u2 handlerpc; /* pc of exception handler */
+};
+
+
+/* lineinfo *******************************************************************/
+
+struct lineinfo {
+ u2 start_pc;
+ u2 line_number;
+};
+
+
+/* global variables ***********************************************************/
+
+extern methodinfo *method_java_lang_reflect_Method_invoke;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* inline functions ***********************************************************/
+
+inline static bool method_is_builtin(methodinfo* m)
+{
+ return m->flags & ACC_METHOD_BUILTIN;
+}
+
+
+/* function prototypes ********************************************************/
+
+void method_init(void);
+
+bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool);
+void method_free(methodinfo *m);
+bool method_canoverwrite(methodinfo *m, methodinfo *old);
+
+methodinfo *method_new_builtin(builtintable_entry *bte);
+
+methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m);
+
+int32_t method_get_parametercount(methodinfo *m);
+java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m);
+java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m);
+classinfo *method_returntype_get(methodinfo *m);
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller);
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl);
+
+s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found);
+
+java_handle_bytearray_t *method_get_annotations(methodinfo *m);
+java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m);
+java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m);
+
+#if !defined(NDEBUG)
+void method_printflags(methodinfo *m);
+void method_print(methodinfo *m);
+void method_println(methodinfo *m);
+void method_methodref_print(constant_FMIref *mr);
+void method_methodref_println(constant_FMIref *mr);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _METHOD_H */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
#include "vm/class.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
#include "vm/properties.hpp"
#include "vm/descriptor.h"
#include "vm/field.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/utf8.h"
#include "mm/memory.h"
#include "vm/access.h"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/descriptor.h"
#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/class.hpp"
#include "vm/field.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/references.h"
#include "vm/jit/jit.hpp"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/signallocal.h"
#include "vm/vm.hpp"
#include "vm/class.hpp"
#include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/stackmap.h"
#include "vm/statistics.h"
#include "vm/global.h"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* verification_type_info *****************************************************/
full_frame_t full_frame;
};
+#if defined(__cplusplus)
+extern "C" {
+#endif
/* function prototypes ********************************************************/
bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* _STACKMAP_H */
#include "vm/class.hpp"
#include "vm/field.hpp"
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/statistics.h"
#include "vm/properties.hpp"
#include "vm/suck.hpp"
#include "vm/vm.hpp"
-#include "vm/zip.h"
+#include "vm/zip.hpp"
/* global variables ***********************************************************/
#endif
#include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/finalizer.h"
#include "vm/global.h"
// Includes.
#include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
/* These C methods are the exported interface. ********************************/
+++ /dev/null
-/* src/vm/zip.c - ZIP file handling for bootstrap classloader
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <zlib.h>
-#include <sys/mman.h>
-
-#include "vm/types.h"
-
-#include "vm/descriptor.h" /* needed to prevent circular dependency */
-#include "toolbox/hashtable.h"
-
-#include "mm/memory.h"
-
-#include "vm/global.h"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-#include "vm/vm.hpp"
-#include "vm/zip.h"
-
-
-/* start size for classes hashtable *******************************************/
-
-#define HASHTABLE_CLASSES_SIZE (1 << 10)
-
-
-/* info taken from:
- http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
-*/
-
-/* all signatures in the ZIP file have a length of 4 bytes ********************/
-
-#define SIGNATURE_LENGTH 4
-
-/* Central directory structure *************************************************
-
- [file header 1]
- .
- .
- .
- [file header n]
- [digital signature]
-
- File header:
-
- central file header signature 4 bytes (0x02014b50)
- version made by 2 bytes
- version needed to extract 2 bytes
- general purpose bit flag 2 bytes
- compression method 2 bytes
- last mod file time 2 bytes
- last mod file date 2 bytes
- crc-32 4 bytes
- compressed size 4 bytes
- uncompressed size 4 bytes
- file name length 2 bytes
- extra field length 2 bytes
- file comment length 2 bytes
- disk number start 2 bytes
- internal file attributes 2 bytes
- external file attributes 4 bytes
- relative offset of local header 4 bytes
-
- file name (variable size)
- extra field (variable size)
- file comment (variable size)
-
- Digital signature:
-
- header signature 4 bytes (0x05054b50)
- size of data 2 bytes
- signature data (variable size)
-
-*******************************************************************************/
-
-#define CDSFH_HEADER_SIZE 46
-
-#define CDSFH_SIGNATURE 0x02014b50
-#define CDSFH_COMPRESSION_METHOD 10
-#define CDSFH_COMPRESSED_SIZE 20
-#define CDSFH_UNCOMPRESSED_SIZE 24
-#define CDSFH_FILE_NAME_LENGTH 28
-#define CDSFH_EXTRA_FIELD_LENGTH 30
-#define CDSFH_FILE_COMMENT_LENGTH 32
-#define CDSFH_RELATIVE_OFFSET 42
-#define CDSFH_FILENAME 46
-
-typedef struct cdsfh cdsfh;
-
-struct cdsfh {
- u2 compressionmethod;
- u4 compressedsize;
- u4 uncompressedsize;
- u2 filenamelength;
- u2 extrafieldlength;
- u2 filecommentlength;
- u4 relativeoffset;
-};
-
-
-/* End of central directory record *********************************************
-
- end of central dir signature 4 bytes (0x06054b50)
- number of this disk 2 bytes
- number of the disk with the
- start of the central directory 2 bytes
- total number of entries in the
- central directory on this disk 2 bytes
- total number of entries in
- the central directory 2 bytes
- size of the central directory 4 bytes
- offset of start of central
- directory with respect to
- the starting disk number 4 bytes
- .ZIP file comment length 2 bytes
- .ZIP file comment (variable size)
-
-*******************************************************************************/
-
-#define EOCDR_SIGNATURE 0x06054b50
-#define EOCDR_ENTRIES 10
-#define EOCDR_OFFSET 16
-
-typedef struct eocdr eocdr;
-
-struct eocdr {
- u2 entries;
- u4 offset;
-};
-
-
-/* zip_open ********************************************************************
-
- XXX
-
-*******************************************************************************/
-
-hashtable *zip_open(char *path)
-{
- hashtable *ht;
- hashtable_zipfile_entry *htzfe;
- int fd;
- u1 lfh_signature[SIGNATURE_LENGTH];
- off_t len;
- u1 *filep;
- s4 i;
- u1 *p;
- eocdr eocdr;
- cdsfh cdsfh;
- const char *filename;
- const char *classext;
- utf *u;
- u4 key; /* hashkey computed from utf-text */
- u4 slot; /* slot in hashtable */
-
- /* first of all, open the file */
-
- if ((fd = open(path, O_RDONLY)) == -1)
- return NULL;
-
- /* check for signature in first local file header */
-
- if (read(fd, lfh_signature, SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
- return NULL;
-
- if (SUCK_LE_U4(lfh_signature) != LFH_SIGNATURE)
- return NULL;
-
- /* get the file length */
-
- if ((len = lseek(fd, 0, SEEK_END)) == -1)
- return NULL;
-
- /* we better mmap the file */
-
- filep = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
-
- /* some older compilers, like DEC OSF cc, don't like comparisons
- on void* types */
-
- if ((ptrint) filep == (ptrint) MAP_FAILED)
- return NULL;
-
- /* find end of central directory record */
-
- for (p = filep + len; p >= filep; p--)
- if (SUCK_LE_U4(p) == EOCDR_SIGNATURE)
- break;
-
- /* get number of entries in central directory */
-
- eocdr.entries = SUCK_LE_U2(p + EOCDR_ENTRIES);
- eocdr.offset = SUCK_LE_U4(p + EOCDR_OFFSET);
-
- /* create hashtable for filenames */
-
- ht = NEW(hashtable);
-
- hashtable_create(ht, HASHTABLE_CLASSES_SIZE);
-
- /* add all file entries into the hashtable */
-
- for (i = 0, p = filep + eocdr.offset; i < eocdr.entries; i++) {
- /* check file header signature */
-
- if (SUCK_LE_U4(p) != CDSFH_SIGNATURE)
- return NULL;
-
- /* we found an entry */
-
- cdsfh.compressionmethod = SUCK_LE_U2(p + CDSFH_COMPRESSION_METHOD);
- cdsfh.compressedsize = SUCK_LE_U4(p + CDSFH_COMPRESSED_SIZE);
- cdsfh.uncompressedsize = SUCK_LE_U4(p + CDSFH_UNCOMPRESSED_SIZE);
- cdsfh.filenamelength = SUCK_LE_U2(p + CDSFH_FILE_NAME_LENGTH);
- cdsfh.extrafieldlength = SUCK_LE_U2(p + CDSFH_EXTRA_FIELD_LENGTH);
- cdsfh.filecommentlength = SUCK_LE_U2(p + CDSFH_FILE_COMMENT_LENGTH);
- cdsfh.relativeoffset = SUCK_LE_U4(p + CDSFH_RELATIVE_OFFSET);
-
- /* create utf8 string of filename, strip .class from classes */
-
- filename = (const char *) (p + CDSFH_FILENAME);
- classext = filename + cdsfh.filenamelength - strlen(".class");
-
- /* skip directory entries */
-
- if (filename[cdsfh.filenamelength - 1] != '/') {
- if (strncmp(classext, ".class", strlen(".class")) == 0)
- u = utf_new(filename, cdsfh.filenamelength - strlen(".class"));
- else
- u = utf_new(filename, cdsfh.filenamelength);
-
- /* insert class into hashtable */
-
- htzfe = NEW(hashtable_zipfile_entry);
-
- htzfe->filename = u;
- htzfe->compressionmethod = cdsfh.compressionmethod;
- htzfe->compressedsize = cdsfh.compressedsize;
- htzfe->uncompressedsize = cdsfh.uncompressedsize;
- htzfe->data = filep + cdsfh.relativeoffset;
-
- /* get hashtable slot */
-
- key = utf_hashkey(u->text, u->blength);
- slot = key & (ht->size - 1);
-
- /* insert into external chain */
-
- htzfe->hashlink = ht->ptr[slot];
-
- /* insert hashtable zipfile entry */
-
- ht->ptr[slot] = htzfe;
- ht->entries++;
- }
-
- /* move to next central directory structure file header */
-
- p = p +
- CDSFH_HEADER_SIZE +
- cdsfh.filenamelength +
- cdsfh.extrafieldlength +
- cdsfh.filecommentlength;
- }
-
- /* return pointer to hashtable */
-
- return ht;
-}
-
-
-/* zip_find ********************************************************************
-
- Search for the given filename in the classpath entries of a zip file.
-
- NOTE: The '.class' extension is stripped when reading a zip file, so if
- you want to find a .class file, you must search for its name _without_
- the '.class' extension.
- XXX I dont like that, it makes foo and foo.class ambiguous. -Edwin
-
- IN:
- lce..........the classpath entries for the zip file
- u............the filename to look for
-
- RETURN VALUE:
- hashtable_zipfile_entry * of the entry if found, or
- NULL if not found
-
-*******************************************************************************/
-
-hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u)
-{
- hashtable *ht;
- u4 key; /* hashkey computed from utf-text */
- u4 slot; /* slot in hashtable */
- hashtable_zipfile_entry *htzfe; /* hashtable element */
-
- /* get classes hashtable from the classpath entry */
-
- ht = lce->htclasses;
-
- /* get the hashtable slot of the name searched */
-
- key = utf_hashkey(u->text, u->blength);
- slot = key & (ht->size - 1);
- htzfe = ht->ptr[slot];
-
- /* search external hash chain for utf-symbol */
-
- while (htzfe) {
- if (htzfe->filename == u)
- return htzfe;
-
- /* next element in external chain */
-
- htzfe = htzfe->hashlink;
- }
-
- /* file not found in this archive */
-
- return NULL;
-}
-
-
-/* zip_get ********************************************************************
-
- XXX
-
-*******************************************************************************/
-
-classbuffer *zip_get(list_classpath_entry *lce, classinfo *c)
-{
- hashtable_zipfile_entry *htzfe;
- lfh lfh;
- u1 *indata;
- u1 *outdata;
- z_stream zs;
- int err;
- classbuffer *cb;
-
- /* try to find the class in the current archive */
-
- htzfe = zip_find(lce, c->name);
-
- if (htzfe == NULL)
- return NULL;
-
- /* read stuff from local file header */
-
- lfh.filenamelength = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
- lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
-
- indata = htzfe->data +
- LFH_HEADER_SIZE +
- lfh.filenamelength +
- lfh.extrafieldlength;
-
- /* allocate buffer for uncompressed data */
-
- outdata = MNEW(u1, htzfe->uncompressedsize);
-
- /* how is the file stored? */
-
- switch (htzfe->compressionmethod) {
- case Z_DEFLATED:
- /* fill z_stream structure */
-
- zs.next_in = indata;
- zs.avail_in = htzfe->compressedsize;
- zs.next_out = outdata;
- zs.avail_out = htzfe->uncompressedsize;
-
- zs.zalloc = Z_NULL;
- zs.zfree = Z_NULL;
- zs.opaque = Z_NULL;
-
- /* initialize this inflate run */
-
- if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
- vm_abort("zip_get: inflateInit2 failed: %s", strerror(errno));
-
- /* decompress the file into buffer */
-
- err = inflate(&zs, Z_SYNC_FLUSH);
-
- if ((err != Z_STREAM_END) && (err != Z_OK))
- vm_abort("zip_get: inflate failed: %s", strerror(errno));
-
- /* finish this inflate run */
-
- if (inflateEnd(&zs) != Z_OK)
- vm_abort("zip_get: inflateEnd failed: %s", strerror(errno));
- break;
-
- case 0:
- /* uncompressed file, just copy the data */
- MCOPY(outdata, indata, u1, htzfe->compressedsize);
- break;
-
- default:
- vm_abort("zip_get: unknown compression method %d",
- htzfe->compressionmethod);
- }
-
- /* allocate classbuffer */
-
- cb = NEW(classbuffer);
-
- cb->clazz = c;
- cb->size = htzfe->uncompressedsize;
- cb->data = outdata;
- cb->pos = outdata;
- cb->path = lce->path;
-
- /* return the filled classbuffer structure */
-
- return cb;
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/zip.cpp - ZIP file handling for bootstrap classloader
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+#include <sys/mman.h>
+
+#include "vm/types.h"
+
+#include "vm/descriptor.h" /* needed to prevent circular dependency */
+#include "toolbox/hashtable.h"
+
+#include "mm/memory.h"
+
+#include "vm/global.h"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+#include "vm/zip.hpp"
+
+
+/* start size for classes hashtable *******************************************/
+
+#define HASHTABLE_CLASSES_SIZE (1 << 10)
+
+
+/* info taken from:
+ http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
+*/
+
+/* all signatures in the ZIP file have a length of 4 bytes ********************/
+
+#define SIGNATURE_LENGTH 4
+
+/* Central directory structure *************************************************
+
+ [file header 1]
+ .
+ .
+ .
+ [file header n]
+ [digital signature]
+
+ File header:
+
+ central file header signature 4 bytes (0x02014b50)
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+ file comment length 2 bytes
+ disk number start 2 bytes
+ internal file attributes 2 bytes
+ external file attributes 4 bytes
+ relative offset of local header 4 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ file comment (variable size)
+
+ Digital signature:
+
+ header signature 4 bytes (0x05054b50)
+ size of data 2 bytes
+ signature data (variable size)
+
+*******************************************************************************/
+
+#define CDSFH_HEADER_SIZE 46
+
+#define CDSFH_SIGNATURE 0x02014b50
+#define CDSFH_COMPRESSION_METHOD 10
+#define CDSFH_COMPRESSED_SIZE 20
+#define CDSFH_UNCOMPRESSED_SIZE 24
+#define CDSFH_FILE_NAME_LENGTH 28
+#define CDSFH_EXTRA_FIELD_LENGTH 30
+#define CDSFH_FILE_COMMENT_LENGTH 32
+#define CDSFH_RELATIVE_OFFSET 42
+#define CDSFH_FILENAME 46
+
+typedef struct cdsfh cdsfh;
+
+struct cdsfh {
+ u2 compressionmethod;
+ u4 compressedsize;
+ u4 uncompressedsize;
+ u2 filenamelength;
+ u2 extrafieldlength;
+ u2 filecommentlength;
+ u4 relativeoffset;
+};
+
+
+/* End of central directory record *********************************************
+
+ end of central dir signature 4 bytes (0x06054b50)
+ number of this disk 2 bytes
+ number of the disk with the
+ start of the central directory 2 bytes
+ total number of entries in the
+ central directory on this disk 2 bytes
+ total number of entries in
+ the central directory 2 bytes
+ size of the central directory 4 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes
+ .ZIP file comment length 2 bytes
+ .ZIP file comment (variable size)
+
+*******************************************************************************/
+
+#define EOCDR_SIGNATURE 0x06054b50
+#define EOCDR_ENTRIES 10
+#define EOCDR_OFFSET 16
+
+typedef struct eocdr eocdr;
+
+struct eocdr {
+ u2 entries;
+ u4 offset;
+};
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* zip_open ********************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+hashtable *zip_open(char *path)
+{
+ hashtable *ht;
+ hashtable_zipfile_entry *htzfe;
+ int fd;
+ u1 lfh_signature[SIGNATURE_LENGTH];
+ off_t len;
+ u1 *filep;
+ s4 i;
+ u1 *p;
+ eocdr eocdr;
+ cdsfh cdsfh;
+ const char *filename;
+ const char *classext;
+ utf *u;
+ u4 key; /* hashkey computed from utf-text */
+ u4 slot; /* slot in hashtable */
+
+ /* first of all, open the file */
+
+ if ((fd = open(path, O_RDONLY)) == -1)
+ return NULL;
+
+ /* check for signature in first local file header */
+
+ if (read(fd, lfh_signature, SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
+ return NULL;
+
+ if (SUCK_LE_U4(lfh_signature) != LFH_SIGNATURE)
+ return NULL;
+
+ /* get the file length */
+
+ if ((len = lseek(fd, 0, SEEK_END)) == -1)
+ return NULL;
+
+ /* we better mmap the file */
+
+ filep = (u1*) mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ /* some older compilers, like DEC OSF cc, don't like comparisons
+ on void* types */
+
+ if ((ptrint) filep == (ptrint) MAP_FAILED)
+ return NULL;
+
+ /* find end of central directory record */
+
+ for (p = filep + len; p >= filep; p--)
+ if (SUCK_LE_U4(p) == EOCDR_SIGNATURE)
+ break;
+
+ /* get number of entries in central directory */
+
+ eocdr.entries = SUCK_LE_U2(p + EOCDR_ENTRIES);
+ eocdr.offset = SUCK_LE_U4(p + EOCDR_OFFSET);
+
+ /* create hashtable for filenames */
+
+ ht = NEW(hashtable);
+
+ hashtable_create(ht, HASHTABLE_CLASSES_SIZE);
+
+ /* add all file entries into the hashtable */
+
+ for (i = 0, p = filep + eocdr.offset; i < eocdr.entries; i++) {
+ /* check file header signature */
+
+ if (SUCK_LE_U4(p) != CDSFH_SIGNATURE)
+ return NULL;
+
+ /* we found an entry */
+
+ cdsfh.compressionmethod = SUCK_LE_U2(p + CDSFH_COMPRESSION_METHOD);
+ cdsfh.compressedsize = SUCK_LE_U4(p + CDSFH_COMPRESSED_SIZE);
+ cdsfh.uncompressedsize = SUCK_LE_U4(p + CDSFH_UNCOMPRESSED_SIZE);
+ cdsfh.filenamelength = SUCK_LE_U2(p + CDSFH_FILE_NAME_LENGTH);
+ cdsfh.extrafieldlength = SUCK_LE_U2(p + CDSFH_EXTRA_FIELD_LENGTH);
+ cdsfh.filecommentlength = SUCK_LE_U2(p + CDSFH_FILE_COMMENT_LENGTH);
+ cdsfh.relativeoffset = SUCK_LE_U4(p + CDSFH_RELATIVE_OFFSET);
+
+ /* create utf8 string of filename, strip .class from classes */
+
+ filename = (const char *) (p + CDSFH_FILENAME);
+ classext = filename + cdsfh.filenamelength - strlen(".class");
+
+ /* skip directory entries */
+
+ if (filename[cdsfh.filenamelength - 1] != '/') {
+ if (strncmp(classext, ".class", strlen(".class")) == 0)
+ u = utf_new(filename, cdsfh.filenamelength - strlen(".class"));
+ else
+ u = utf_new(filename, cdsfh.filenamelength);
+
+ /* insert class into hashtable */
+
+ htzfe = NEW(hashtable_zipfile_entry);
+
+ htzfe->filename = u;
+ htzfe->compressionmethod = cdsfh.compressionmethod;
+ htzfe->compressedsize = cdsfh.compressedsize;
+ htzfe->uncompressedsize = cdsfh.uncompressedsize;
+ htzfe->data = filep + cdsfh.relativeoffset;
+
+ /* get hashtable slot */
+
+ key = utf_hashkey(u->text, u->blength);
+ slot = key & (ht->size - 1);
+
+ /* insert into external chain */
+
+ htzfe->hashlink = (hashtable_zipfile_entry*) ht->ptr[slot];
+
+ /* insert hashtable zipfile entry */
+
+ ht->ptr[slot] = htzfe;
+ ht->entries++;
+ }
+
+ /* move to next central directory structure file header */
+
+ p = p +
+ CDSFH_HEADER_SIZE +
+ cdsfh.filenamelength +
+ cdsfh.extrafieldlength +
+ cdsfh.filecommentlength;
+ }
+
+ /* return pointer to hashtable */
+
+ return ht;
+}
+
+
+/* zip_find ********************************************************************
+
+ Search for the given filename in the classpath entries of a zip file.
+
+ NOTE: The '.class' extension is stripped when reading a zip file, so if
+ you want to find a .class file, you must search for its name _without_
+ the '.class' extension.
+ XXX I dont like that, it makes foo and foo.class ambiguous. -Edwin
+
+ IN:
+ lce..........the classpath entries for the zip file
+ u............the filename to look for
+
+ RETURN VALUE:
+ hashtable_zipfile_entry * of the entry if found, or
+ NULL if not found
+
+*******************************************************************************/
+
+hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u)
+{
+ hashtable *ht;
+ u4 key; /* hashkey computed from utf-text */
+ u4 slot; /* slot in hashtable */
+ hashtable_zipfile_entry *htzfe; /* hashtable element */
+
+ /* get classes hashtable from the classpath entry */
+
+ ht = lce->htclasses;
+
+ /* get the hashtable slot of the name searched */
+
+ key = utf_hashkey(u->text, u->blength);
+ slot = key & (ht->size - 1);
+ htzfe = (hashtable_zipfile_entry*) ht->ptr[slot];
+
+ /* search external hash chain for utf-symbol */
+
+ while (htzfe) {
+ if (htzfe->filename == u)
+ return htzfe;
+
+ /* next element in external chain */
+
+ htzfe = htzfe->hashlink;
+ }
+
+ /* file not found in this archive */
+
+ return NULL;
+}
+
+
+/* zip_get ********************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+classbuffer *zip_get(list_classpath_entry *lce, classinfo *c)
+{
+ hashtable_zipfile_entry *htzfe;
+ lfh lfh;
+ u1 *indata;
+ u1 *outdata;
+ z_stream zs;
+ int err;
+ classbuffer *cb;
+
+ /* try to find the class in the current archive */
+
+ htzfe = zip_find(lce, c->name);
+
+ if (htzfe == NULL)
+ return NULL;
+
+ /* read stuff from local file header */
+
+ lfh.filenamelength = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
+ lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
+
+ indata = htzfe->data +
+ LFH_HEADER_SIZE +
+ lfh.filenamelength +
+ lfh.extrafieldlength;
+
+ /* allocate buffer for uncompressed data */
+
+ outdata = MNEW(u1, htzfe->uncompressedsize);
+
+ /* how is the file stored? */
+
+ switch (htzfe->compressionmethod) {
+ case Z_DEFLATED:
+ /* fill z_stream structure */
+
+ zs.next_in = indata;
+ zs.avail_in = htzfe->compressedsize;
+ zs.next_out = outdata;
+ zs.avail_out = htzfe->uncompressedsize;
+
+ zs.zalloc = Z_NULL;
+ zs.zfree = Z_NULL;
+ zs.opaque = Z_NULL;
+
+ /* initialize this inflate run */
+
+ if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
+ vm_abort("zip_get: inflateInit2 failed: %s", strerror(errno));
+
+ /* decompress the file into buffer */
+
+ err = inflate(&zs, Z_SYNC_FLUSH);
+
+ if ((err != Z_STREAM_END) && (err != Z_OK))
+ vm_abort("zip_get: inflate failed: %s", strerror(errno));
+
+ /* finish this inflate run */
+
+ if (inflateEnd(&zs) != Z_OK)
+ vm_abort("zip_get: inflateEnd failed: %s", strerror(errno));
+ break;
+
+ case 0:
+ /* uncompressed file, just copy the data */
+ MCOPY(outdata, indata, u1, htzfe->compressedsize);
+ break;
+
+ default:
+ vm_abort("zip_get: unknown compression method %d",
+ htzfe->compressionmethod);
+ }
+
+ /* allocate classbuffer */
+
+ cb = NEW(classbuffer);
+
+ cb->clazz = c;
+ cb->size = htzfe->uncompressedsize;
+ cb->data = outdata;
+ cb->pos = outdata;
+ cb->path = lce->path;
+
+ /* return the filled classbuffer structure */
+
+ return cb;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+++ /dev/null
-/* src/vm/zip.c - ZIP file handling for bootstrap classloader
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program 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.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _ZIP_H
-#define _ZIP_H
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "toolbox/hashtable.h"
-
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/loader.hpp"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-
-
-/* Local file header ***********************************************************
-
- local file header signature 4 bytes (0x04034b50)
- version needed to extract 2 bytes
- general purpose bit flag 2 bytes
- compression method 2 bytes
- last mod file time 2 bytes
- last mod file date 2 bytes
- crc-32 4 bytes
- compressed size 4 bytes
- uncompressed size 4 bytes
- file name length 2 bytes
- extra field length 2 bytes
-
- file name (variable size)
- extra field (variable size)
-
-*******************************************************************************/
-
-#define LFH_HEADER_SIZE 30
-
-#define LFH_SIGNATURE 0x04034b50
-#define LFH_FILE_NAME_LENGTH 26
-#define LFH_EXTRA_FIELD_LENGTH 28
-
-typedef struct lfh lfh;
-
-struct lfh {
- u2 compressionmethod;
- u4 compressedsize;
- u4 uncompressedsize;
- u2 filenamelength;
- u2 extrafieldlength;
-};
-
-/* hashtable_zipfile_entry ****************************************************/
-
-typedef struct hashtable_zipfile_entry hashtable_zipfile_entry;
-
-struct hashtable_zipfile_entry {
- utf *filename;
- u2 compressionmethod;
- u4 compressedsize;
- u4 uncompressedsize;
- u1 *data;
- hashtable_zipfile_entry *hashlink;
-};
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-hashtable *zip_open(char *path);
-hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u);
-classbuffer *zip_get(list_classpath_entry *lce, classinfo *c);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZIP_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
--- /dev/null
+/* src/vm/zip.cpp - ZIP file handling for bootstrap classloader
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _ZIP_HPP
+#define _ZIP_HPP
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "toolbox/hashtable.h"
+
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/loader.hpp"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+
+
+/* Local file header ***********************************************************
+
+ local file header signature 4 bytes (0x04034b50)
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+
+ file name (variable size)
+ extra field (variable size)
+
+*******************************************************************************/
+
+#define LFH_HEADER_SIZE 30
+
+#define LFH_SIGNATURE 0x04034b50
+#define LFH_FILE_NAME_LENGTH 26
+#define LFH_EXTRA_FIELD_LENGTH 28
+
+typedef struct lfh lfh;
+
+struct lfh {
+ u2 compressionmethod;
+ u4 compressedsize;
+ u4 uncompressedsize;
+ u2 filenamelength;
+ u2 extrafieldlength;
+};
+
+/* hashtable_zipfile_entry ****************************************************/
+
+typedef struct hashtable_zipfile_entry hashtable_zipfile_entry;
+
+struct hashtable_zipfile_entry {
+ utf *filename;
+ u2 compressionmethod;
+ u4 compressedsize;
+ u4 uncompressedsize;
+ u1 *data;
+ hashtable_zipfile_entry *hashlink;
+};
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+hashtable *zip_open(char *path);
+hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u);
+classbuffer *zip_get(list_classpath_entry *lce, classinfo *c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIP_HPP */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */