From: twisti Date: Mon, 29 Jan 2007 18:49:05 +0000 (+0000) Subject: * This is a rather huge commit, which changes the build order of X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=d362a578296d95d99d4c996a12d116ecbb809866;p=cacao.git * This is a rather huge commit, which changes the build order of various parts to be able to bootstrap cacaoh without any dependencies on a generated header file. I include the file list from SVN, so we can see what happened to the files. Here we go (D-files were mostly moved to src/vmcore): D src/vm/hashtable.h D src/vm/options.h M src/vm/properties.h D src/vm/zip.c D src/vm/class.c D src/vm/suck.c D src/vm/loader.c M src/vm/builtin.c M src/vm/string.c D src/vm/zip.h D src/vm/class.h D src/vm/rt-timing.c D src/vm/suck.h D src/vm/annotation.c M src/vm/builtin.h D src/vm/loader.h D src/vm/descriptor.c D src/vm/annotation.h D src/vm/rt-timing.h D src/vm/resolve.c D src/vm/method.c D src/vm/descriptor.h M src/vm/finalizer.c D src/vm/resolve.h D src/vm/method.h D src/vm/references.h D src/vm/classcache.c D src/vm/statistics.c D src/vm/classcache.h D src/vm/statistics.h M src/vm/initialize.c M src/vm/access.c D src/vm/stackmap.c M src/vm/jit/powerpc/linux/md-abi.c M src/vm/jit/powerpc/emit.c M src/vm/jit/powerpc/md.c M src/vm/jit/powerpc/codegen.c M src/vm/jit/powerpc/patcher.c M src/vm/jit/codegen-common.h M src/vm/jit/abi.h M src/vm/jit/stack.c M src/vm/jit/optimizing/profile.c M src/vm/jit/optimizing/recompile.c M src/vm/jit/optimizing/ifconv.c M src/vm/jit/optimizing/ifconv.h M src/vm/jit/code.c M src/vm/jit/tools/genoffsets.c M src/vm/jit/code.h M src/vm/jit/show.c M src/vm/jit/dseg.c M src/vm/jit/verify/typeinfo.h M src/vm/jit/verify/typecheck-typeinferer.c M src/vm/jit/verify/typecheck.c M src/vm/jit/verify/typecheck-stackbased.c M src/vm/jit/verify/typeinfo.c M src/vm/jit/dseg.h M src/vm/jit/loop/loop.h M src/vm/jit/loop/graph.h M src/vm/jit/allocator/simplereg.c M src/vm/jit/parse.c M src/vm/jit/asmpart.h M src/vm/jit/stacktrace.c M src/vm/jit/emit-common.c M src/vm/jit/jit.c M src/vm/jit/stacktrace.h M src/vm/jit/codegen-common.c M src/vm/jit/jit.h M src/vm/initialize.h M src/vm/access.h D src/vm/stackmap.h M src/vm/signal.c M src/vm/exceptions.c M src/vm/vm.c D src/vm/field.c D src/vm/linker.c M src/vm/exceptions.h M src/vm/stringlocal.h D src/vm/utf8.c D src/vm/field.h M src/vm/Makefile.am D src/vm/linker.h D src/vm/hashtable.c D src/vm/options.c D src/vm/utf8.h M src/vm/properties.c M src/vm/signallocal.h M src/cacao/Makefile.am M src/native/jni.c M src/native/vm/java_lang_Class.c M src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c M src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c M src/native/vm/gnu/java_security_VMAccessController.c M src/native/vm/gnu/java_lang_VMClassLoader.c M src/native/vm/gnu/java_lang_management_VMManagementFactory.c M src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c M src/native/vm/gnu/java_lang_VMClass.c M src/native/vm/gnu/java_lang_VMThread.c M src/native/vm/gnu/gnu_classpath_VMSystemProperties.c M src/native/vm/gnu/java_lang_reflect_Method.c M src/native/vm/gnu/java_lang_VMRuntime.c M src/native/vm/gnu/java_lang_reflect_Field.c M src/native/vm/gnu/gnu_classpath_VMStackWalker.c M src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c M src/native/vm/gnu/java_lang_reflect_Constructor.c M src/native/vm/gnu/java_lang_VMThrowable.c M src/native/vm/java_lang_Object.c M src/native/vm/java_lang_Thread.c D src/native/include/java_lang_Thread.h D src/native/include/java_lang_Throwable.h D src/native/include/java_util_Properties.h D src/native/include/java_lang_VMThread.h D src/native/include/java_lang_VMThrowable.h D src/native/include/java_lang_ClassLoader.h M src/native/include/Makefile.am D src/native/include/java_lang_Cloneable.h D src/native/include/java_lang_ThreadGroup.h D src/native/include/java_lang_Class.h D src/native/include/java_lang_Object.h D src/native/include/java_lang_String.h M src/native/jni.h M src/native/native.c M src/native/native.h A src/toolbox/hashtable.h M src/toolbox/list.c M src/toolbox/avl.c M src/toolbox/logging.c M src/toolbox/Makefile.am M src/toolbox/logging.h A src/toolbox/hashtable.c M src/mm/gc-common.h M src/mm/Makefile.am M src/mm/memory.c M src/mm/boehm.c M src/Makefile.am M src/threads/none/threads.h M src/threads/none/lock.h M src/threads/native/threads.h M src/threads/native/lock.c M src/threads/native/threads.c AM src/vmcore A src/vmcore/options.h A src/vmcore/zip.c A src/vmcore/suck.c A src/vmcore/class.c A src/vmcore/loader.c A src/vmcore/zip.h A src/vmcore/annotation.c A src/vmcore/suck.h A src/vmcore/class.h A src/vmcore/rt-timing.c A src/vmcore/loader.h A src/vmcore/descriptor.c A src/vmcore/resolve.c A src/vmcore/annotation.h A src/vmcore/rt-timing.h A src/vmcore/method.c A src/vmcore/descriptor.h A src/vmcore/resolve.h A src/vmcore/method.h A src/vmcore/references.h A src/vmcore/classcache.c A src/vmcore/statistics.c A src/vmcore/.cvsignore A src/vmcore/classcache.h A src/vmcore/statistics.h A src/vmcore/stackmap.c A src/vmcore/stackmap.h A src/vmcore/field.c A src/vmcore/linker.c A src/vmcore/utf8.c A src/vmcore/field.h A src/vmcore/Makefile.am A src/vmcore/linker.h A src/vmcore/options.c A src/vmcore/utf8.h M src/cacaoh/cacaoh.c M src/cacaoh/headers.h M src/cacaoh/Makefile.am M src/cacaoh/headers.c A src/cacaoh/dummy.c M configure.ac --HG-- rename : src/vm/hashtable.c => src/toolbox/hashtable.c rename : src/vm/hashtable.h => src/toolbox/hashtable.h rename : src/vm/annotation.c => src/vmcore/annotation.c rename : src/vm/annotation.h => src/vmcore/annotation.h rename : src/vm/class.c => src/vmcore/class.c rename : src/vm/class.h => src/vmcore/class.h rename : src/vm/classcache.c => src/vmcore/classcache.c rename : src/vm/classcache.h => src/vmcore/classcache.h rename : src/vm/descriptor.c => src/vmcore/descriptor.c rename : src/vm/descriptor.h => src/vmcore/descriptor.h rename : src/vm/field.c => src/vmcore/field.c rename : src/vm/field.h => src/vmcore/field.h rename : src/vm/linker.c => src/vmcore/linker.c rename : src/vm/linker.h => src/vmcore/linker.h rename : src/vm/loader.c => src/vmcore/loader.c rename : src/vm/loader.h => src/vmcore/loader.h rename : src/vm/method.c => src/vmcore/method.c rename : src/vm/method.h => src/vmcore/method.h rename : src/vm/options.c => src/vmcore/options.c rename : src/vm/options.h => src/vmcore/options.h rename : src/vm/references.h => src/vmcore/references.h rename : src/vm/resolve.c => src/vmcore/resolve.c rename : src/vm/resolve.h => src/vmcore/resolve.h rename : src/vm/rt-timing.c => src/vmcore/rt-timing.c rename : src/vm/rt-timing.h => src/vmcore/rt-timing.h rename : src/vm/stackmap.c => src/vmcore/stackmap.c rename : src/vm/stackmap.h => src/vmcore/stackmap.h rename : src/vm/statistics.c => src/vmcore/statistics.c rename : src/vm/statistics.h => src/vmcore/statistics.h rename : src/vm/suck.c => src/vmcore/suck.c rename : src/vm/suck.h => src/vmcore/suck.h rename : src/vm/utf8.c => src/vmcore/utf8.c rename : src/vm/utf8.h => src/vmcore/utf8.h rename : src/vm/zip.c => src/vmcore/zip.c rename : src/vm/zip.h => src/vmcore/zip.h --- diff --git a/configure.ac b/configure.ac index d40e88b9b..b7568ab3a 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA dnl 02110-1301, USA. dnl -dnl $Id: configure.ac 7241 2007-01-27 15:52:01Z twisti $ +dnl $Id: configure.ac 7246 2007-01-29 18:49:05Z twisti $ dnl Process this file with autoconf to produce a configure script. @@ -1066,13 +1066,14 @@ AC_CONFIG_FILES([Makefile] [src/vm/jit/powerpc/netbsd/Makefile] [src/vm/jit/powerpc64/Makefile] [src/vm/jit/powerpc64/linux/Makefile] + [src/vm/jit/s390/Makefile] [src/vm/jit/schedule/Makefile] [src/vm/jit/sparc64/Makefile] [src/vm/jit/sparc64/linux/Makefile] [src/vm/jit/tools/Makefile] [src/vm/jit/verify/Makefile] [src/vm/jit/x86_64/Makefile] - [src/vm/jit/s390/Makefile] + [src/vmcore/Makefile] [tests/Makefile] [tests/regression/Makefile] [tests/regression/codepatching/Makefile] diff --git a/src/Makefile.am b/src/Makefile.am index d64def12f..a2f02acc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ ## src/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,42 +22,41 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ## 02110-1301, USA. ## -## Contact: cacao@cacaojvm.org -## -## Authors: Christian Thalinger -## -## $Id: Makefile.am 6243 2006-12-27 13:56:31Z twisti $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in DIST_SUBDIRS = \ - mm \ - lib \ + cacao \ + cacaoh \ fdlibm \ + lib \ + mm \ + native \ + scripts \ + threads \ toolbox \ vm \ - threads \ - cacaoh \ - native \ - cacao \ - scripts + vmcore if WITH_CLASSPATH_GNU VM_DIR = \ lib endif -# Keep this order!!! +# DON'T CHANGE THIS ORDER!!! SUBDIRS = \ - mm \ - $(VM_DIR) \ - fdlibm \ toolbox \ - vm \ - threads \ + vmcore \ cacaoh \ + \ + $(VM_DIR) \ native \ + fdlibm \ + mm \ + threads \ + vm \ cacao \ scripts diff --git a/src/cacao/Makefile.am b/src/cacao/Makefile.am index 51c3f728a..8b0c55f27 100644 --- a/src/cacao/Makefile.am +++ b/src/cacao/Makefile.am @@ -1,6 +1,6 @@ ## src/cacao/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -24,11 +24,7 @@ ## ## Contact: cacao@cacaojvm.org ## -## Authors: Christian Thalinger -## -## Changes: -## -## $Id: Makefile.am 5884 2006-10-31 20:11:28Z twisti $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in @@ -109,6 +105,7 @@ libjvm_la_LIBADD = \ $(top_builddir)/src/native/libnative.la \ $(top_builddir)/src/toolbox/libtoolbox.la \ $(top_builddir)/src/vm/libvm.la \ + $(top_builddir)/src/vmcore/libvmcore.la \ $(GC_LIB) \ $(THREAD_LIB) diff --git a/src/cacaoh/Makefile.am b/src/cacaoh/Makefile.am index 85b18f932..5e2e8136f 100644 --- a/src/cacaoh/Makefile.am +++ b/src/cacaoh/Makefile.am @@ -1,6 +1,6 @@ ## src/cacaoh/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,23 +22,12 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ## 02110-1301, USA. ## -## Contact: cacao@cacaojvm.org -## -## Authors: Christian Thalinger -## -## Changes: -## -## $Id: Makefile.am 5884 2006-10-31 20:11:28Z twisti $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR) -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR)/$(OS_DIR) -if ENABLE_THREADS -THREAD_LIB = \ - $(top_builddir)/src/threads/native/libthreads.la -endif - if ENABLE_RT_TIMING cacaoh_LDFLAGS = -lrt endif @@ -47,24 +36,22 @@ noinst_LTLIBRARIES = \ libcacaoh.la libcacaoh_la_SOURCES = \ + dummy.c \ headers.c \ headers.h libcacaoh_la_LIBADD = \ - $(top_builddir)/src/mm/libmm.la \ - $(THREAD_LIB) \ $(top_builddir)/src/toolbox/libtoolbox.la \ - $(top_builddir)/src/vm/libvmcore.la + $(top_builddir)/src/vmcore/libvmcore.la -noinst_PROGRAMS = cacaoh +noinst_PROGRAMS = \ + cacaoh cacaoh_SOURCES = \ cacaoh.c cacaoh_LDADD = \ - libcacaoh.la \ - $(top_builddir)/src/fdlibm/libfdlibm.la \ - $(GC_LIB) + libcacaoh.la cacaoh_DEPENDENCIES = \ $(cacaoh_LDADD) diff --git a/src/cacaoh/cacaoh.c b/src/cacaoh/cacaoh.c index 5a64b73fb..757c14450 100644 --- a/src/cacaoh/cacaoh.c +++ b/src/cacaoh/cacaoh.c @@ -1,6 +1,6 @@ /* src/cacaoh/cacaoh.c - main for header generation (cacaoh) - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,14 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Mark Probst - Philipp Tomsich - Christian Thalinger - - $Id: cacaoh.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: cacaoh.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -43,23 +36,23 @@ #include "vm/types.h" #include "cacaoh/headers.h" + #include "mm/gc-common.h" #include "mm/memory.h" -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif - +#include "toolbox/hashtable.h" #include "toolbox/logging.h" -#include "vm/classcache.h" + #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" -#include "vm/suck.h" +#include "vm/vm.h" + +#include "vmcore/classcache.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/statistics.h" +#include "vmcore/suck.h" /* define heap sizes **********************************************************/ @@ -99,7 +92,7 @@ opt_struct opts[] = { *******************************************************************************/ -static void usage(void) +void usage(void) { printf("Usage: cacaoh [options] \n" "\n" @@ -126,7 +119,7 @@ static void usage(void) static void version(void) { printf("cacaoh version "VERSION"\n"); - printf("Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,\n"); + printf("Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,\n"); printf("C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,\n"); printf("E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,\n"); printf("J. Wenninger, Institut f. Computersprachen - TU Wien\n\n"); @@ -148,7 +141,6 @@ static void version(void) /* forward declarations *******************************************************/ static JavaVMInitArgs *cacaoh_options_prepare(int argc, char **argv); -static void cacaoh_abort(const char *text, ...); /* main ************************************************************************ @@ -282,41 +274,24 @@ int main(int argc, char **argv) log_init(NULL); log_println("Java - header-generator started"); } - -#if defined(ENABLE_THREADS) - /* pre-initialize some core thread stuff, like the stopworldlock, - thus this has to happen _before_ gc_init()!!! */ - - threads_preinit(); -#endif - - /* initialize the garbage collector */ - - gc_init(heapmaxsize, heapstartsize); - - /* initialize the string hashtable stuff: lock (must be done - _after_ threads_preinit) */ - - if (!string_init()) - cacaoh_abort("string_init failed\n"); /* initialize the utf8 hashtable stuff: lock, often used utf8 strings (must be done _after_ threads_preinit) */ if (!utf8_init()) - cacaoh_abort("utf8_init failed\n"); + vm_abort("utf8_init failed\n"); /* initialize the classcache hashtable stuff: lock, hashtable (must be done _after_ threads_preinit) */ if (!classcache_init()) - cacaoh_abort("classcache_init failed\n"); + vm_abort("classcache_init failed\n"); /* initialize the loader with bootclasspath (must be done _after_ thread_preinit) */ if (!suck_init()) - cacaoh_abort("suck_init failed\n"); + vm_abort("suck_init failed\n"); suck_add(bootclasspath); @@ -329,7 +304,7 @@ int main(int argc, char **argv) classcache_init) */ if (!loader_init()) - cacaoh_abort("loader_init failed\n"); + vm_abort("loader_init failed\n"); /* load Java classes ******************************************************/ @@ -353,10 +328,10 @@ int main(int argc, char **argv) /* exceptions are catched with new_exception call */ if (!(c = load_class_bootstrap(utf_new_char(cp)))) - cacaoh_abort("java.lang.NoClassDefFoundError: %s\n", cp); + vm_abort("java.lang.NoClassDefFoundError: %s\n", cp); if (!link_class(c)) - cacaoh_abort("java.lang.LinkageError: %s\n", cp); + vm_abort("java.lang.LinkageError: %s\n", cp); headerfile_generate(c, opt_directory); } @@ -368,7 +343,7 @@ int main(int argc, char **argv) if (opt_verbose) { log_println("Java - header-generator stopped"); #if defined(ENABLE_STATISTICS) - mem_usagelog(true); + statistics_print_memory_usage(); #endif } @@ -399,32 +374,6 @@ static JavaVMInitArgs *cacaoh_options_prepare(int argc, char **argv) } -/* cacaoh_abort **************************************************************** - - Prints an error message and aborts the VM. - -*******************************************************************************/ - -static void cacaoh_abort(const char *text, ...) -{ - va_list ap; - - /* print the log message */ - - log_start(); - - va_start(ap, text); - log_vprint(text, ap); - va_end(ap); - - log_finish(); - - /* now abort the VM */ - - abort(); -} - - /* * 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 diff --git a/src/cacaoh/dummy.c b/src/cacaoh/dummy.c new file mode 100644 index 000000000..bd5b34ca1 --- /dev/null +++ b/src/cacaoh/dummy.c @@ -0,0 +1,497 @@ +/* src/cacaoh/dummy.c - dummy functions for cacaoh + + Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: headers.c 6286 2007-01-10 10:03:38Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include + +#include "toolbox/logging.h" + +#include "vm/types.h" + +#include "vm/global.h" +#include "vm/vm.h" + +#include "vm/jit/code.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/utf8.h" + + +/* global variables ***********************************************************/ + +char *_Jv_bootclasspath; + + +void compiler_lock() +{ +} + +void compiler_unlock() +{ +} + +java_objectheader *javastring_new_slash_to_dot(utf *u) +{ + vm_abort("javastring_new_slash_to_dot"); + + return NULL; +} + + +/* access *********************************************************************/ + +bool access_is_accessible_class(classinfo *referer, classinfo *cls) +{ + return true; +} + +bool access_is_accessible_member(classinfo *referer, classinfo *declarer, + s4 memberflags) +{ + vm_abort("access_is_accessible_member"); + + return true; +} + + +/* asm ************************************************************************/ + +void asm_abstractmethoderror(void) +{ + abort(); +} + + +/* builtin ********************************************************************/ + +java_objectheader *builtin_clone(void *env, java_objectheader *o) +{ + abort(); +} + +s4 builtin_isanysubclass(classinfo *sub, classinfo *super) +{ + abort(); +} + +java_objectheader *builtin_new(classinfo *c) +{ + abort(); +} + + +/* code ***********************************************************************/ + +void code_free_code_of_method(methodinfo *m) +{ +} + + +/* codegen ********************************************************************/ + +codeinfo *codegen_createnativestub(functionptr f, methodinfo *m) +{ + return NULL; +} + +u1 *createcompilerstub(methodinfo *m) +{ + return NULL; +} + +#if defined(ENABLE_INTRP) +u1 *intrp_createcompilerstub(methodinfo *m) +{ + return NULL; +} +#endif + +void removecompilerstub(u1 *stub) +{ +} + +void removenativestub(u1 *stub) +{ +} + + +/* exceptions *****************************************************************/ + +void exceptions_clear_exception(void) +{ +} + +void exceptions_print_current_exception(void) +{ +} + +void exceptions_throw_abstractmethoderror(void) +{ + fprintf(stderr, "java.lang.AbstractMethodError\n"); + + abort(); +} + +void exceptions_throw_classcircularityerror(classinfo *c) +{ + fprintf(stderr, "java.lang.ClassCircularityError: "); + + utf_display_printable_ascii(c->name); + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_classformaterror(classinfo *c, const char *message, ...) +{ + va_list ap; + + fprintf(stderr, "java.lang.ClassFormatError: "); + + utf_display_printable_ascii(c->name); + fprintf(stderr, ": "); + + va_start(ap, message); + vfprintf(stderr, message, ap); + va_end(ap); + + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_incompatibleclasschangeerror(classinfo *c) +{ + fprintf(stderr, "java.lang.IncompatibleClassChangeError: "); + + if (c != NULL) + utf_fprint_printable_ascii_classname(stderr, c->name); + + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_internalerror(const char *message, ...) +{ + va_list ap; + + fprintf(stderr, "java.lang.InternalError: "); + + va_start(ap, message); + vfprintf(stderr, message, ap); + va_end(ap); + + abort(); +} + +void exceptions_throw_linkageerror(const char *message, classinfo *c) +{ + fprintf(stderr, "java.lang.LinkageError: %s", message); + + if (c != NULL) + utf_fprint_printable_ascii_classname(stderr, c->name); + + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_noclassdeffounderror(utf *name) +{ + fprintf(stderr, "java.lang.NoClassDefFoundError: "); + utf_fprint_printable_ascii(stderr, name); + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_outofmemoryerror(void) +{ + fprintf(stderr, "java.lang.OutOfMemoryError\n"); + + abort(); +} + +void exceptions_throw_verifyerror(methodinfo *m, const char *message) +{ + fprintf(stderr, "java.lang.VerifyError: "); + utf_fprint_printable_ascii(stderr, m->name); + fprintf(stderr, ": %s", message); + + abort(); +} + +void exceptions_throw_nosuchfielderror(classinfo *c, utf *name) +{ + fprintf(stderr, "java.lang.NoSuchFieldError: "); + utf_fprint_printable_ascii(stderr, c->name); + fprintf(stderr, "."); + utf_fprint_printable_ascii(stderr, name); + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_nosuchmethoderror(classinfo *c, utf *name, utf *desc) +{ + fprintf(stderr, "java.lang.NoSuchMethodError: "); + utf_fprint_printable_ascii(stderr, c->name); + fprintf(stderr, "."); + utf_fprint_printable_ascii(stderr, name); + utf_fprint_printable_ascii(stderr, desc); + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_unsupportedclassversionerror(classinfo *c, + const char *message, ...) +{ + va_list ap; + + fprintf(stderr, "java.lang.UnsupportedClassVersionError: " ); + + utf_display_printable_ascii(c->name); + fprintf(stderr, ": "); + + va_start(ap, message); + vfprintf(stderr, message, ap); + va_end(ap); + + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_illegalaccessexception(classinfo *c) +{ + fprintf(stderr, "java.lang.IllegalAccessException: "); + + if (c != NULL) + utf_fprint_printable_ascii_classname(stderr, c->name); + + fputc('\n', stderr); + + abort(); +} + +void exceptions_throw_nullpointerexception(void) +{ + fprintf(stderr, "java.lang.NullPointerException\n"); + + abort(); +} + +void classnotfoundexception_to_noclassdeffounderror(void) +{ + /* Can that one happen? */ + + abort(); +} + + +/* finalizer ******************************************************************/ + +void finalizer_notify(void) +{ + vm_abort("finalizer_notify"); +} + +void finalizer_run(void *o, void *p) +{ + vm_abort("finalizer_run"); +} + + +/* heap ***********************************************************************/ + +void *heap_alloc_uncollectable(u4 bytelength) +{ + return calloc(bytelength, 1); +} + + +/* jit ************************************************************************/ + +void jit_invalidate_code(methodinfo *m) +{ + vm_abort("jit_invalidate_code"); +} + + +/* lock ***********************************************************************/ + +void lock_init_object_lock(java_objectheader *o) +{ +} + +bool lock_monitor_enter(java_objectheader *o) +{ + return true; +} + +bool lock_monitor_exit(java_objectheader *o) +{ + return true; +} + + +/* md *************************************************************************/ + +void md_param_alloc(methoddesc *md) +{ +} + + +/* memory *********************************************************************/ + +void *mem_alloc(s4 size) +{ + return malloc(size); +} + +void *mem_realloc(void *src, s4 len1, s4 len2) +{ + return realloc(src, len2); +} + +void mem_free(void *m, s4 size) +{ + free(m); +} + +void *dump_alloc(s4 size) +{ + return malloc(size); +} + +void dump_release(s4 size) +{ +} + +s4 dump_size(void) +{ + return 0; +} + + +/* properties *****************************************************************/ + +char *properties_get(char *key) +{ + return NULL; +} + + +/* stacktrace *****************************************************************/ + +java_objectarray *stacktrace_getClassContext() +{ + return NULL; +} + + +/* threads ********************************************************************/ + +pthread_key_t threads_current_threadobject_key; + + +/* typeinfo *******************************************************************/ + +bool typeinfo_init_class(typeinfo *info, classref_or_classinfo c) +{ + return true; +} + +void typeinfo_init_classinfo(typeinfo *info, classinfo *c) +{ +} + +typecheck_result typeinfo_is_assignable_to_class(typeinfo *value, classref_or_classinfo dest) +{ + return typecheck_TRUE; +} + + +/* vm *************************************************************************/ + +void vm_abort(const char *text, ...) +{ + va_list ap; + + /* print the log message */ + + va_start(ap, text); + vfprintf(stderr, text, ap); + va_end(ap); + + /* now abort the VM */ + + abort(); +} + +java_objectheader *vm_call_method(methodinfo *m, java_objectheader *o, ...) +{ + return NULL; +} + + +/* XXX */ + +void stringtable_update(void) +{ + log_println("stringtable_update: REMOVE ME!"); +} + +java_objectheader *literalstring_new(utf *u) +{ + log_println("literalstring_new: REMOVE ME!"); + + return NULL; +} + + +/* + * 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: + */ diff --git a/src/cacaoh/headers.c b/src/cacaoh/headers.c index 1aee58958..4d779ed43 100644 --- a/src/cacaoh/headers.c +++ b/src/cacaoh/headers.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: headers.c 7228 2007-01-19 01:13:48Z edwin $ + $Id: headers.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -46,492 +46,20 @@ #include "mm/gc-common.h" #include "mm/memory.h" -#include "native/include/java_lang_String.h" -#include "native/include/java_lang_Throwable.h" + #include "toolbox/chain.h" #include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/global.h" -#include "vm/method.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" -#include "vm/jit/asmpart.h" - - -/* Invocation API variables ***************************************************/ - -_Jv_JavaVM *_Jv_jvm; /* denotes a Java VM */ -char *_Jv_bootclasspath; - -char *cacao_prefix; -char *classpath_libdir; - -char *_Jv_classpath; -char *_Jv_java_library_path; - -#if defined(ENABLE_INTRP) -/* dummy interpreter stack to keep the compiler happy */ - -u1 *intrp_main_stack; -#endif - - -/* for raising exceptions from native methods *********************************/ - -#if !defined(ENABLE_THREADS) -java_objectheader *_no_threads_exceptionptr = NULL; -#endif - - -/* replace some non-vmcore functions ******************************************/ - -functionptr native_findfunction(utf *cname, utf *mname, utf *desc, - bool isstatic) -{ - /* return something different than NULL, otherwise we get an exception */ - - return (functionptr) 1; -} - -java_objectheader *native_new_and_init(classinfo *c) { return NULL; } -java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s) { return NULL; } -java_objectheader *native_new_and_init_int(classinfo *c, s4 i) { return NULL; } -java_objectheader *native_new_and_init_throwable(classinfo *c, java_lang_Throwable *t) { return NULL; } - - -java_objectheader *vm_call_method(methodinfo *m, java_objectheader *o, ...) -{ return NULL; } - -void vm_abort(const char *text, ...) -{ - va_list ap; - - /* print the log message */ - - va_start(ap, text); - vfprintf(stderr, text, ap); - va_end(ap); - - /* now abort the VM */ - - abort(); -} - -/* code patching functions */ -void patcher_builtin_arraycheckcast(u1 *sp) {} - - -long compare_and_swap(volatile long *p, long oldval, long newval) -{ - if (*p == oldval) { - *p = newval; - return oldval; - } - else - return *p; - - return oldval; -} - -long asm_compare_and_swap(volatile long *p, long oldval, long newval) -{ - if (*p == oldval) { - *p = newval; - return oldval; - } - else - return *p; - - return oldval; -} - -void asm_memory_barrier(void) -{ -} - - -u1 *createcompilerstub(methodinfo *m) { return NULL; } -#if defined(ENABLE_INTRP) -u1 *intrp_createcompilerstub(methodinfo *m) { return NULL; } -#endif - -codeinfo *codegen_createnativestub(functionptr f, methodinfo *m) { return NULL; } - -void removecompilerstub(u1 *stub) {} -void removenativestub(u1 *stub) {} - -void asm_perform_threadswitch(u1 **from, u1 **to, u1 **stackTop) {} -u1* asm_initialize_thread_stack(void *func, u1 *stack) { return NULL; } - -void *asm_switchstackandcall(void *stack, void *func, void **stacktopsave, void * p) { return NULL; } - -void asm_handle_builtin_exception(classinfo *c) {} - -#if defined(ENABLE_JIT) -void asm_abstractmethoderror(void) {} -void asm_getclassvalues_atomic(vftbl_t *super, vftbl_t *sub, castinfo *out) {} -#endif - -#if defined(ENABLE_INTRP) -void intrp_asm_abstractmethoderror(void) {} -void intrp_asm_getclassvalues_atomic(vftbl_t *super, vftbl_t *sub, castinfo *out) {} -#endif - -u8 asm_get_cycle_count(void) -{ - return 0; -} - - -void *Java_java_lang_VMObject_clone(void *env, void *clazz, void * this) -{ - return NULL; -} - -typecheck_result typeinfo_is_assignable_to_class(typeinfo *value,classref_or_classinfo dest) -{ - return typecheck_TRUE; -} - -void typeinfo_init_classinfo(typeinfo *info,classinfo *c) -{ -} - -bool typeinfo_init_class(typeinfo *info,classref_or_classinfo c) -{ - return true; -} - -void typeinfo_print(FILE *file,typeinfo *info,int indent) {} -void typeinfo_print_short(FILE *file,typeinfo *info) {} - -void exceptions_print_exception(java_objectheader *xptr) {} -void stacktrace_dump_trace(threadobject *thread) {} -void stacktrace_print_trace(java_objectheader *xptr) {} -java_objectarray *stacktrace_getClassContext() { return NULL; } -void code_free_code_of_method(methodinfo *m) {} - -void jit_invalidate_code(methodinfo *m) {} - - -/* exception functions ********************************************************/ - -/* these should not be called */ - -void throw_main_exception_exit(void) { assert(0); } -void throw_exception(void) { assert(0); } -void throw_exception_exit(void) { assert(0); } - -void exceptions_throw_verifyerror(methodinfo *m, const char *message) -{ - assert(0); -} - -java_objectheader *new_exception_throwable(const char *classname, java_lang_Throwable *throwable) -{ - assert(0); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_exception(const char *classname) -{ - fprintf(stderr, "%s\n", classname); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_exception_message(const char *classname, const char *message) -{ - fprintf(stderr, "%s: %s\n", classname, message); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_exception_utfmessage(const char *classname, utf *message) -{ - fprintf(stderr, "%s: ", classname); - utf_display_printable_ascii(message); - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_exception_javastring(const char *classname, - java_lang_String *message) -{ - fprintf(stderr, "%s: ", classname); - /* TODO print message */ - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_abstractmethoderror(void) -{ - fprintf(stderr, "java.lang.AbstractMethodError\n"); - - exit(1); -} - - -java_objectheader *new_classformaterror(classinfo *c, const char *message, ...) -{ - va_list ap; - - utf_display_printable_ascii(c->name); - fprintf(stderr, ": "); - - va_start(ap, message); - vfprintf(stderr, message, ap); - va_end(ap); - - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_classformaterror(classinfo *c, const char *message, ...) -{ - va_list ap; - - va_start(ap, message); - (void) new_classformaterror(c, message, ap); - va_end(ap); -} - - -java_objectheader *new_classnotfoundexception(utf *name) -{ - fprintf(stderr, "java.lang.ClassNotFoundException: "); - utf_fprint_printable_ascii(stderr, name); - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_noclassdeffounderror(utf *name) -{ - fprintf(stderr, "java.lang.NoClassDefFoundError: "); - utf_fprint_printable_ascii(stderr, name); - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *exceptions_new_linkageerror(const char *message, - classinfo *c) -{ - fprintf(stderr, "java.lang.LinkageError: %s",message); - if (c) { - utf_fprint_printable_ascii_classname(stderr, c->name); - } - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - -java_objectheader *exceptions_new_nosuchmethoderror(classinfo *c, - utf *name, utf *desc) -{ - fprintf(stderr, "java.lang.NoSuchMethodError: "); - utf_fprint_printable_ascii(stderr, c->name); - fprintf(stderr, "."); - utf_fprint_printable_ascii(stderr, name); - utf_fprint_printable_ascii(stderr, desc); - fputc('\n', stderr); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_nosuchmethoderror(classinfo *c, utf *name, utf *desc) -{ - (void) exceptions_new_nosuchmethoderror(c, name, desc); -} - - -void exceptions_throw_internalerror(const char *message, ...) -{ - va_list ap; - - fprintf(stderr, "%s: ", string_java_lang_InternalError); - - va_start(ap, message); - vfprintf(stderr, message, ap); - va_end(ap); - - exit(1); -} - - -void exceptions_throw_outofmemoryerror(void) -{ - fprintf(stderr, "%s", string_java_lang_OutOfMemoryError); - exit(1); -} - - -java_objectheader *new_unsupportedclassversionerror(classinfo *c, const char *message, ...) -{ - va_list ap; - - fprintf(stderr, "%s: ", string_java_lang_UnsupportedClassVersionError); - - utf_display_printable_ascii(c->name); - fprintf(stderr, ": "); - - va_start(ap, message); - vfprintf(stderr, message, ap); - va_end(ap); - - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_virtualmachineerror(void) -{ - fprintf(stderr, "%s", string_java_lang_VirtualMachineError); - exit(1); -} - - -void exceptions_throw_arrayindexoutofboundsexception(void) -{ - fprintf(stderr, "%s", string_java_lang_ArrayIndexOutOfBoundsException); - exit(1); -} - - -java_objectheader *exceptions_new_arraystoreexception(void) -{ - fprintf(stderr, "%s", string_java_lang_ArrayStoreException); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_arraystoreexception(void) -{ - (void) exceptions_new_arraystoreexception(); -} - - -java_objectheader *exceptions_throw_illegalmonitorstateexception(void) -{ - fprintf(stderr, "%s", string_java_lang_IllegalMonitorStateException); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -java_objectheader *new_negativearraysizeexception(void) -{ - fprintf(stderr, "%s", string_java_lang_NegativeArraySizeException); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_negativearraysizeexception(void) -{ - (void) new_negativearraysizeexception(); -} - - -java_objectheader *exceptions_new_nullpointerexception(void) -{ - fprintf(stderr, "%s", string_java_lang_NullPointerException); - exit(1); - - /* keep compiler happy */ - - return NULL; -} - - -void exceptions_throw_nullpointerexception(void) -{ - (void) exceptions_new_nullpointerexception(); -} - - -void classnotfoundexception_to_noclassdeffounderror(void) -{ -} - -/* machine dependent stuff ****************************************************/ - -#if defined(ENABLE_THREADS) -critical_section_node_t asm_criticalsections; -void thread_restartcriticalsection(ucontext_t *uc) {} -#endif - -void md_param_alloc(methoddesc *md) {} +#include "vm/jit/asmpart.h" -#if defined(ENABLE_INTRP) -void print_dynamic_super_statistics(void) {} -#endif +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" /************************ global variables **********************/ @@ -942,15 +470,6 @@ void print_classname(classinfo *clazz) } } -/* jvmti releated functions ************************************************/ - -#if defined(ENABLE_JVMTI) -void jvmti_ThreadStartEnd(int ev) {;} -void jvmti_ClassLoadPrepare(bool prepared, classinfo *c) {;} -void jvmti_MonitorContendedEntering(bool entered, jobject obj) {;} -#endif - - /* * These are local overrides for various environment variables in Emacs. diff --git a/src/cacaoh/headers.h b/src/cacaoh/headers.h index 7bb7c6c9e..e12c74de1 100644 --- a/src/cacaoh/headers.h +++ b/src/cacaoh/headers.h @@ -1,6 +1,6 @@ /* src/cacaoh/headers.h - export functions for header generation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: headers.h 5123 2006-07-12 21:45:34Z twisti $ + $Id: headers.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -35,22 +31,18 @@ #include "config.h" -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#else -# include "threads/none/threads.h" -#endif - #include "toolbox/chain.h" -#include "vm/class.h" + #include "vm/global.h" -#include "vm/method.h" -#include "vm/utf8.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/utf8.h" /* export variables ***********************************************************/ -extern THREADSPECIFIC java_objectheader *_exceptionptr; +extern java_objectheader *_exceptionptr; extern chain *nativemethod_chain; extern chain *nativeclass_chain; extern chain *ident_chain; diff --git a/src/mm/Makefile.am b/src/mm/Makefile.am index 8ef863bb2..ab39ff1ee 100644 --- a/src/mm/Makefile.am +++ b/src/mm/Makefile.am @@ -1,6 +1,6 @@ ## src/mm/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ## 02110-1301, USA. ## -## Contact: cacao@cacaojvm.org -## -## Authors: Christian Thalinger -## -## Changes: -## -## $Id: Makefile.am 5900 2006-11-04 17:30:44Z michi $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in diff --git a/src/mm/boehm.c b/src/mm/boehm.c index c85a53950..7201aa2ba 100644 --- a/src/mm/boehm.c +++ b/src/mm/boehm.c @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Stefan Ring - Christian Thalinger - - $Id: boehm.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: boehm.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -51,15 +46,17 @@ #endif #include "toolbox/logging.h" -#include "vm/options.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/finalizer.h" #include "vm/global.h" -#include "vm/loader.h" #include "vm/stringlocal.h" #include "vm/vm.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" + /* global variables ***********************************************************/ diff --git a/src/mm/gc-common.h b/src/mm/gc-common.h index 732a98a7a..431f58d7b 100644 --- a/src/mm/gc-common.h +++ b/src/mm/gc-common.h @@ -1,6 +1,6 @@ /* src/mm/gc-common.h - gc independant interface for heap managment - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: gc-common.h 6054 2006-11-27 14:37:57Z michi $ + $Id: gc-common.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -37,7 +33,9 @@ #include "config.h" #include "vm/types.h" -#include "vm/method.h" +#include "vm/global.h" + +#include "vmcore/method.h" /* function prototypes ********************************************************/ diff --git a/src/mm/memory.c b/src/mm/memory.c index 29ccae179..1f6173636 100644 --- a/src/mm/memory.c +++ b/src/mm/memory.c @@ -1,6 +1,6 @@ -/* src/mm/memory.c - +/* src/mm/memory.c - memory management - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Christian Thalinger - Edwin Steiner - - $Id: memory.c 7205 2007-01-11 22:36:29Z twisti $ + $Id: memory.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -66,10 +60,13 @@ #include "toolbox/logging.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" #include "vm/vm.h" +#include "vmcore/options.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif /* constants for ENABLE_MEMCHECK **********************************************/ diff --git a/src/native/include/Makefile.am b/src/native/include/Makefile.am index 585de125a..4da573e9a 100644 --- a/src/native/include/Makefile.am +++ b/src/native/include/Makefile.am @@ -22,26 +22,17 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ## 02110-1301, USA. ## -## $Id: Makefile.am 7235 2007-01-22 17:22:28Z twisti $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in -NO_GEN_HEADER_FILES = \ +COMMON_HEADER_FILES = \ java_lang_Class.h \ java_lang_Object.h \ java_lang_String.h \ java_lang_Thread.h \ - java_lang_Throwable.h - -NO_GEN_JAVASE_HEADER_FILES = \ - java_lang_ClassLoader.h \ - java_lang_Cloneable.h \ - java_lang_ThreadGroup.h \ - java_lang_VMThread.h \ - java_lang_VMThrowable.h \ - java_util_Properties.h - -COMMON_HEADER_FILES = \ + java_lang_Throwable.h \ + \ java_io_InputStream.h \ java_io_PrintStream.h \ \ @@ -56,6 +47,13 @@ COMMON_HEADER_FILES = \ java_util_Vector.h JAVASE_HEADER_FILES = \ + java_lang_ClassLoader.h \ + java_lang_Cloneable.h \ + java_lang_ThreadGroup.h \ + java_lang_VMThread.h \ + java_lang_VMThrowable.h \ + java_util_Properties.h \ + \ gnu_classpath_Pointer.h \ gnu_classpath_Pointer32.h \ gnu_classpath_Pointer64.h \ @@ -126,16 +124,10 @@ CLEANFILES = \ $(ADDITIONAL_IMPLEMENTED_VM_CLASSES_HEADER_FILES) \ $(ADDITIONAL_STATIC_CLASSPATH_HEADER_FILES) -noinst_HEADERS = \ - $(NO_GEN_HEADER_FILES) - DO_HEADER_FILES = \ $(COMMON_HEADER_FILES) if ENABLE_JAVASE -noinst_HEADERS += \ - $(NO_GEN_JAVASE_HEADER_FILES) - DO_HEADER_FILES += \ $(JAVASE_HEADER_FILES) \ $(ADDITIONAL_IMPLEMENTED_VM_CLASSES_HEADER_FILES) @@ -167,22 +159,11 @@ endif noinst_DATA = $(DO_HEADER_FILES) -genall: $(NO_GEN_HEADER_FILES) - -$(NO_GEN_HEADER_FILES): - @class=`echo $@ | sed -e 's/\.h$$//' -e 's/_/\./g'`; \ - echo "$(CACAOH) -bootclasspath $(CLASSPATH) -d . $$class"; \ - $(CACAOH) -bootclasspath $(CLASSPATH) -d . $$class - $(DO_HEADER_FILES): $(CACAOH) $(VM_ZIP) $(CLASSPATH_CLASSES) @class=`echo $@ | sed -e 's/\.h$$//' -e 's/_/\./g'`; \ echo "$(CACAOH) -bootclasspath $(CLASSPATH) -d . $$class"; \ $(CACAOH) -bootclasspath $(CLASSPATH) -d . $$class -cleanall: clean - -rm -rf $(NO_GEN_HEADER_FILES) - -rm -rf $(NO_GEN_JAVASE_HEADER_FILES) - ## Local variables: ## mode: Makefile diff --git a/src/native/include/java_lang_Class.h b/src/native/include/java_lang_Class.h deleted file mode 100644 index 653868a75..000000000 --- a/src/native/include/java_lang_Class.h +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_CLASS_H -#define _JAVA_LANG_CLASS_H - -/* Structure information for class: java/lang/Class */ - -typedef struct java_lang_Class { - java_objectheader header; - java_objectarray* signers; - struct java_security_ProtectionDomain* pd; - struct java_lang_Object* vmdata; - struct java_lang_reflect_Constructor* constructor; -} java_lang_Class; - -#endif - diff --git a/src/native/include/java_lang_ClassLoader.h b/src/native/include/java_lang_ClassLoader.h deleted file mode 100644 index 13cd74e24..000000000 --- a/src/native/include/java_lang_ClassLoader.h +++ /dev/null @@ -1,20 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_CLASSLOADER_H -#define _JAVA_LANG_CLASSLOADER_H - -/* Structure information for class: java/lang/ClassLoader */ - -typedef struct java_lang_ClassLoader { - java_objectheader header; - struct java_util_HashMap* definedPackages; - struct java_lang_ClassLoader* parent; - s4 initialized; - s4 defaultAssertionStatus; - struct java_util_Map* packageAssertionStatus; - struct java_util_Map* classAssertionStatus; - struct java_lang_Object* vmdata; -} java_lang_ClassLoader; - -#endif - diff --git a/src/native/include/java_lang_Cloneable.h b/src/native/include/java_lang_Cloneable.h deleted file mode 100644 index b428f12ae..000000000 --- a/src/native/include/java_lang_Cloneable.h +++ /dev/null @@ -1,13 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_CLONEABLE_H -#define _JAVA_LANG_CLONEABLE_H - -/* Structure information for class: java/lang/Cloneable */ - -typedef struct java_lang_Cloneable { - java_objectheader header; -} java_lang_Cloneable; - -#endif - diff --git a/src/native/include/java_lang_Object.h b/src/native/include/java_lang_Object.h deleted file mode 100644 index d21904d85..000000000 --- a/src/native/include/java_lang_Object.h +++ /dev/null @@ -1,13 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_OBJECT_H -#define _JAVA_LANG_OBJECT_H - -/* Structure information for class: java/lang/Object */ - -typedef struct java_lang_Object { - java_objectheader header; -} java_lang_Object; - -#endif - diff --git a/src/native/include/java_lang_String.h b/src/native/include/java_lang_String.h deleted file mode 100644 index cffb3daea..000000000 --- a/src/native/include/java_lang_String.h +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_STRING_H -#define _JAVA_LANG_STRING_H - -/* Structure information for class: java/lang/String */ - -typedef struct java_lang_String { - java_objectheader header; - java_chararray* value; - s4 count; - s4 cachedHashCode; - s4 offset; -} java_lang_String; - -#endif - diff --git a/src/native/include/java_lang_Thread.h b/src/native/include/java_lang_Thread.h deleted file mode 100644 index 1ad04c9e9..000000000 --- a/src/native/include/java_lang_Thread.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_THREAD_H -#define _JAVA_LANG_THREAD_H - -/* Structure information for class: java/lang/Thread */ - -typedef struct java_lang_Thread { - java_objectheader header; - struct java_lang_VMThread* vmThread; - struct java_lang_ThreadGroup* group; - struct java_lang_Runnable* runnable; - struct java_lang_String* name; - s4 daemon; - s4 priority; - s8 stacksize; - struct java_lang_Throwable* stillborn; - struct java_lang_ClassLoader* contextClassLoader; - s4 contextClassLoaderIsSystemClassLoader; - s8 threadId; - struct java_lang_Object* parkBlocker; - struct gnu_java_util_WeakIdentityHashMap* locals; - struct java_lang_Thread_UncaughtExceptionHandler* exceptionHandler; -} java_lang_Thread; - -#endif - diff --git a/src/native/include/java_lang_ThreadGroup.h b/src/native/include/java_lang_ThreadGroup.h deleted file mode 100644 index 6b419a175..000000000 --- a/src/native/include/java_lang_ThreadGroup.h +++ /dev/null @@ -1,19 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_THREADGROUP_H -#define _JAVA_LANG_THREADGROUP_H - -/* Structure information for class: java/lang/ThreadGroup */ - -typedef struct java_lang_ThreadGroup { - java_objectheader header; - struct java_lang_ThreadGroup* parent; - struct java_lang_String* name; - struct java_util_Vector* threads; - struct java_util_Vector* groups; - s4 daemon_flag; - s4 maxpri; -} java_lang_ThreadGroup; - -#endif - diff --git a/src/native/include/java_lang_Throwable.h b/src/native/include/java_lang_Throwable.h deleted file mode 100644 index ad4b51130..000000000 --- a/src/native/include/java_lang_Throwable.h +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_THROWABLE_H -#define _JAVA_LANG_THROWABLE_H - -/* Structure information for class: java/lang/Throwable */ - -typedef struct java_lang_Throwable { - java_objectheader header; - struct java_lang_String* detailMessage; - struct java_lang_Throwable* cause; - java_objectarray* stackTrace; - struct java_lang_VMThrowable* vmState; -} java_lang_Throwable; - -#endif - diff --git a/src/native/include/java_lang_VMThread.h b/src/native/include/java_lang_VMThread.h deleted file mode 100644 index 423f9c2aa..000000000 --- a/src/native/include/java_lang_VMThread.h +++ /dev/null @@ -1,120 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_VMTHREAD_H -#define _JAVA_LANG_VMTHREAD_H - -/* Structure information for class: java/lang/VMThread */ - -typedef struct java_lang_VMThread { - java_objectheader header; - struct java_lang_Thread* thread; - s4 running; - struct java_lang_Object* vmdata; -} java_lang_VMThread; - - -/* - * Class: java/lang/VMThread - * Method: countStackFrames - * Signature: ()I - */ -JNIEXPORT s4 JNICALL Java_java_lang_VMThread_countStackFrames(JNIEnv *env, struct java_lang_VMThread* this); - - -/* - * Class: java/lang/VMThread - * Method: start - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_start(JNIEnv *env, struct java_lang_VMThread* this, s8 par1); - - -/* - * Class: java/lang/VMThread - * Method: interrupt - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_interrupt(JNIEnv *env, struct java_lang_VMThread* this); - - -/* - * Class: java/lang/VMThread - * Method: isInterrupted - * Signature: ()Z - */ -JNIEXPORT s4 JNICALL Java_java_lang_VMThread_isInterrupted(JNIEnv *env, struct java_lang_VMThread* this); - - -/* - * Class: java/lang/VMThread - * Method: suspend - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_suspend(JNIEnv *env, struct java_lang_VMThread* this); - - -/* - * Class: java/lang/VMThread - * Method: resume - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_resume(JNIEnv *env, struct java_lang_VMThread* this); - - -/* - * Class: java/lang/VMThread - * Method: nativeSetPriority - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_nativeSetPriority(JNIEnv *env, struct java_lang_VMThread* this, s4 par1); - - -/* - * Class: java/lang/VMThread - * Method: nativeStop - * Signature: (Ljava/lang/Throwable;)V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_nativeStop(JNIEnv *env, struct java_lang_VMThread* this, struct java_lang_Throwable* par1); - - -/* - * Class: java/lang/VMThread - * Method: currentThread - * Signature: ()Ljava/lang/Thread; - */ -JNIEXPORT struct java_lang_Thread* JNICALL Java_java_lang_VMThread_currentThread(JNIEnv *env, jclass clazz); - - -/* - * Class: java/lang/VMThread - * Method: yield - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_java_lang_VMThread_yield(JNIEnv *env, jclass clazz); - - -/* - * Class: java/lang/VMThread - * Method: interrupted - * Signature: ()Z - */ -JNIEXPORT s4 JNICALL Java_java_lang_VMThread_interrupted(JNIEnv *env, jclass clazz); - - -/* - * Class: java/lang/VMThread - * Method: holdsLock - * Signature: (Ljava/lang/Object;)Z - */ -JNIEXPORT s4 JNICALL Java_java_lang_VMThread_holdsLock(JNIEnv *env, jclass clazz, struct java_lang_Object* par1); - - -/* - * Class: java/lang/VMThread - * Method: getState - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT struct java_lang_String* JNICALL Java_java_lang_VMThread_getState(JNIEnv *env, struct java_lang_VMThread* this); - -#endif - diff --git a/src/native/include/java_lang_VMThrowable.h b/src/native/include/java_lang_VMThrowable.h deleted file mode 100644 index 49999fae8..000000000 --- a/src/native/include/java_lang_VMThrowable.h +++ /dev/null @@ -1,31 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_LANG_VMTHROWABLE_H -#define _JAVA_LANG_VMTHROWABLE_H - -/* Structure information for class: java/lang/VMThrowable */ - -typedef struct java_lang_VMThrowable { - java_objectheader header; - struct gnu_classpath_Pointer* vmData; - struct java_lang_Object* vmdata; -} java_lang_VMThrowable; - - -/* - * Class: java/lang/VMThrowable - * Method: fillInStackTrace - * Signature: (Ljava/lang/Throwable;)Ljava/lang/VMThrowable; - */ -JNIEXPORT struct java_lang_VMThrowable* JNICALL Java_java_lang_VMThrowable_fillInStackTrace(JNIEnv *env, jclass clazz, struct java_lang_Throwable* par1); - - -/* - * Class: java/lang/VMThrowable - * Method: getStackTrace - * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement; - */ -JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, struct java_lang_VMThrowable* this, struct java_lang_Throwable* par1); - -#endif - diff --git a/src/native/include/java_util_Properties.h b/src/native/include/java_util_Properties.h deleted file mode 100644 index e71afc983..000000000 --- a/src/native/include/java_util_Properties.h +++ /dev/null @@ -1,22 +0,0 @@ -/* This file is machine generated, don't edit it! */ - -#ifndef _JAVA_UTIL_PROPERTIES_H -#define _JAVA_UTIL_PROPERTIES_H - -/* Structure information for class: java/util/Properties */ - -typedef struct java_util_Properties { - java_objectheader header; - s4 threshold; - float loadFactor; - java_objectarray* buckets; - s4 modCount; - s4 size; - struct java_util_Set* keys; - struct java_util_Collection* values; - struct java_util_Set* entries; - struct java_util_Properties* defaults; -} java_util_Properties; - -#endif - diff --git a/src/native/jni.c b/src/native/jni.c index 7d7864e50..742e04589 100644 --- a/src/native/jni.c +++ b/src/native/jni.c @@ -1,6 +1,6 @@ /* src/native/jni.c - implementation of the Java Native Interface functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,16 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Rainhard Grafl - Roman Obermaisser - Joseph Wenninger - Martin Platter - Christian Thalinger - Edwin Steiner - - $Id: jni.c 6252 2006-12-27 23:42:37Z twisti $ + $Id: jni.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -65,6 +56,7 @@ #include "native/include/java_lang_Long.h" #include "native/include/java_lang_Float.h" #include "native/include/java_lang_Double.h" +#include "native/include/java_lang_String.h" #include "native/include/java_lang_Throwable.h" #include "native/include/java_lang_reflect_Method.h" #include "native/include/java_lang_reflect_Constructor.h" @@ -89,19 +81,21 @@ #endif #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" +#include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" -#include "vm/statistics.h" -#include "vm/vm.h" + +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" +#include "vmcore/statistics.h" /* global variables ***********************************************************/ @@ -843,9 +837,7 @@ java_objectheader *_Jv_jni_invokeNative(methodinfo *m, java_objectheader *o, parameter is ignored. */ if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->class))) { - *exceptionptr = - new_exception_message(string_java_lang_IllegalArgumentException, - "Object parameter of wrong type in Java_java_lang_reflect_Method_invokeNative"); + exceptions_throw_illegalargumentexception(); return NULL; } @@ -854,17 +846,15 @@ java_objectheader *_Jv_jni_invokeNative(methodinfo *m, java_objectheader *o, if (((params == NULL) && (paramcount != 0)) || (params && (params->header.size != paramcount))) { - *exceptionptr = - new_exception(string_java_lang_IllegalArgumentException); + exceptions_throw_illegalargumentexception(); return NULL; } /* for instance methods we need an object */ if (!(m->flags & ACC_STATIC) && (o == NULL)) { - *exceptionptr = - new_exception_message(string_java_lang_NullPointerException, - "Static mismatch in Java_java_lang_reflect_Method_invokeNative"); + /* XXX not sure if that is the correct exception */ + exceptions_throw_nullpointerexception(); return NULL; } @@ -875,8 +865,8 @@ java_objectheader *_Jv_jni_invokeNative(methodinfo *m, java_objectheader *o, if (o != NULL) { /* for instance methods we must do a vftbl lookup */ resm = method_vftbl_lookup(o->vftbl, m); - - } else { + } + else { /* for static methods, just for convenience */ resm = m; } @@ -1031,15 +1021,11 @@ java_objectheader *_Jv_jni_invokeNative(methodinfo *m, java_objectheader *o, if (*exceptionptr) { java_objectheader *cause; - cause = *exceptionptr; - /* clear exception pointer, we are calling JIT code again */ - *exceptionptr = NULL; + cause = exceptions_get_and_clear_exception(); - *exceptionptr = - new_exception_throwable(string_java_lang_reflect_InvocationTargetException, - (java_lang_Throwable *) cause); + exceptions_throw_invocationtargetexception(cause); } return ro; @@ -1225,7 +1211,7 @@ jint _Jv_JNI_ThrowNew(JNIEnv* env, jclass clazz, const char *msg) if (o == NULL) return -1; - *exceptionptr = (java_objectheader *) o; + exceptions_set_exception(o); return 0; } @@ -1318,7 +1304,9 @@ void _Jv_JNI_FatalError(JNIEnv *env, const char *msg) { STATISTICS(jniinvokation()); - throw_cacao_exception_exit(string_java_lang_InternalError, msg); + /* this seems to be the best way */ + + vm_abort(msg); } @@ -1590,9 +1578,7 @@ jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz) c = (classinfo *) clazz; if ((c->flags & ACC_INTERFACE) || (c->flags & ACC_ABSTRACT)) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_InstantiationException, - c->name); + exceptions_throw_instantiationexception(c); return NULL; } @@ -2876,19 +2862,22 @@ void _Jv_JNI_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass clazz, jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + classinfo *c; fieldinfo *f; utf *uname; utf *udesc; STATISTICS(jniinvokation()); + c = (classinfo *) clazz; + uname = utf_new_char((char *) name); udesc = utf_new_char((char *) sig); f = class_findfield(clazz, uname, udesc); - if (!f) - *exceptionptr = new_exception(string_java_lang_NoSuchFieldError); + if (f == NULL) + exceptions_throw_nosuchfielderror(c, uname); return (jfieldID) f; } @@ -3567,19 +3556,22 @@ void _Jv_JNI_CallStaticVoidMethodA(JNIEnv *env, jclass clazz, jfieldID _Jv_JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + classinfo *c; fieldinfo *f; utf *uname; utf *usig; STATISTICS(jniinvokation()); + c = (classinfo *) clazz; + uname = utf_new_char((char *) name); usig = utf_new_char((char *) sig); f = class_findfield(clazz, uname, usig); if (f == NULL) - *exceptionptr = new_exception(string_java_lang_NoSuchFieldError); + exceptions_throw_nosuchfielderror(c, uname); return (jfieldID) f; } @@ -4245,8 +4237,7 @@ void _Jv_JNI_SetObjectArrayElement(JNIEnv *env, jobjectArray array, of the array */ if (!builtin_canstore(oa, o)) { - *exceptionptr = new_exception(string_java_lang_ArrayStoreException); - + exceptions_throw_arraystoreexception(); return; } diff --git a/src/native/jni.h b/src/native/jni.h index 9a05c7334..0c14db8e2 100644 --- a/src/native/jni.h +++ b/src/native/jni.h @@ -1,6 +1,6 @@ /* src/native/jni.h - JNI types and data structures - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Roman Obermaisser - Christian Thalinger - - $Id: jni.h 6171 2006-12-11 11:47:42Z twisti $ + $Id: jni.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -63,7 +57,8 @@ typedef struct localref_table localref_table; #include "vm/types.h" #include "vm/global.h" -#include "vm/method.h" + +#include "vmcore/method.h" /* _Jv_JNIEnv *****************************************************************/ diff --git a/src/native/native.c b/src/native/native.c index a4486b9f7..179609eab 100644 --- a/src/native/native.c +++ b/src/native/native.c @@ -1,6 +1,6 @@ /* src/native/native.c - table of native functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,14 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Roman Obermaisser - Andreas Krall - Christian Thalinger - - $Id: native.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: native.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -48,6 +41,7 @@ #include "mm/memory.h" #include "native/jni.h" #include "native/native.h" +#include "native/include/java_lang_String.h" #include "native/include/java_lang_Throwable.h" #if defined(ENABLE_THREADS) @@ -56,19 +50,22 @@ # include "threads/none/lock.h" #endif +#include "toolbox/hashtable.h" #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/resolve.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + #if defined(ENABLE_JVMTI) #include "native/jvmti/cacaodbg.h" #endif @@ -92,6 +89,7 @@ #include "native/include/gnu_java_lang_management_VMMemoryMXBeanImpl.h" #include "native/include/gnu_java_lang_management_VMRuntimeMXBeanImpl.h" #include "native/include/java_lang_VMClass.h" +#include "native/include/java_security_ProtectionDomain.h" /* required by... */ #include "native/include/java_lang_VMClassLoader.h" #include "native/include/java_lang_VMObject.h" #include "native/include/java_lang_VMRuntime.h" @@ -922,17 +920,7 @@ functionptr native_resolve_function(methodinfo *m) if (opt_verbosejni) printf("failed ]\n"); -#if defined(ENABLE_JAVASE) - *exceptionptr = - new_exception_utfmessage(string_java_lang_UnsatisfiedLinkError, - m->name); -#elif defined(ENABLE_JAVAME_CLDC1_1) - *exceptionptr = - new_exception_utfmessage(string_java_lang_VirtualMachineError, - m->name); -#else -#error IMPLEMENT ME! -#endif + exceptions_throw_unsatisfiedlinkerror(m->name); } /* release memory */ @@ -956,14 +944,14 @@ java_objectheader *native_new_and_init(classinfo *c) methodinfo *m; java_objectheader *o; - if (!c) - return *exceptionptr; + if (c == NULL) + vm_abort("native_new_and_init: c == NULL"); /* create object */ o = builtin_new(c); - if (!o) + if (o == NULL) return NULL; /* try to find the initializer */ @@ -973,7 +961,7 @@ java_objectheader *native_new_and_init(classinfo *c) /* ATTENTION: returning the object here is ok, since the class may not have an initializer */ - if (!m) + if (m == NULL) return o; /* call initializer */ @@ -984,19 +972,19 @@ java_objectheader *native_new_and_init(classinfo *c) } -java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s) +java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s) { - methodinfo *m; + methodinfo *m; java_objectheader *o; - if (!c) - return *exceptionptr; + if (c == NULL) + vm_abort("native_new_and_init_string: c == NULL"); /* create object */ o = builtin_new(c); - if (!o) + if (o == NULL) return NULL; /* find initializer */ @@ -1009,7 +997,7 @@ java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s) /* initializer not found */ - if (!m) + if (m == NULL) return NULL; /* call initializer */ @@ -1025,14 +1013,14 @@ java_objectheader *native_new_and_init_int(classinfo *c, s4 i) methodinfo *m; java_objectheader *o; - if (!c) - return *exceptionptr; + if (c == NULL) + vm_abort("native_new_and_init_int: c == NULL"); /* create object */ o = builtin_new(c); - if (!o) + if (o == NULL) return NULL; /* find initializer */ @@ -1041,7 +1029,7 @@ java_objectheader *native_new_and_init_int(classinfo *c, s4 i) /* initializer not found */ - if (!m) + if (m == NULL) return NULL; /* call initializer */ @@ -1052,19 +1040,19 @@ java_objectheader *native_new_and_init_int(classinfo *c, s4 i) } -java_objectheader *native_new_and_init_throwable(classinfo *c, java_lang_Throwable *t) +java_objectheader *native_new_and_init_throwable(classinfo *c, java_objectheader *t) { - methodinfo *m; java_objectheader *o; + methodinfo *m; - if (!c) - return *exceptionptr; + if (c == NULL) + vm_abort("native_new_and_init_throwable: c == NULL"); /* create object */ o = builtin_new(c); - if (!o) + if (o == NULL) return NULL; /* find initializer */ @@ -1073,7 +1061,7 @@ java_objectheader *native_new_and_init_throwable(classinfo *c, java_lang_Throwab /* initializer not found */ - if (!m) + if (m == NULL) return NULL; /* call initializer */ diff --git a/src/native/native.h b/src/native/native.h index c05429957..1cffac9bf 100644 --- a/src/native/native.h +++ b/src/native/native.h @@ -1,6 +1,6 @@ /* src/native/native.h - table of native functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Christian Thalinger - - $Id: native.h 6251 2006-12-27 23:15:56Z twisti $ + $Id: native.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,13 +36,11 @@ # include #endif -#include "native/jni.h" -#include "native/include/java_lang_String.h" -#include "native/include/java_lang_Throwable.h" -#include "vm/class.h" #include "vm/global.h" -#include "vm/method.h" -#include "vm/utf8.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/utf8.h" /* table for locating native methods */ @@ -128,7 +121,8 @@ java_objectheader *native_new_and_init(classinfo *c); /* create new object on the heap and call the initializer mainly used for exceptions with a message */ -java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s); +java_objectheader *native_new_and_init_string(classinfo *c, + java_objectheader *s); /* create new object on the heap and call the initializer mainly used for exceptions with an index */ @@ -136,7 +130,8 @@ java_objectheader *native_new_and_init_int(classinfo *c, s4 i); /* create new object on the heap and call the initializer mainly used for exceptions with cause */ -java_objectheader *native_new_and_init_throwable(classinfo *c, java_lang_Throwable *t); +java_objectheader *native_new_and_init_throwable(classinfo *c, + java_objectheader *t); java_objectarray *native_get_parametertypes(methodinfo *m); java_objectarray *native_get_exceptiontypes(methodinfo *m); diff --git a/src/native/vm/gnu/gnu_classpath_VMStackWalker.c b/src/native/vm/gnu/gnu_classpath_VMStackWalker.c index 1e0c941c7..93ccbe1ce 100644 --- a/src/native/vm/gnu/gnu_classpath_VMStackWalker.c +++ b/src/native/vm/gnu/gnu_classpath_VMStackWalker.c @@ -1,6 +1,6 @@ -/* src/native/vm/gnu_classpath_VMStackWalker.c - gnu/classpath/VMStackWalker +/* src/native/vm/gnu/gnu_classpath_VMStackWalker.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Edwin Steiner - - $Id: gnu_classpath_VMStackWalker.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: gnu_classpath_VMStackWalker.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -39,10 +33,14 @@ #include "native/native.h" #include "native/include/java_lang_Class.h" #include "native/include/java_lang_ClassLoader.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/global.h" -#include "vm/options.h" + +#include "vm/jit/stacktrace.h" + +#include "vmcore/class.h" +#include "vmcore/options.h" /* diff --git a/src/native/vm/gnu/gnu_classpath_VMSystemProperties.c b/src/native/vm/gnu/gnu_classpath_VMSystemProperties.c index d0e27f35c..ae531fe7a 100644 --- a/src/native/vm/gnu/gnu_classpath_VMSystemProperties.c +++ b/src/native/vm/gnu/gnu_classpath_VMSystemProperties.c @@ -26,7 +26,7 @@ Authors: Christian Thalinger - $Id: gnu_classpath_VMSystemProperties.c 7237 2007-01-22 20:16:22Z twisti $ + $Id: gnu_classpath_VMSystemProperties.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -52,14 +52,18 @@ */ JNIEXPORT void JNICALL Java_gnu_classpath_VMSystemProperties_preInit(JNIEnv *env, jclass clazz, java_util_Properties *properties) { - if (properties == NULL) { + java_objectheader *p; + + p = (java_objectheader *) properties; + + if (p == NULL) { exceptions_throw_nullpointerexception(); return; } /* fill the java.util.Properties object */ - properties_system_add_all(properties); + properties_system_add_all(p); } diff --git a/src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c b/src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c index 7ee69bfe4..8be4825a1 100644 --- a/src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c +++ b/src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c @@ -1,6 +1,6 @@ -/* src/native/vm/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c +/* src/native/vm/gnu/gnu_java_lang_management_VMClassLoadingMXBeanImpl.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: VMFrame.c 4996 2006-05-31 13:53:16Z motse $ */ @@ -41,9 +35,11 @@ #include "native/jni.h" #include "toolbox/logging.h" -#include "vm/classcache.h" + #include "vm/vm.h" +#include "vmcore/classcache.h" + /* * Class: gnu/java/lang/management/VMClassLoadingMXBeanImpl diff --git a/src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c b/src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c index 4dc96e5cc..37741ec71 100644 --- a/src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c +++ b/src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c @@ -1,6 +1,6 @@ -/* src/native/vm/gnu_java_lang_management_VMMemoryMXBeanImpl.c +/* src/native/vm/gnu/gnu_java_lang_management_VMMemoryMXBeanImpl.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: VMFrame.c 4996 2006-05-31 13:53:16Z motse $ */ @@ -42,12 +36,13 @@ #include "native/include/java_lang_management_MemoryUsage.h" #include "vm/builtin.h" -#include "vm/class.h" #include "vm/global.h" -#include "vm/loader.h" /* XXX only for load_class_bootstrap */ -#include "vm/options.h" #include "vm/vm.h" +#include "vmcore/class.h" +#include "vmcore/loader.h" /* XXX only for load_class_bootstrap */ +#include "vmcore/options.h" + /* * Class: gnu/java/lang/management/VMMemoryMXBeanImpl diff --git a/src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c b/src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c index 68e8784c8..adeef5faa 100644 --- a/src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c +++ b/src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c @@ -1,6 +1,6 @@ -/* src/native/vm/gnu_java_lang_management_VMRuntimeMXBeanImpl.c +/* src/native/vm/gnu/gnu_java_lang_management_VMRuntimeMXBeanImpl.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: VMFrame.c 4996 2006-05-31 13:53:16Z motse $ */ @@ -37,11 +31,13 @@ #include "vm/types.h" #include "native/jni.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/global.h" #include "vm/vm.h" +#include "vmcore/class.h" + /* * Class: gnu/java/lang/management/VMRuntimeMXBeanImpl diff --git a/src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c b/src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c index 8bde3431e..483e5e1d9 100644 --- a/src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c +++ b/src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c @@ -1,4 +1,4 @@ -/* src/native/vm/gnu_java_lang_management_VMThreadMXBeanImpl.c +/* src/native/vm/gnu/gnu_java_lang_management_VMThreadMXBeanImpl.c Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: VMFrame.c 4996 2006-05-31 13:53:16Z motse $ */ @@ -39,12 +33,15 @@ #include "mm/gc-common.h" #include "native/jni.h" +#include "native/include/java_lang_Throwable.h" #include "native/include/java_lang_management_ThreadInfo.h" #include "toolbox/logging.h" -#include "vm/classcache.h" + #include "vm/vm.h" +#include "vmcore/classcache.h" + /* * Class: gnu/java/lang/management/VMThreadMXBeanImpl diff --git a/src/native/vm/gnu/java_lang_VMClass.c b/src/native/vm/gnu/java_lang_VMClass.c index 206607902..dfd4c155f 100644 --- a/src/native/vm/gnu/java_lang_VMClass.c +++ b/src/native/vm/gnu/java_lang_VMClass.c @@ -1,6 +1,6 @@ -/* src/native/vm/java_lang_VMClass.c - java/lang/VMClass +/* src/native/vm/gnu/java_lang_VMClass.c - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: java_lang_VMClass.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_VMClass.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -38,9 +34,11 @@ #include "native/include/java_lang_Class.h" #include "native/include/java_lang_ClassLoader.h" #include "native/include/java_lang_Object.h" +#include "native/include/java_lang_Throwable.h" #include "native/include/java_lang_VMClass.h" #include "native/include/java_lang_reflect_Constructor.h" #include "native/include/java_lang_reflect_Method.h" + #include "native/vm/java_lang_Class.h" diff --git a/src/native/vm/gnu/java_lang_VMClassLoader.c b/src/native/vm/gnu/java_lang_VMClassLoader.c index 282414ac3..23f01d6d1 100644 --- a/src/native/vm/gnu/java_lang_VMClassLoader.c +++ b/src/native/vm/gnu/java_lang_VMClassLoader.c @@ -1,6 +1,6 @@ -/* src/native/vm/VMClassLoader.c - java/lang/VMClassLoader +/* src/native/vm/gnu/VMClassLoader.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - - Changes: Joseph Wenninger - Christian Thalinger - Edwin Steiner - - $Id: java_lang_VMClassLoader.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_VMClassLoader.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -42,29 +34,34 @@ #include "vm/types.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" #include "native/include/java_lang_Class.h" #include "native/include/java_lang_String.h" +#include "native/include/java_security_ProtectionDomain.h" /* required by... */ #include "native/include/java_lang_ClassLoader.h" -#include "native/include/java_security_ProtectionDomain.h" #include "native/include/java_util_Vector.h" + #include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/class.h" -#include "vm/classcache.h" #include "vm/exceptions.h" #include "vm/initialize.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" -#include "vm/suck.h" #include "vm/vm.h" -#include "vm/zip.h" + #include "vm/jit/asmpart.h" +#include "vmcore/class.h" +#include "vmcore/classcache.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/statistics.h" +#include "vmcore/suck.h" +#include "vmcore/zip.h" + #if defined(ENABLE_JVMTI) #include "native/jvmti/cacaodbg.h" #endif @@ -77,10 +74,11 @@ */ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name, java_bytearray *data, s4 offset, s4 len, java_security_ProtectionDomain *pd) { - classinfo *c; - classinfo *r; - classbuffer *cb; - utf *utfname; + classinfo *c; + classinfo *r; + classbuffer *cb; + utf *utfname; + java_lang_Class *co; #if defined(ENABLE_JVMTI) jint new_class_data_len = 0; unsigned char* new_class_data = NULL; @@ -100,7 +98,7 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE return NULL; } - if (name) { + if (name != NULL) { /* convert '.' to '/' in java string */ utfname = javastring_toutf(name, true); @@ -108,9 +106,8 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE /* check if this class has already been defined */ c = classcache_lookup_defined_or_initiated((java_objectheader *) cl, utfname); - if (c) { - *exceptionptr = - exceptions_new_linkageerror("duplicate class definition: ",c); + if (c != NULL) { + exceptions_throw_linkageerror("duplicate class definition: ", c); return NULL; } } @@ -175,10 +172,10 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE loadingtime_stop(); #endif - if (!r) { - /* If return value is NULL, we had a problem and the class is not */ - /* loaded. */ - /* now free the allocated memory, otherwise we could run into a DOS */ + if (r == NULL) { + /* If return value is NULL, we had a problem and the class is + not loaded. Now free the allocated memory, otherwise we + could run into a DOS. */ class_free(c); @@ -187,7 +184,9 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE /* set ProtectionDomain */ - c->object.pd = pd; + co = (java_lang_Class *) c; + + co->pd = pd; /* Store the newly defined class in the class cache. This call also */ /* checks whether a class of the same name has already been defined by */ @@ -198,7 +197,7 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE /* pointer after the lookup at to top of this function */ /* directly after the class cache lock has been released. */ - c = classcache_store((java_objectheader *)cl,c,true); + c = classcache_store((java_objectheader *) cl, c, true); return (java_lang_Class *) c; } @@ -212,42 +211,45 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIE JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, s4 type) { classinfo *c; + s4 index; /* get primitive class */ switch (type) { case 'I': - c = primitivetype_table[PRIMITIVETYPE_INT].class_primitive; + index = PRIMITIVETYPE_INT; break; case 'J': - c = primitivetype_table[PRIMITIVETYPE_LONG].class_primitive; + index = PRIMITIVETYPE_LONG; break; case 'F': - c = primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive; + index = PRIMITIVETYPE_FLOAT; break; case 'D': - c = primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive; + index = PRIMITIVETYPE_DOUBLE; break; case 'B': - c = primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive; + index = PRIMITIVETYPE_BYTE; break; case 'C': - c = primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive; + index = PRIMITIVETYPE_CHAR; break; case 'S': - c = primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive; + index = PRIMITIVETYPE_SHORT; break; case 'Z': - c = primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive; + index = PRIMITIVETYPE_BOOLEAN; break; case 'V': - c = primitivetype_table[PRIMITIVETYPE_VOID].class_primitive; + index = PRIMITIVETYPE_VOID; break; default: - *exceptionptr = new_exception(string_java_lang_ClassNotFoundException); + exceptions_throw_noclassdeffounderror(utf_null); c = NULL; } + c = primitivetype_table[index].class_primitive; + return (java_lang_Class *) c; } @@ -284,8 +286,9 @@ JNIEXPORT void JNICALL Java_java_lang_VMClassLoader_resolveClass(JNIEnv *env, jc */ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv *env, jclass clazz, java_lang_String *name, jboolean resolve) { - classinfo *c; - utf *u; + classinfo *c; + utf *u; + java_objectheader *xptr; if (name == NULL) { exceptions_throw_nullpointerexception(); @@ -298,7 +301,9 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv /* load class */ - if (!(c = load_class_bootstrap(u))) + c = load_class_bootstrap(u); + + if (c == NULL) goto exception; /* resolve class -- if requested */ @@ -310,7 +315,9 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv return (java_lang_Class *) c; exception: - c = (*exceptionptr)->vftbl->class; + xptr = exceptions_get_exception(); + + c = xptr->vftbl->class; /* if the exception is a NoClassDefFoundError, we replace it with a ClassNotFoundException, otherwise return the exception */ @@ -318,10 +325,9 @@ JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv if (c == class_java_lang_NoClassDefFoundError) { /* clear exceptionptr, because builtin_new checks for ExceptionInInitializerError */ - *exceptionptr = NULL; + exceptions_clear_exception(); - *exceptionptr = - new_exception_javastring(string_java_lang_ClassNotFoundException, name); + exceptions_throw_classnotfoundexception(u); } return NULL; @@ -452,7 +458,7 @@ JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResour if (path) { ret = vm_call_method_int(m, o, path); - if (*exceptionptr) + if (exceptions_get_exception() != NULL) goto return_NULL; if (ret == 0) diff --git a/src/native/vm/gnu/java_lang_VMRuntime.c b/src/native/vm/gnu/java_lang_VMRuntime.c index edb5b3634..e5975ec46 100644 --- a/src/native/vm/gnu/java_lang_VMRuntime.c +++ b/src/native/vm/gnu/java_lang_VMRuntime.c @@ -1,6 +1,6 @@ -/* src/native/vm/VMRuntime.c - java/lang/VMRuntime +/* src/native/vm/gnu/java_lang_VMRuntime.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - - Changes: Joseph Wenninger - Christian Thalinger - Edwin Steiner - - $Id: java_lang_VMRuntime.c 6252 2006-12-27 23:42:37Z twisti $ + $Id: java_lang_VMRuntime.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -55,20 +47,23 @@ #include "mm/gc-common.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" #include "native/include/java_io_File.h" #include "native/include/java_lang_ClassLoader.h" #include "native/include/java_lang_String.h" #include "native/include/java_lang_Process.h" + #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" +#include "vmcore/options.h" + /* this should work on BSD */ /* diff --git a/src/native/vm/gnu/java_lang_VMThread.c b/src/native/vm/gnu/java_lang_VMThread.c index 97a2da00f..765960d92 100644 --- a/src/native/vm/gnu/java_lang_VMThread.c +++ b/src/native/vm/gnu/java_lang_VMThread.c @@ -1,6 +1,6 @@ -/* src/native/vm/gnu/java_lang_VMThread.c - java/lang/VMThread +/* src/native/vm/gnu/java_lang_VMThread.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - - $Id: java_lang_VMThread.c 6228 2006-12-26 19:56:58Z twisti $ + $Id: java_lang_VMThread.c 7246 2007-01-29 18:49:05Z twisti $ */ diff --git a/src/native/vm/gnu/java_lang_VMThrowable.c b/src/native/vm/gnu/java_lang_VMThrowable.c index 47ceaaa31..906333861 100644 --- a/src/native/vm/gnu/java_lang_VMThrowable.c +++ b/src/native/vm/gnu/java_lang_VMThrowable.c @@ -1,6 +1,6 @@ -/* src/native/vm/java_lang_VMThrowable.c - java/lang/VMThrowable +/* src/native/vm/gnu/java_lang_VMThrowable.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Joseph Wenninger - Christian Thalinger - - $Id: java_lang_VMThrowable.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_VMThrowable.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -45,14 +40,18 @@ #include "native/include/java_lang_StackTraceElement.h" #include "native/include/java_lang_Throwable.h" #include "native/include/java_lang_VMThrowable.h" + #include "native/vm/java_lang_Class.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/exceptions.h" -#include "vm/loader.h" #include "vm/stringlocal.h" + #include "vm/jit/stacktrace.h" +#include "vmcore/class.h" +#include "vmcore/loader.h" + /* * Class: java/lang/VMThrowable diff --git a/src/native/vm/gnu/java_lang_management_VMManagementFactory.c b/src/native/vm/gnu/java_lang_management_VMManagementFactory.c index 8abcd629c..54b902447 100644 --- a/src/native/vm/gnu/java_lang_management_VMManagementFactory.c +++ b/src/native/vm/gnu/java_lang_management_VMManagementFactory.c @@ -1,6 +1,6 @@ -/* src/native/vm/java_lang_management_VMManagementFactory.c +/* src/native/vm/gnu/java_lang_management_VMManagementFactory.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: VMFrame.c 4996 2006-05-31 13:53:16Z motse $ */ @@ -42,8 +36,10 @@ #include "native/jni.h" #include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/class.h" + +#include "vmcore/class.h" /* diff --git a/src/native/vm/gnu/java_lang_reflect_Constructor.c b/src/native/vm/gnu/java_lang_reflect_Constructor.c index e507a1fa9..cbeeb4cda 100644 --- a/src/native/vm/gnu/java_lang_reflect_Constructor.c +++ b/src/native/vm/gnu/java_lang_reflect_Constructor.c @@ -1,6 +1,6 @@ -/* src/native/vm/java_lang_reflect_Constructor.c +/* src/native/vm/gnu/java_lang_reflect_Constructor.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - - $Id: java_lang_reflect_Constructor.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_reflect_Constructor.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -46,13 +40,17 @@ #include "native/include/java_lang_Object.h" #include "native/include/java_lang_String.h" #include "native/include/java_lang_reflect_Constructor.h" + #include "toolbox/logging.h" -#include "vm/class.h" + +#include "vm/builtin.h" #include "vm/exceptions.h" -#include "vm/method.h" #include "vm/access.h" #include "vm/stringlocal.h" +#include "vmcore/class.h" +#include "vmcore/method.h" + /* * Class: java/lang/reflect/Constructor diff --git a/src/native/vm/gnu/java_lang_reflect_Field.c b/src/native/vm/gnu/java_lang_reflect_Field.c index dd60bfcd1..796e3607a 100644 --- a/src/native/vm/gnu/java_lang_reflect_Field.c +++ b/src/native/vm/gnu/java_lang_reflect_Field.c @@ -1,6 +1,6 @@ -/* src/native/vm/java_lang_reflect_Field.c - java/lang/reflect/Field +/* src/native/vm/gnu/java_lang_reflect_Field.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - - $Id: java_lang_reflect_Field.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_reflect_Field.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -51,18 +45,22 @@ #include "native/include/java_lang_Double.h" #include "native/include/java_lang_Object.h" #include "native/include/java_lang_Class.h" +#include "native/include/java_lang_String.h" #include "native/include/java_lang_reflect_Field.h" + #include "vm/access.h" #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/loader.h" -#include "vm/resolve.h" #include "vm/stringlocal.h" -#include "vm/utf8.h" + #include "vm/jit/stacktrace.h" +#include "vmcore/loader.h" +#include "vmcore/resolve.h" +#include "vmcore/utf8.h" + #define CHECKFIELDACCESS(this,fi,c,doret) diff --git a/src/native/vm/gnu/java_lang_reflect_Method.c b/src/native/vm/gnu/java_lang_reflect_Method.c index d7560e699..cfc0ef871 100644 --- a/src/native/vm/gnu/java_lang_reflect_Method.c +++ b/src/native/vm/gnu/java_lang_reflect_Method.c @@ -1,6 +1,6 @@ -/* src/native/vm/Method.c - java/lang/reflect/Method +/* src/native/vm/gnu/java_lang_reflect_Method.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - - $Id: java_lang_reflect_Method.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_lang_reflect_Method.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -43,7 +37,9 @@ #include "native/native.h" #include "native/include/java_lang_Object.h" #include "native/include/java_lang_Class.h" +#include "native/include/java_lang_String.h" #include "native/include/java_lang_reflect_Method.h" + #include "vm/access.h" #include "vm/global.h" #include "vm/builtin.h" diff --git a/src/native/vm/gnu/java_security_VMAccessController.c b/src/native/vm/gnu/java_security_VMAccessController.c index 36d1d1e51..43f6bd55b 100644 --- a/src/native/vm/gnu/java_security_VMAccessController.c +++ b/src/native/vm/gnu/java_security_VMAccessController.c @@ -1,6 +1,6 @@ -/* src/native/vm/VMAccessController.c - java/security/VMAccessController +/* src/native/vm/gnu/java_security_VMAccessController.c - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Joseph Wenninger - - Changes: Christian Thalinger - - $Id: java_security_VMAccessController.c 6213 2006-12-18 17:36:06Z twisti $ + $Id: java_security_VMAccessController.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -37,11 +31,14 @@ #include "vm/types.h" #include "native/jni.h" + #include "vm/builtin.h" -#include "vm/class.h" -#include "vm/options.h" + #include "vm/jit/stacktrace.h" +#include "vmcore/class.h" +#include "vmcore/options.h" + /* * Class: java/security/VMAccessController diff --git a/src/native/vm/java_lang_Class.c b/src/native/vm/java_lang_Class.c index 05b370892..d04c4d5fb 100644 --- a/src/native/vm/java_lang_Class.c +++ b/src/native/vm/java_lang_Class.c @@ -1,6 +1,6 @@ /* src/native/vm/java_lang_Class.c - java/lang/Class - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - Edwin Steiner - $Id: java_lang_VMClass.c 6131 2006-12-06 22:15:57Z twisti $ */ @@ -42,6 +35,7 @@ #include "vm/types.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" #include "native/include/java_lang_Class.h" @@ -55,16 +49,19 @@ #endif #include "native/vm/java_lang_Class.h" + #include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/exceptions.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/loader.h" -#include "vm/resolve.h" #include "vm/stringlocal.h" +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/resolve.h" + /* * Class: java/lang/Class @@ -108,10 +105,16 @@ java_lang_Class *_Jv_java_lang_Class_forName(java_lang_String *name, s4 initiali java_lang_Class *_Jv_java_lang_Class_forName(java_lang_String *name) #endif { - classinfo *c; - utf *u; - u2 *pos; - s4 i; + java_objectheader *cl; + utf *ufile; + utf *uname; + classinfo *c; + java_objectheader *xptr; + classinfo *xclass; + u2 *pos; + s4 i; + + cl = (java_objectheader *) loader; /* illegal argument */ @@ -120,30 +123,32 @@ java_lang_Class *_Jv_java_lang_Class_forName(java_lang_String *name) return NULL; } + /* create utf string in which '.' is replaced by '/' */ + + ufile = javastring_toutf(name, true); + uname = javastring_toutf(name, false); + /* name must not contain '/' (mauve test) */ for (i = 0, pos = name->value->data + name->offset; i < name->count; i++, pos++) { if (*pos == '/') { - *exceptionptr = - new_exception_javastring(string_java_lang_ClassNotFoundException, name); + exceptions_throw_classnotfoundexception(uname); return NULL; } } - /* create utf string in which '.' is replaced by '/' */ - - u = javastring_toutf(name, true); - /* try to load, ... */ #if defined(ENABLE_JAVASE) - if (!(c = load_class_from_classloader(u, (java_objectheader *) loader))) { + c = load_class_from_classloader(ufile, cl); #elif defined(ENABLE_JAVAME_CLDC1_1) - if (!(c = load_class_bootstrap(u))) { + c = load_class_bootstrap(ufile); #endif - classinfo *xclass; - xclass = (*exceptionptr)->vftbl->class; + if (c == NULL) { + xptr = exceptions_get_exception(); + + xclass = xptr->vftbl->class; /* if the exception is a NoClassDefFoundError, we replace it with a ClassNotFoundException, otherwise return the exception */ @@ -151,10 +156,9 @@ java_lang_Class *_Jv_java_lang_Class_forName(java_lang_String *name) if (xclass == class_java_lang_NoClassDefFoundError) { /* clear exceptionptr, because builtin_new checks for ExceptionInInitializerError */ - *exceptionptr = NULL; + exceptions_clear_exception(); - *exceptionptr = - new_exception_javastring(string_java_lang_ClassNotFoundException, name); + exceptions_throw_classnotfoundexception(uname); } return NULL; @@ -792,7 +796,11 @@ s4 _Jv_java_lang_Class_isArray(java_lang_Class *klass) */ void _Jv_java_lang_Class_throwException(java_lang_Throwable *t) { - *exceptionptr = (java_objectheader *) t; + java_objectheader *o; + + o = (java_objectheader *) t; + + exceptions_set_exception(o); } diff --git a/src/native/vm/java_lang_Object.c b/src/native/vm/java_lang_Object.c index 8f4ec57a8..463c43a89 100644 --- a/src/native/vm/java_lang_Object.c +++ b/src/native/vm/java_lang_Object.c @@ -1,6 +1,6 @@ /* src/native/vm/java_lang_Object.c - java/lang/Object functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - $Id: java_lang_VMObject.c 6213 2006-12-18 17:36:06Z twisti $ */ @@ -54,7 +48,8 @@ #endif #include "vm/builtin.h" -#include "vm/options.h" + +#include "vmcore/options.h" #if defined(ENABLE_JVMTI) #include "native/jvmti/cacaodbg.h" diff --git a/src/native/vm/java_lang_Thread.c b/src/native/vm/java_lang_Thread.c index c2e2fe1e5..50e7fb37c 100644 --- a/src/native/vm/java_lang_Thread.c +++ b/src/native/vm/java_lang_Thread.c @@ -1,6 +1,6 @@ /* src/native/vm/java_lang_Thread.c - java/lang/Thread functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Roman Obermaiser - Joseph Wenninger - Christian Thalinger - $Id: java_lang_VMThread.c 6213 2006-12-18 17:36:06Z twisti $ */ @@ -43,6 +37,7 @@ # include "native/include/java_lang_ThreadGroup.h" #endif +#include "native/include/java_lang_String.h" #include "native/include/java_lang_Object.h" /* java_lang_Thread.h */ #include "native/include/java_lang_Throwable.h" /* java_lang_Thread.h */ #include "native/include/java_lang_Thread.h" @@ -52,9 +47,14 @@ #endif #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" -#include "vm/options.h" + +#include "vmcore/options.h" + +/* XXX REMOVE ME only for vm_abort */ +#include "vm/vm.h" /* diff --git a/src/threads/native/lock.c b/src/threads/native/lock.c index ed7d795f8..9bc692e5a 100644 --- a/src/threads/native/lock.c +++ b/src/threads/native/lock.c @@ -1,6 +1,6 @@ /* src/threads/native/lock.c - lock implementation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Stefan Ring - Edwin Steiner - - Changes: Christian Thalinger - $Id: threads.c 4903 2006-05-11 12:48:43Z edwin $ */ @@ -42,8 +35,13 @@ #include #include -#include "mm/memory.h" #include "vm/types.h" + +#include "mm/memory.h" + +#include "threads/native/lock.h" +#include "threads/native/threads.h" + #include "vm/global.h" #include "vm/exceptions.h" #include "vm/stringlocal.h" @@ -1141,7 +1139,7 @@ static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 n /* if we have been interrupted, throw the appropriate exception */ if (wasinterrupted) - *exceptionptr = new_exception(string_java_lang_InterruptedException); + exceptions_throw_interruptedexception(); } diff --git a/src/threads/native/threads.c b/src/threads/native/threads.c index 0ab9ead32..b7ab5a4fa 100644 --- a/src/threads/native/threads.c +++ b/src/threads/native/threads.c @@ -1,6 +1,6 @@ /* src/threads/native/threads.c - native threads support - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Stefan Ring - Christian Thalinger - Edwin Steiner - - $Id: threads.c 6254 2006-12-28 00:19:16Z twisti $ + $Id: threads.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -61,8 +55,11 @@ #include "mm/gc-common.h" #include "mm/memory.h" + +#include "native/jni.h" #include "native/native.h" #include "native/include/java_lang_Object.h" +#include "native/include/java_lang_String.h" #include "native/include/java_lang_Throwable.h" #include "native/include/java_lang_Thread.h" @@ -75,17 +72,20 @@ #endif #include "threads/native/threads.h" + #include "toolbox/avl.h" #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" +#include "vmcore/options.h" + #if !defined(__DARWIN__) # if defined(__LINUX__) # define GC_LINUX_THREADS @@ -1802,7 +1802,7 @@ void threads_sleep(s8 millis, s4 nanos) wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime); if (wasinterrupted) - *exceptionptr = new_exception(string_java_lang_InterruptedException); + exceptions_throw_interruptedexception(); } diff --git a/src/threads/native/threads.h b/src/threads/native/threads.h index e1b8f0384..38bca07e8 100644 --- a/src/threads/native/threads.h +++ b/src/threads/native/threads.h @@ -1,6 +1,6 @@ /* src/threads/native/threads.h - native threads header - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Stefan Ring - Edwin Steiner - Christian Thalinger - - $Id: threads.h 6251 2006-12-27 23:15:56Z twisti $ + $Id: threads.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -53,10 +47,13 @@ typedef struct threads_table_t threads_table_t; #include "mm/memory.h" #include "native/jni.h" #include "native/include/java_lang_Thread.h" -#include "vm/global.h" #include "threads/native/lock.h" +#include "vm/global.h" + +#include "vm/jit/stacktrace.h" + #if defined(ENABLE_INTRP) #include "vm/jit/intrp/intrp.h" #endif @@ -184,6 +181,16 @@ struct threadobject { }; +/* exception pointer **********************************************************/ + +#define exceptionptr (&(THREADOBJECT->_exceptionptr)) + + +/* stackframeinfo *************************************************************/ + +#define STACKFRAMEINFO (&(THREADOBJECT->_stackframeinfo)) + + /* variables ******************************************************************/ extern threadobject *mainthreadobj; diff --git a/src/threads/none/lock.h b/src/threads/none/lock.h index 9dbc9c0ce..b671bd7e6 100644 --- a/src/threads/none/lock.h +++ b/src/threads/none/lock.h @@ -1,6 +1,6 @@ /* src/threads/none/lock.h - fake lock implementation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: Christian Thalinger - $Id: threads.h 4866 2006-05-01 21:40:38Z edwin $ */ diff --git a/src/threads/none/threads.h b/src/threads/none/threads.h index c6a9d3e28..fcdfdc357 100644 --- a/src/threads/none/threads.h +++ b/src/threads/none/threads.h @@ -1,6 +1,6 @@ /* src/threads/none/threads.h - fake threads header - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: threads.h 4405 2006-02-03 12:46:22Z twisti $ */ @@ -47,6 +41,20 @@ #define threadobject void + +/* exception pointer **********************************************************/ + +extern java_objectheader *_no_threads_exceptionptr; + +#define exceptionptr (&_no_threads_exceptionptr) + + +/* stackframeinfo *************************************************************/ + +extern stackframeinfo *_no_threads_stackframeinfo; + +#define STACKFRAMEINFO (&_no_threads_stackframeinfo) + #endif /* _THREADS_H */ diff --git a/src/toolbox/Makefile.am b/src/toolbox/Makefile.am index 566797ff8..58b5da335 100644 --- a/src/toolbox/Makefile.am +++ b/src/toolbox/Makefile.am @@ -1,6 +1,6 @@ ## src/toolbox/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -26,9 +26,7 @@ ## ## Authors: Christian Thalinger ## -## Changes: -## -## $Id: Makefile.am 5234 2006-08-14 17:50:12Z christian $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in @@ -36,13 +34,18 @@ AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR) -I$(top LIBS = -noinst_LTLIBRARIES = libtoolbox.la +noinst_LTLIBRARIES = \ + libtoolbox.la libtoolbox_la_SOURCES = \ avl.c \ avl.h \ + bitvector.c \ + bitvector.h \ chain.c \ chain.h \ + hashtable.c \ + hashtable.h \ list.c \ list.h \ logging.c \ @@ -51,8 +54,6 @@ libtoolbox_la_SOURCES = \ tree.h \ util.c \ util.h \ - bitvector.c \ - bitvector.h \ worklist.c \ worklist.h diff --git a/src/toolbox/avl.c b/src/toolbox/avl.c index 24981f51c..15337fa43 100644 --- a/src/toolbox/avl.c +++ b/src/toolbox/avl.c @@ -1,6 +1,6 @@ /* src/toolbox/avl.c - AVL tree implementation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: avl.c 5123 2006-07-12 21:45:34Z twisti $ + $Id: avl.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -44,7 +38,6 @@ #if defined(ENABLE_THREADS) # include "threads/native/lock.h" -# include "threads/native/threads.h" #else # include "threads/none/lock.h" #endif diff --git a/src/toolbox/hashtable.c b/src/toolbox/hashtable.c new file mode 100644 index 000000000..d6d7bf185 --- /dev/null +++ b/src/toolbox/hashtable.c @@ -0,0 +1,141 @@ +/* src/vm/hashtable.c - functions for internal hashtables + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + Contact: cacao@cacaojvm.org + + Authors: Reinhard Grafl + Mark Probst + Andreas Krall + Christian Thalinger + + $Id: hashtable.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "toolbox/hashtable.h" +#include "vm/global.h" + + +/* hashtable_create ************************************************************ + + Initializes a hashtable structure and allocates memory. The + parameter size specifies the initial size of the hashtable. + +*******************************************************************************/ + +void hashtable_create(hashtable *hash, u4 size) +{ + /* initialize locking pointer */ + +#if defined(ENABLE_THREADS) + /* We need to seperately allocate a java_objectheader here, as we + need to store the lock object in the new hashtable if it's + resized. Otherwise we get an IllegalMonitorStateException. */ + + hash->header = NEW(java_objectheader); + + lock_init_object_lock(hash->header); +#endif + + /* set initial hash values */ + + hash->size = size; + hash->entries = 0; + hash->ptr = MNEW(void*, size); + + /* MNEW always allocates memory zeroed out, no need to clear the table */ +} + + +/* hashtable_resize ************************************************************ + + Creates a new hashtable with specified size and moves the important + stuff from the old hashtable. + +*******************************************************************************/ + +hashtable *hashtable_resize(hashtable *hash, u4 size) +{ + hashtable *newhash; + + /* create new hashtable with specified size */ + + newhash = NEW(hashtable); + + hashtable_create(newhash, size); + +#if defined(ENABLE_THREADS) + /* We need to store the old lock object in the new hashtable. + Otherwise we get an IllegalMonitorStateException. */ + + FREE(newhash->header, java_objectheader); + + newhash->header = hash->header; +#endif + + /* store the number of entries in the new hashtable */ + + newhash->entries = hash->entries; + + return newhash; +} + + +/* hashtable_free ************************************************************** + + Simply frees the hashtable. + + ATTENTION: It does NOT free the lock object! + +*******************************************************************************/ + +void hashtable_free(hashtable *hash) +{ + MFREE(hash->ptr, void*, hash->size); + FREE(hash, hashtable); +} + + +/* + * 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: + */ diff --git a/src/toolbox/hashtable.h b/src/toolbox/hashtable.h new file mode 100644 index 000000000..056dbc1c0 --- /dev/null +++ b/src/toolbox/hashtable.h @@ -0,0 +1,138 @@ +/* src/toolbox/hashtable.h - functions for internal hashtables + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + Contact: cacao@cacaojvm.org + + Authors: Reinhard Grafl + Christian Thalinger + + $Id: hashtable.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _HASHTABLE_H +#define _HASHTABLE_H + +/* forward typedefs ***********************************************************/ + +typedef struct hashtable hashtable; + + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" +#include "vmcore/utf8.h" + + +/* data structures for hashtables ******************************************** + + All utf-symbols, javastrings and classes are stored in global + hashtables, so every symbol exists only once. Equal symbols have + identical pointers. The functions for adding hashtable elements + search the table for the element with the specified name/text and + return it on success. Otherwise a new hashtable element is created. + + The hashtables use external linking for handling collisions. The + hashtable structure contains a pointer to the array of + hashtable slots. The number of hashtable slots and therefore the + size of this array is specified by the element of hashtable + structure. contains the number of all hashtable elements + stored in the table, including those in the external chains. The + hashtable element structures (utf, literalstring, classinfo) + contain both a pointer to the next hashtable element as a link for + the external hash chain and the key of the element. The key is + computed from the text of the string or the classname by using up + to 8 characters. + + If the number of entries in the hashtable exceeds twice the size of + the hashtableslot-array it is supposed that the average length of + the external chains has reached a value beyond 2. Therefore the + functions for adding hashtable elements (utf_new, class_new, + literalstring_new) double the hashtableslot-array. In this + restructuring process all elements have to be inserted into the new + hashtable and new external chains must be built. + + Example for the layout of a hashtable: + +hashtable.ptr-->+-------------------+ + | | + ... + | | + +-------------------+ +-------------------+ +-------------------+ + | hashtable element |-->| hashtable element |-->| hashtable element |-->NULL + +-------------------+ +-------------------+ +-------------------+ + | hashtable element | + +-------------------+ +-------------------+ + | hashtable element |-->| hashtable element |-->NULL + +-------------------+ +-------------------+ + | hashtable element |-->NULL + +-------------------+ + | | + ... + | | + +-------------------+ + +*/ + + +/* hashtable ******************************************************************/ + +struct hashtable { +#if defined(ENABLE_THREADS) + java_objectheader *header; /* required for locking */ +#endif + u4 size; /* current size of the hashtable */ + u4 entries; /* number of entries in the table */ + void **ptr; /* pointer to hashtable */ +}; + + +/* function prototypes ********************************************************/ + +/* create hashtable */ +void hashtable_create(hashtable *hash, u4 size); + +/* creates and resizes a hashtable */ +hashtable *hashtable_resize(hashtable *hash, u4 size); + +/* frees a hashtable */ +void hashtable_free(hashtable *hash); + +#endif /* _HASHTABLE_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: + */ diff --git a/src/toolbox/list.c b/src/toolbox/list.c index f9569ae7a..e277eb572 100644 --- a/src/toolbox/list.c +++ b/src/toolbox/list.c @@ -1,6 +1,6 @@ /* src/toolbox/list.c - double linked list - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - $Id: list.c 5894 2006-11-02 12:54:15Z twisti $ + $Id: list.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,7 +37,6 @@ #if defined(ENABLE_THREADS) # include "threads/native/lock.h" -# include "threads/native/threads.h" #else # include "threads/none/lock.h" #endif diff --git a/src/toolbox/logging.c b/src/toolbox/logging.c index 3e4218abc..0d21c1a8e 100644 --- a/src/toolbox/logging.c +++ b/src/toolbox/logging.c @@ -1,6 +1,6 @@ /* src/toolbox/logging.c - contains logging functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,14 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Christian Thalinger - Edwin Steiner - - $Id: logging.c 4967 2006-05-26 16:24:58Z edwin $ + $Id: logging.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -46,11 +39,16 @@ #include "toolbox/logging.h" #include "toolbox/util.h" #include "vm/global.h" -#include "vm/statistics.h" +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#if 0 #if defined(ENABLE_THREADS) # include "threads/native/threads.h" #endif +#endif /*************************************************************************** @@ -81,12 +79,14 @@ void log_start(void) { if (logfile) { #if defined(ENABLE_THREADS) - fprintf(logfile, "[%p] ", (void *) THREADOBJECT); +#warning FIX ME! +/* fprintf(logfile, "[%p] ", (void *) threads_get_current_threadobject()); */ #endif } else { #if defined(ENABLE_THREADS) - fprintf(stdout, "LOG: [%p] ", (void *) THREADOBJECT); +#warning FIX ME! +/* fprintf(stdout, "LOG: [%p] ", (void *) threads_get_current_threadobject()); */ #else fputs("LOG: ", stdout); #endif diff --git a/src/toolbox/logging.h b/src/toolbox/logging.h index cc8b7a136..3af0a0df9 100644 --- a/src/toolbox/logging.h +++ b/src/toolbox/logging.h @@ -1,6 +1,6 @@ /* src/toolbox/logging.h - contains logging functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Christan Thalinger - - $Id: logging.h 5464 2006-09-11 14:45:13Z edwin $ + $Id: logging.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,9 +35,9 @@ #include #include -#include "vm/class.h" -#include "vm/method.h" -#include "vm/utf8.h" +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/utf8.h" /*500 is to small for eclipse traces, (builtin_trace_args, perhaps the diff --git a/src/vm/Makefile.am b/src/vm/Makefile.am index 9c6da3a59..50db1ba23 100644 --- a/src/vm/Makefile.am +++ b/src/vm/Makefile.am @@ -1,6 +1,6 @@ ## src/vm/Makefile.am ## -## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, ## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, ## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, ## J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ## 02110-1301, USA. ## -## Contact: cacao@cacaojvm.org -## -## Authors: Christian Thalinger -## -## $Id: Makefile.am 6216 2006-12-18 18:21:37Z twisti $ +## $Id: Makefile.am 7246 2007-01-29 18:49:05Z twisti $ ## Process this file with automake to produce Makefile.in @@ -36,104 +32,42 @@ LIBS = SUBDIRS = jit -if ENABLE_JAVASE -ANNOTATION_SOURCES = \ - annotation.c \ - annotation.h - -STACKMAP_SOURCES = \ - stackmap.c \ - stackmap.h -endif - -if ENABLE_STATISTICS -STATISTICS_SOURCES = \ - statistics.c \ - statistics.h -endif - -if ENABLE_RT_TIMING -RT_TIMING_OBJ = \ - rt-timing.c -endif - if ENABLE_CYCLES_STATS -CYCLES_STATS_SOURCE = \ +CYCLES_STATS_SOURCES = \ cycles-stats.c \ cycles-stats.h endif -if ENABLE_ZLIB -ZLIB_OBJ = \ - zip.c \ - zip.h -endif - noinst_HEADERS = \ global.h \ types.h noinst_LTLIBRARIES = \ - libvmcore.la \ libvm.la -libvmcore_la_SOURCES = \ +libvm_la_SOURCES = \ access.c \ access.h \ - $(ANNOTATION_SOURCES) \ builtin.c \ builtin.h \ builtintable.inc \ - class.c \ - class.h \ - classcache.c \ - classcache.h \ - $(CYCLES_STATS_SOURCE) \ - descriptor.c \ - descriptor.h \ - field.c \ - field.h \ + $(CYCLES_STATS_SOURCES) \ + exceptions.c \ + exceptions.h \ finalizer.c \ finalizer.h \ - hashtable.c \ - hashtable.h \ initialize.c \ initialize.h \ - linker.c \ - linker.h \ - loader.c \ - loader.h \ - method.c \ - method.h \ - options.c \ - options.h \ properties.c \ properties.h \ - references.h \ - resolve.c \ - resolve.h \ - $(RT_TIMING_OBJ) \ - rt-timing.h \ - $(STATISTICS_SOURCES) \ signal.c \ signallocal.h \ - $(STACKMAP_SOURCES) \ string.c \ stringlocal.h \ - suck.c \ - suck.h \ - utf8.c \ - utf8.h \ - $(ZLIB_OBJ) - -libvm_la_SOURCES = \ - exceptions.c \ - exceptions.h \ vm.c \ vm.h libvm_la_LIBADD = \ - libvmcore.la \ jit/libjit.la diff --git a/src/vm/access.c b/src/vm/access.c index fa36e0fd9..66c9db65a 100644 --- a/src/vm/access.c +++ b/src/vm/access.c @@ -1,6 +1,6 @@ -/* vm/access.c - checking access rights +/* src/vmcore/access.c - checking access rights - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id: access.c 5846 2006-10-28 13:02:19Z edwin $ + $Id: access.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,9 +35,11 @@ #include "vm/access.h" #include "vm/builtin.h" -#include "vm/class.h" #include "vm/exceptions.h" -#include "vm/stringlocal.h" + +#include "vm/jit/stacktrace.h" + +#include "vmcore/class.h" /****************************************************************************/ @@ -186,7 +182,8 @@ bool access_check_caller(classinfo *declarer, s4 memberflags, s4 calldepth) /* get the caller's class */ oa = stacktrace_getClassContext(); - if (!oa) + + if (oa == NULL) return false; assert(calldepth >= 0 && calldepth < oa->header.size); @@ -198,8 +195,7 @@ bool access_check_caller(classinfo *declarer, s4 memberflags, s4 calldepth) if (!access_is_accessible_class(callerclass, declarer) || !access_is_accessible_member(callerclass, declarer, memberflags)) { - *exceptionptr = - new_exception(string_java_lang_IllegalAccessException); + exceptions_throw_illegalaccessexception(callerclass); return false; } @@ -208,6 +204,7 @@ bool access_check_caller(classinfo *declarer, s4 memberflags, s4 calldepth) return true; } + /* * 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 diff --git a/src/vm/access.h b/src/vm/access.h index 61e47ee88..d46cd4f16 100644 --- a/src/vm/access.h +++ b/src/vm/access.h @@ -1,6 +1,6 @@ -/* src/vm/access.h - checking access rights +/* src/vmcore/access.h - checking access rights - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,23 +22,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id: access.h 5223 2006-08-08 16:21:22Z edwin $ + $Id: access.h 7246 2007-01-29 18:49:05Z twisti $ */ #ifndef _ACCESS_H #define _ACCESS_H +#include "config.h" #include "vm/types.h" -#include "vm/references.h" -#include "vm/class.h" +#include "vm/global.h" + +#include "vmcore/class.h" + /* macros *********************************************************************/ diff --git a/src/vm/annotation.c b/src/vm/annotation.c deleted file mode 100644 index 98aeef2f8..000000000 --- a/src/vm/annotation.c +++ /dev/null @@ -1,181 +0,0 @@ -/* src/vm/annotation.c - class annotations - - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ - -*/ - - -#include "config.h" -#include "vm/types.h" - -#include "mm/memory.h" -#include "vm/annotation.h" -#include "vm/class.h" -#include "vm/suck.h" - - -/* annotation_load_attribute_runtimevisibleannotations ************************* - - RuntimeVisibleAnnotations_attribute { - u2 attribute_name_index; - u4 attribute_length; - u2 num_annotations; - annotation annotations[num_annotations]; - } - - annotation { - u2 type_index; - u2 num_element_value_pairs; - { - u2 element_name_index; - element_value element; - } element_value_pairs[num_element_value_pairs]; - } - - element_value { - u1 tag; - union { - u2 const_value_index; - { - u2 type_name_index; - u2 const_name_index; - } enum_const_value; - u2 class_info_index; - annotation annotation_value; - { - u2 num_values; - element_value values[num_values]; - } array_value; - } value; - } - -*******************************************************************************/ - -bool annotation_load_attribute_runtimevisibleannotations(classbuffer *cb) -{ - classinfo *c; - u4 attribute_length; - u2 num_annotations; - annotation_t *aa; - element_value_t *element_value; - u2 type_index; - u2 num_element_value_pairs; - u2 element_name_index; - u4 i, j; - - /* get classinfo */ - - c = cb->class; - - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* attribute_length */ - - attribute_length = suck_u4(cb); - - if (!suck_check_classbuffer_size(cb, attribute_length)) - return false; - - /* get number of annotations */ - - num_annotations = suck_u2(cb); - - printf("num_annotations: %d\n", num_annotations); - - /* allocate annotations-array */ - - aa = MNEW(annotation_t, num_annotations); - - /* parse all annotations */ - - for (i = 0; i < num_annotations; i++) { - /* get annotation type */ - - type_index = suck_u2(cb); - - if (!(aa[i].type = class_getconstant(c, type_index, CONSTANT_Utf8))) - return false; - - printf("type: "); - utf_display_printable_ascii(aa[i].type); - printf("\n"); - - /* get number of element values */ - - num_element_value_pairs = suck_u2(cb); - - printf("num_element_value_pairs: %d\n", num_element_value_pairs); - - element_value = MNEW(element_value_t, num_element_value_pairs); - - /* parse all element values */ - - for (j = 0; j < num_element_value_pairs; j++) { - /* get element name */ - - element_name_index = suck_u2(cb); - - if (!(element_value[j].name = - class_getconstant(c, element_name_index, CONSTANT_Utf8))) - return false; - - /* get element tag */ - - element_value[i].tag = suck_u1(cb); - } - - /* store element value data */ - - aa[i].element_valuescount = num_element_value_pairs; - aa[i].element_values = element_value; - } - - /* store annotation variables */ - - c->runtimevisibleannotationscount = num_annotations; - c->runtimevisibleannotations = aa; - - return true; -} - - -/* - * 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: - */ diff --git a/src/vm/annotation.h b/src/vm/annotation.h deleted file mode 100644 index fd3f5c9a8..000000000 --- a/src/vm/annotation.h +++ /dev/null @@ -1,86 +0,0 @@ -/* src/vm/annotation.h - class annotations - - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ - -*/ - - -#ifndef _ANNOTATION_H -#define _ANNOTATION_H - -/* forward typedefs ***********************************************************/ - -typedef struct annotation_t annotation_t; -typedef struct element_value_t element_value_t; - -#include "config.h" -#include "vm/types.h" - -#include "vm/global.h" -#include "vm/loader.h" -#include "vm/utf8.h" - - -/* annotation *****************************************************************/ - -struct annotation_t { - utf *type; - s4 element_valuescount; - element_value_t *element_values; -}; - - -/* element_value **************************************************************/ - -struct element_value_t { - utf *name; - u1 tag; -}; - - -/* function prototypes ********************************************************/ - -bool annotation_load_attribute_runtimevisibleannotations(classbuffer *cb); - -#endif /* _ANNOTATION_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: - */ diff --git a/src/vm/builtin.c b/src/vm/builtin.c index ee42646aa..269a559cc 100644 --- a/src/vm/builtin.c +++ b/src/vm/builtin.c @@ -22,21 +22,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Andreas Krall - Mark Probst - Christian Thalinger - Edwin Steiner - Contains C functions for JavaVM Instructions that cannot be translated to machine language directly. Consequently, the generated machine code for these instructions contains function calls instead of machine instructions, using the C calling convention. - $Id: builtin.c 7241 2007-01-27 15:52:01Z twisti $ + $Id: builtin.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -63,24 +55,31 @@ #include "mm/gc-common.h" #include "mm/memory.h" +#include "native/jni.h" +#include "native/include/java_lang_String.h" +#include "native/include/java_lang_Throwable.h" + #if defined(ENABLE_THREADS) # include "threads/native/threads.h" #endif #include "toolbox/logging.h" #include "toolbox/util.h" + #include "vm/builtin.h" -#include "vm/class.h" +#include "vm/cycles-stats.h" #include "vm/exceptions.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" + #include "vm/jit/asmpart.h" #include "vm/jit/patcher.h" -#include "vm/rt-timing.h" -#include "vm/cycles-stats.h" + +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/rt-timing.h" /* include builtin tables *****************************************************/ @@ -811,9 +810,7 @@ java_objectheader *builtin_new(classinfo *c) /* check if we can instantiate this class */ if (c->flags & ACC_ABSTRACT) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_InstantiationError, - c->name); + exceptions_throw_instantiationerror(c); return NULL; } @@ -2710,8 +2707,7 @@ java_objectheader *builtin_clone(void *env, java_objectheader *o) /* we are cloning a non-array */ if (!builtin_instanceof(o, class_java_lang_Cloneable)) { - *exceptionptr = - new_exception(string_java_lang_CloneNotSupportedException); + exceptions_throw_clonenotsupportedexception(); return NULL; } diff --git a/src/vm/builtin.h b/src/vm/builtin.h index 3886016e9..c41ca6bd1 100644 --- a/src/vm/builtin.h +++ b/src/vm/builtin.h @@ -1,6 +1,6 @@ /* src/vm/builtin.h - prototypes of builtin functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Edwin Steiner - Christian Thalinger - - $Id: builtin.h 6013 2006-11-16 22:14:10Z twisti $ + $Id: builtin.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -37,15 +31,13 @@ #define _BUILTIN_H #include "config.h" +#include "vm/types.h" #include "arch.h" -#include "toolbox/logging.h" -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif +#include "toolbox/logging.h" -#include "vm/jit/stacktrace.h" +#include "vmcore/utf8.h" /* define infinity for floating point numbers */ diff --git a/src/vm/class.c b/src/vm/class.c deleted file mode 100644 index 1e50710a1..000000000 --- a/src/vm/class.c +++ /dev/null @@ -1,1689 +0,0 @@ -/* src/vm/class.c - class related functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Mark Probst - Andreas Krall - Christian Thalinger - Edwin Steiner - - $Id: class.c 6251 2006-12-27 23:15:56Z twisti $ - -*/ - - -#include "config.h" - -#include -#include -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif - -#include "toolbox/logging.h" -#include "vm/class.h" -#include "vm/classcache.h" -#include "vm/exceptions.h" -#include "vm/global.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" -#include "vm/stringlocal.h" -#include "vm/suck.h" -#include "vm/utf8.h" - - -/* global variables ***********************************************************/ - -list unlinkedclasses; /* this is only used for eager class */ - /* loading */ - - -/* frequently used classes ****************************************************/ - -/* important system classes */ - -classinfo *class_java_lang_Object; -classinfo *class_java_lang_Class; -classinfo *class_java_lang_ClassLoader; -classinfo *class_java_lang_Cloneable; -classinfo *class_java_lang_SecurityManager; -classinfo *class_java_lang_String; -classinfo *class_java_lang_System; -classinfo *class_java_lang_Thread; -classinfo *class_java_lang_ThreadGroup; -classinfo *class_java_lang_VMSystem; -classinfo *class_java_lang_VMThread; -classinfo *class_java_io_Serializable; - - -/* system exception classes required in cacao */ - -classinfo *class_java_lang_Throwable; -classinfo *class_java_lang_Error; -classinfo *class_java_lang_LinkageError; -classinfo *class_java_lang_NoClassDefFoundError; -classinfo *class_java_lang_OutOfMemoryError; -classinfo *class_java_lang_VirtualMachineError; - -#if defined(ENABLE_JAVASE) -classinfo *class_java_lang_AbstractMethodError; -classinfo *class_java_lang_NoSuchMethodError; -#endif - -#if defined(WITH_CLASSPATH_GNU) -classinfo *class_java_lang_VMThrowable; -#endif - -classinfo *class_java_lang_Exception; -classinfo *class_java_lang_ClassCastException; -classinfo *class_java_lang_ClassNotFoundException; -classinfo *class_java_lang_IllegalArgumentException; -classinfo *class_java_lang_IllegalMonitorStateException; - -#if defined(ENABLE_JAVASE) -classinfo *class_java_lang_Void; -#endif -classinfo *class_java_lang_Boolean; -classinfo *class_java_lang_Byte; -classinfo *class_java_lang_Character; -classinfo *class_java_lang_Short; -classinfo *class_java_lang_Integer; -classinfo *class_java_lang_Long; -classinfo *class_java_lang_Float; -classinfo *class_java_lang_Double; - - -/* some runtime exception */ - -classinfo *class_java_lang_NullPointerException; - - -/* some classes which may be used more often */ - -#if defined(ENABLE_JAVASE) -classinfo *class_java_lang_StackTraceElement; -classinfo *class_java_lang_reflect_Constructor; -classinfo *class_java_lang_reflect_Field; -classinfo *class_java_lang_reflect_Method; -classinfo *class_java_security_PrivilegedAction; -classinfo *class_java_util_Vector; - -classinfo *arrayclass_java_lang_Object; -#endif - - -/* pseudo classes for the typechecker */ - -classinfo *pseudo_class_Arraystub; -classinfo *pseudo_class_Null; -classinfo *pseudo_class_New; - - -/* class_set_packagename ******************************************************* - - Derive the package name from the class name and store it in the struct. - -*******************************************************************************/ - -void class_set_packagename(classinfo *c) -{ - char *p = UTF_END(c->name) - 1; - char *start = c->name->text; - - /* set the package name */ - /* classes in the unnamed package keep packagename == NULL */ - - if (c->name->text[0] == '[') { - /* set packagename of arrays to the element's package */ - - for (; *start == '['; start++); - - /* skip the 'L' in arrays of references */ - if (*start == 'L') - start++; - - for (; (p > start) && (*p != '/'); --p); - - c->packagename = utf_new(start, p - start); - - } else { - for (; (p > start) && (*p != '/'); --p); - - c->packagename = utf_new(start, p - start); - } -} - - -/* class_create_classinfo ****************************************************** - - Create a new classinfo struct. The class name is set to the given utf *, - most other fields are initialized to zero. - - Note: classname may be NULL. In this case a not-yet-named classinfo is - created. The name must be filled in later and class_set_packagename - must be called after that. - -*******************************************************************************/ - -classinfo *class_create_classinfo(utf *classname) -{ - classinfo *c; - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - size_classinfo += sizeof(classinfo); -#endif - - /* we use a safe name for temporarily unnamed classes */ - if (!classname) - classname = utf_not_named_yet; - -#if !defined(NDEBUG) - if (initverbose) - log_message_utf("Creating class: ", classname); -#endif - - /* GCNEW_UNCOLLECTABLE clears the allocated memory */ - - c = GCNEW_UNCOLLECTABLE(classinfo, 1); - /*c=NEW(classinfo);*/ - c->name = classname; - - /* set the header.vftbl of all loaded classes to the one of - java.lang.Class, so Java code can use a class as object */ - - if (class_java_lang_Class) - if (class_java_lang_Class->vftbl) - c->object.header.vftbl = class_java_lang_Class->vftbl; - - if (classname != utf_not_named_yet) - class_set_packagename(c); - -#if defined(ENABLE_THREADS) - lock_init_object_lock(&c->object.header); -#endif - - return c; -} - - -/* class_postset_header_vftbl ************************************************** - - Set the header.vftbl of all classes created before java.lang.Class - was linked. This is necessary that Java code can use a class as - object. - -*******************************************************************************/ - -void class_postset_header_vftbl(void) -{ - classinfo *c; - u4 slot; - classcache_name_entry *nmen; - classcache_class_entry *clsen; - - assert(class_java_lang_Class); - - for (slot = 0; slot < hashtable_classcache.size; slot++) { - nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot]; - - for (; nmen; nmen = nmen->hashlink) { - /* iterate over all class entries */ - - for (clsen = nmen->classes; clsen; clsen = clsen->next) { - c = clsen->classobj; - - /* now set the the vftbl */ - - if (c->object.header.vftbl == NULL) - c->object.header.vftbl = class_java_lang_Class->vftbl; - } - } - } -} - - -/* class_load_attribute_sourcefile ********************************************* - - SourceFile_attribute { - u2 attribute_name_index; - u4 attribute_length; - u2 sourcefile_index; - } - -*******************************************************************************/ - -static bool class_load_attribute_sourcefile(classbuffer *cb) -{ - classinfo *c; - u4 attribute_length; - u2 sourcefile_index; - utf *sourcefile; - - /* get classinfo */ - - c = cb->class; - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* check attribute length */ - - attribute_length = suck_u4(cb); - - if (attribute_length != 2) { - exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); - return false; - } - - /* there can be no more than one SourceFile attribute */ - - if (c->sourcefile != NULL) { - exceptions_throw_classformaterror(c, "Multiple SourceFile attributes"); - return false; - } - - /* get sourcefile */ - - sourcefile_index = suck_u2(cb); - sourcefile = class_getconstant(c, sourcefile_index, CONSTANT_Utf8); - - if (sourcefile == NULL) - return false; - - /* store sourcefile */ - - c->sourcefile = sourcefile; - - return true; -} - - -/* class_load_attribute_enclosingmethod **************************************** - - EnclosingMethod_attribute { - u2 attribute_name_index; - u4 attribute_length; - u2 class_index; - u2 method_index; - } - -*******************************************************************************/ - -#if defined(ENABLE_JAVASE) -static bool class_load_attribute_enclosingmethod(classbuffer *cb) -{ - classinfo *c; - u4 attribute_length; - u2 class_index; - u2 method_index; - classref_or_classinfo cr; - constant_nameandtype *cn; - - /* get classinfo */ - - c = cb->class; - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 4 + 2 + 2)) - return false; - - /* check attribute length */ - - attribute_length = suck_u4(cb); - - if (attribute_length != 4) { - exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); - return false; - } - - /* there can be no more than one EnclosingMethod attribute */ - - if (c->enclosingmethod != NULL) { - exceptions_throw_classformaterror(c, "Multiple EnclosingMethod attributes"); - return false; - } - - /* get class index */ - - class_index = suck_u2(cb); - cr.ref = innerclass_getconstant(c, class_index, CONSTANT_Class); - - /* get method index */ - - method_index = suck_u2(cb); - cn = innerclass_getconstant(c, method_index, CONSTANT_NameAndType); - - /* store info in classinfo */ - - c->enclosingclass.any = cr.any; - c->enclosingmethod = cn; - - return true; -} -#endif /* defined(ENABLE_JAVASE) */ - - -/* class_load_attributes ******************************************************* - - Read attributes from ClassFile. - - attribute_info { - u2 attribute_name_index; - u4 attribute_length; - u1 info[attribute_length]; - } - - InnerClasses_attribute { - u2 attribute_name_index; - u4 attribute_length; - } - -*******************************************************************************/ - -bool class_load_attributes(classbuffer *cb) -{ - classinfo *c; - u4 i, j; - u2 attributes_count; - u2 attribute_name_index; - utf *attribute_name; - - c = cb->class; - - /* get attributes count */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - attributes_count = suck_u2(cb); - - for (i = 0; i < attributes_count; i++) { - /* get attribute name */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - 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_InnerClasses) { - /* InnerClasses */ - - if (c->innerclass != NULL) { - exceptions_throw_classformaterror(c, "Multiple InnerClasses attributes"); - return false; - } - - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* skip attribute length */ - suck_u4(cb); - - /* number of records */ - c->innerclasscount = suck_u2(cb); - - if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) - return false; - - /* allocate memory for innerclass structure */ - c->innerclass = MNEW(innerclassinfo, c->innerclasscount); - - for (j = 0; j < c->innerclasscount; j++) { - /* The innerclass structure contains a class with an encoded - name, its defining scope, its simple name and a bitmask of - the access flags. If an inner class is not a member, its - outer_class is NULL, if a class is anonymous, its name is - NULL. */ - - innerclassinfo *info = c->innerclass + j; - - info->inner_class.ref = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); - info->outer_class.ref = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); - info->name = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - info->flags = suck_u2(cb); - } - } - else if (attribute_name == utf_SourceFile) { - /* SourceFile */ - - if (!class_load_attribute_sourcefile(cb)) - return false; - } -#if defined(ENABLE_JAVASE) - else if (attribute_name == utf_EnclosingMethod) { - /* EnclosingMethod */ - - if (!class_load_attribute_enclosingmethod(cb)) - return false; - } - else if (attribute_name == utf_Signature) { - /* Signature */ - - if (!loader_load_attribute_signature(cb, &(c->signature))) - return false; - } - else if (attribute_name == utf_RuntimeVisibleAnnotations) { - /* RuntimeVisibleAnnotations */ - - if (!annotation_load_attribute_runtimevisibleannotations(cb)) - return false; - } -#endif - else { - /* unknown attribute */ - - if (!loader_skip_attribute_body(cb)) - return false; - } - } - - return true; -} - - -/* class_freepool ************************************************************** - - Frees all resources used by this classes Constant Pool. - -*******************************************************************************/ - -static void class_freecpool(classinfo *c) -{ - u4 idx; - u4 tag; - voidptr info; - - if (c->cptags && c->cpinfos) { - for (idx = 0; idx < c->cpcount; idx++) { - tag = c->cptags[idx]; - info = c->cpinfos[idx]; - - if (info != NULL) { - switch (tag) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - FREE(info, constant_FMIref); - break; - case CONSTANT_Integer: - FREE(info, constant_integer); - break; - case CONSTANT_Float: - FREE(info, constant_float); - break; - case CONSTANT_Long: - FREE(info, constant_long); - break; - case CONSTANT_Double: - FREE(info, constant_double); - break; - case CONSTANT_NameAndType: - FREE(info, constant_nameandtype); - break; - } - } - } - } - - if (c->cptags) - MFREE(c->cptags, u1, c->cpcount); - - if (c->cpinfos) - MFREE(c->cpinfos, voidptr, c->cpcount); -} - - -/* class_getconstant *********************************************************** - - Retrieves the value at position 'pos' of the constantpool of a - class. If the type of the value is other than 'ctype', an error is - thrown. - -*******************************************************************************/ - -voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype) -{ - /* check index and type of constantpool entry */ - /* (pos == 0 is caught by type comparison) */ - - if ((pos >= c->cpcount) || (c->cptags[pos] != ctype)) { - exceptions_throw_classformaterror(c, "Illegal constant pool index"); - return NULL; - } - - return c->cpinfos[pos]; -} - - -/* innerclass_getconstant ****************************************************** - - Like class_getconstant, but if cptags is ZERO, null is returned. - -*******************************************************************************/ - -voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) -{ - /* invalid position in constantpool */ - - if (pos >= c->cpcount) { - exceptions_throw_classformaterror(c, "Illegal constant pool index"); - return NULL; - } - - /* constantpool entry of type 0 */ - - if (c->cptags[pos] == 0) - return NULL; - - /* check type of constantpool entry */ - - if (c->cptags[pos] != ctype) { - *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); - return NULL; - } - - return c->cpinfos[pos]; -} - - -/* class_free ****************************************************************** - - Frees all resources used by the class. - -*******************************************************************************/ - -void class_free(classinfo *c) -{ - s4 i; - vftbl_t *v; - - class_freecpool(c); - - if (c->interfaces) - MFREE(c->interfaces, classinfo*, c->interfacescount); - - if (c->fields) { - for (i = 0; i < c->fieldscount; i++) - field_free(&(c->fields[i])); -#if defined(ENABLE_CACAO_GC) - MFREE(c->fields, fieldinfo, c->fieldscount); -#endif - } - - if (c->methods) { - for (i = 0; i < c->methodscount; i++) - method_free(&(c->methods[i])); - MFREE(c->methods, methodinfo, c->methodscount); - } - - if ((v = c->vftbl) != NULL) { - if (v->arraydesc) - mem_free(v->arraydesc,sizeof(arraydescriptor)); - - for (i = 0; i < v->interfacetablelength; i++) { - MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); - } - MFREE(v->interfacevftbllength, s4, v->interfacetablelength); - - i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) + - sizeof(methodptr*) * (v->interfacetablelength - - (v->interfacetablelength > 0)); - v = (vftbl_t*) (((methodptr*) v) - - (v->interfacetablelength - 1) * (v->interfacetablelength > 1)); - mem_free(v, i); - } - - if (c->innerclass) - MFREE(c->innerclass, innerclassinfo, c->innerclasscount); - - /* if (c->classvftbl) - mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */ - -/* GCFREE(c); */ -} - - -/* get_array_class ************************************************************* - - Returns the array class with the given name for the given - classloader, or NULL if an exception occurred. - - Note: This function does eager loading. - -*******************************************************************************/ - -static classinfo *get_array_class(utf *name,java_objectheader *initloader, - java_objectheader *defloader,bool link) -{ - classinfo *c; - - /* lookup this class in the classcache */ - c = classcache_lookup(initloader,name); - if (!c) - c = classcache_lookup_defined(defloader,name); - - if (!c) { - /* we have to create it */ - c = class_create_classinfo(name); - c = load_newly_created_array(c,initloader); - if (c == NULL) - return NULL; - } - - assert(c); - assert(c->state & CLASS_LOADED); - assert(c->classloader == defloader); - - if (link && !(c->state & CLASS_LINKED)) - if (!link_class(c)) - return NULL; - - assert(!link || (c->state & CLASS_LINKED)); - - return c; -} - - -/* class_array_of ************************************************************** - - Returns an array class with the given component class. The array - class is dynamically created if neccessary. - -*******************************************************************************/ - -classinfo *class_array_of(classinfo *component, bool link) -{ - s4 namelen; - char *namebuf; - s4 dumpsize; - classinfo *c; - - dumpsize = dump_size(); - - /* Assemble the array class name */ - namelen = component->name->blength; - - if (component->name->text[0] == '[') { - /* the component is itself an array */ - namebuf = DMNEW(char, namelen + 1); - namebuf[0] = '['; - MCOPY(namebuf + 1, component->name->text, char, namelen); - namelen++; - - } else { - /* the component is a non-array class */ - namebuf = DMNEW(char, namelen + 3); - namebuf[0] = '['; - namebuf[1] = 'L'; - MCOPY(namebuf + 2, component->name->text, char, namelen); - namebuf[2 + namelen] = ';'; - namelen += 3; - } - - c = get_array_class(utf_new(namebuf, namelen), - component->classloader, - component->classloader, - link); - - dump_release(dumpsize); - - return c; -} - - -/* class_multiarray_of ********************************************************* - - Returns an array class with the given dimension and element class. - The array class is dynamically created if neccessary. - -*******************************************************************************/ - -classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link) -{ - s4 namelen; - char *namebuf; - s4 dumpsize; - classinfo *c; - - dumpsize = dump_size(); - - if (dim < 1) { - log_text("Invalid array dimension requested"); - assert(0); - } - - /* Assemble the array class name */ - namelen = element->name->blength; - - if (element->name->text[0] == '[') { - /* the element is itself an array */ - namebuf = DMNEW(char, namelen + dim); - memcpy(namebuf + dim, element->name->text, namelen); - namelen += dim; - } - else { - /* the element is a non-array class */ - namebuf = DMNEW(char, namelen + 2 + dim); - namebuf[dim] = 'L'; - memcpy(namebuf + dim + 1, element->name->text, namelen); - namelen += (2 + dim); - namebuf[namelen - 1] = ';'; - } - memset(namebuf, '[', dim); - - c = get_array_class(utf_new(namebuf, namelen), - element->classloader, - element->classloader, - link); - - dump_release(dumpsize); - - return c; -} - - -/* class_lookup_classref ******************************************************* - - Looks up the constant_classref for a given classname in the classref - tables of a class. - - IN: - cls..............the class containing the reference - name.............the name of the class refered to - - RETURN VALUE: - a pointer to a constant_classref, or - NULL if the reference was not found - -*******************************************************************************/ - -constant_classref *class_lookup_classref(classinfo *cls, utf *name) -{ - constant_classref *ref; - extra_classref *xref; - int count; - - assert(cls); - assert(name); - assert(!cls->classrefcount || cls->classrefs); - - /* first search the main classref table */ - count = cls->classrefcount; - ref = cls->classrefs; - for (; count; --count, ++ref) - if (ref->name == name) - return ref; - - /* next try the list of extra classrefs */ - for (xref = cls->extclassrefs; xref; xref = xref->next) { - if (xref->classref.name == name) - return &(xref->classref); - } - - /* not found */ - return NULL; -} - - -/* class_get_classref ********************************************************** - - Returns the constant_classref for a given classname. - - IN: - cls..............the class containing the reference - name.............the name of the class refered to - - RETURN VALUE: - a pointer to a constant_classref (never NULL) - - NOTE: - The given name is not checked for validity! - -*******************************************************************************/ - -constant_classref *class_get_classref(classinfo *cls, utf *name) -{ - constant_classref *ref; - extra_classref *xref; - - assert(cls); - assert(name); - - ref = class_lookup_classref(cls,name); - if (ref) - return ref; - - xref = NEW(extra_classref); - CLASSREF_INIT(xref->classref,cls,name); - - xref->next = cls->extclassrefs; - cls->extclassrefs = xref; - - return &(xref->classref); -} - - -/* class_get_self_classref ***************************************************** - - Returns the constant_classref to the class itself. - - IN: - cls..............the class containing the reference - - RETURN VALUE: - a pointer to a constant_classref (never NULL) - -*******************************************************************************/ - -constant_classref *class_get_self_classref(classinfo *cls) -{ - /* XXX this should be done in a faster way. Maybe always make */ - /* the classref of index 0 a self reference. */ - return class_get_classref(cls,cls->name); -} - -/* class_get_classref_multiarray_of ******************************************** - - Returns an array type reference with the given dimension and element class - reference. - - IN: - dim..............the requested dimension - dim must be in [1;255]. This is NOT checked! - ref..............the component class reference - - RETURN VALUE: - a pointer to the class reference for the array type - - NOTE: - The referer of `ref` is used as the referer for the new classref. - -*******************************************************************************/ - -constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref) -{ - s4 namelen; - char *namebuf; - s4 dumpsize; - constant_classref *cr; - - assert(ref); - assert(dim >= 1 && dim <= 255); - - dumpsize = dump_size(); - - /* Assemble the array class name */ - namelen = ref->name->blength; - - if (ref->name->text[0] == '[') { - /* the element is itself an array */ - namebuf = DMNEW(char, namelen + dim); - memcpy(namebuf + dim, ref->name->text, namelen); - namelen += dim; - } - else { - /* the element is a non-array class */ - namebuf = DMNEW(char, namelen + 2 + dim); - namebuf[dim] = 'L'; - memcpy(namebuf + dim + 1, ref->name->text, namelen); - namelen += (2 + dim); - namebuf[namelen - 1] = ';'; - } - memset(namebuf, '[', dim); - - cr = class_get_classref(ref->referer,utf_new(namebuf, namelen)); - - dump_release(dumpsize); - - return cr; -} - - -/* class_get_classref_component_of ********************************************* - - Returns the component classref of a given array type reference - - IN: - ref..............the array type reference - - RETURN VALUE: - a reference to the component class, or - NULL if `ref` is not an object array type reference - - NOTE: - The referer of `ref` is used as the referer for the new classref. - -*******************************************************************************/ - -constant_classref *class_get_classref_component_of(constant_classref *ref) -{ - s4 namelen; - char *name; - - assert(ref); - - name = ref->name->text; - if (*name++ != '[') - return NULL; - - namelen = ref->name->blength - 1; - if (*name == 'L') { - name++; - namelen -= 2; - } - else if (*name != '[') { - return NULL; - } - - return class_get_classref(ref->referer, utf_new(name, namelen)); -} - - -/* class_findmethod ************************************************************ - - Searches a 'classinfo' structure for a method having the given name - and descriptor. If descriptor is NULL, it is ignored. - -*******************************************************************************/ - -methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *m; - s4 i; - - for (i = 0; i < c->methodscount; i++) { - m = &(c->methods[i]); - - if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc))) - return m; - } - - return NULL; -} - - -/* class_resolvemethod ********************************************************* - - Searches a class and it's super classes for a method. - - Superinterfaces are *not* searched. - -*******************************************************************************/ - -methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *m; - - while (c) { - m = class_findmethod(c, name, desc); - - if (m) - return m; - - /* JVM Specification bug: - - It is important NOT to resolve special and - methods to super classes or interfaces; yet, this is not - explicited in the specification. Section 5.4.3.3 should be - updated appropriately. */ - - if (name == utf_init || name == utf_clinit) - return NULL; - - c = c->super.cls; - } - - return NULL; -} - - -/* class_resolveinterfacemethod_intern ***************************************** - - Internally used helper function. Do not use this directly. - -*******************************************************************************/ - -static methodinfo *class_resolveinterfacemethod_intern(classinfo *c, - utf *name, utf *desc) -{ - methodinfo *m; - s4 i; - - /* try to find the method in the class */ - - m = class_findmethod(c, name, desc); - - if (m != NULL) - return m; - - /* no method found? try the superinterfaces */ - - for (i = 0; i < c->interfacescount; i++) { - m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, - name, desc); - - if (m != NULL) - return m; - } - - /* no method found */ - - return NULL; -} - - -/* class_resolveclassmethod **************************************************** - - Resolves a reference from REFERER to a method with NAME and DESC in - class C. - - If the method cannot be resolved the return value is NULL. If - EXCEPT is true *exceptionptr is set, too. - -*******************************************************************************/ - -methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool throwexception) -{ - classinfo *cls; - methodinfo *m; - s4 i; - -/* if (c->flags & ACC_INTERFACE) { */ -/* if (throwexception) */ -/* *exceptionptr = */ -/* new_exception(string_java_lang_IncompatibleClassChangeError); */ -/* return NULL; */ -/* } */ - - /* try class c and its superclasses */ - - cls = c; - - m = class_resolvemethod(cls, name, desc); - - if (m != NULL) - goto found; - - /* try the superinterfaces */ - - for (i = 0; i < c->interfacescount; i++) { - m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, - name, desc); - - if (m != NULL) - goto found; - } - - if (throwexception) { -#if defined(ENABLE_JAVASE) - exceptions_throw_nosuchmethoderror(c, name, desc); -#else - exceptions_throw_virtualmachineerror(); -#endif - } - - return NULL; - - found: - if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { - if (throwexception) { -#if defined(ENABLE_JAVASE) - exceptions_throw_abstractmethoderror(); -#else - exceptions_throw_virtualmachineerror(); -#endif - } - - return NULL; - } - - /* XXX check access rights */ - - return m; -} - - -/* class_resolveinterfacemethod ************************************************ - - Resolves a reference from REFERER to a method with NAME and DESC in - interface C. - - If the method cannot be resolved the return value is NULL. If - EXCEPT is true *exceptionptr is set, too. - -*******************************************************************************/ - -methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool throwexception) -{ - methodinfo *mi; - - if (!(c->flags & ACC_INTERFACE)) { - if (throwexception) - *exceptionptr = - new_exception(string_java_lang_IncompatibleClassChangeError); - - return NULL; - } - - mi = class_resolveinterfacemethod_intern(c, name, desc); - - if (mi != NULL) - return mi; - - /* try class java.lang.Object */ - - mi = class_findmethod(class_java_lang_Object, name, desc); - - if (mi != NULL) - return mi; - - if (throwexception) { -#if defined(ENABLE_JAVASE) - exceptions_throw_nosuchmethoderror(c, name, desc); -#else - exceptions_throw_virtualmachineerror(); -#endif - } - - return NULL; -} - - -/* class_findfield ************************************************************* - - Searches for field with specified name and type in a classinfo - structure. If no such field is found NULL is returned. - -*******************************************************************************/ - -fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) -{ - s4 i; - - for (i = 0; i < c->fieldscount; i++) - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) - return &(c->fields[i]); - - if (c->super.cls) - return class_findfield(c->super.cls, name, desc); - - return NULL; -} - - -/* class_findfield_approx ****************************************************** - - Searches in 'classinfo'-structure for a field with the specified - name. - -*******************************************************************************/ - -fieldinfo *class_findfield_by_name(classinfo *c, utf *name) -{ - s4 i; - - /* get field index */ - - i = class_findfield_index_by_name(c, name); - - /* field was not found, return */ - - if (i == -1) - return NULL; - - /* return field address */ - - return &(c->fields[i]); -} - - -s4 class_findfield_index_by_name(classinfo *c, utf *name) -{ - s4 i; - - for (i = 0; i < c->fieldscount; i++) { - /* compare field names */ - - if ((c->fields[i].name == name)) - return i; - } - - /* field was not found, raise exception */ - - *exceptionptr = new_exception(string_java_lang_NoSuchFieldException); - - return -1; -} - - -/****************** Function: class_resolvefield_int *************************** - - This is an internally used helper function. Do not use this directly. - - Tries to resolve a field having the given name and type. - If the field cannot be resolved, NULL is returned. - -*******************************************************************************/ - -static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) -{ - fieldinfo *fi; - s4 i; - - /* search for field in class c */ - - for (i = 0; i < c->fieldscount; i++) { - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { - return &(c->fields[i]); - } - } - - /* try superinterfaces recursively */ - - for (i = 0; i < c->interfacescount; i++) { - fi = class_resolvefield_int(c->interfaces[i].cls, name, desc); - if (fi) - return fi; - } - - /* try superclass */ - - if (c->super.cls) - return class_resolvefield_int(c->super.cls, name, desc); - - /* not found */ - - return NULL; -} - - -/********************* Function: class_resolvefield *************************** - - Resolves a reference from REFERER to a field with NAME and DESC in class C. - - If the field cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. - -*******************************************************************************/ - -fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool throwexception) -{ - fieldinfo *fi; - - fi = class_resolvefield_int(c, name, desc); - - if (!fi) { - if (throwexception) - *exceptionptr = - new_exception_utfmessage(string_java_lang_NoSuchFieldError, - name); - - return NULL; - } - - /* XXX check access rights */ - - return fi; -} - - -/* class_issubclass ************************************************************ - - Checks if sub is a descendant of super. - -*******************************************************************************/ - -bool class_issubclass(classinfo *sub, classinfo *super) -{ - for (;;) { - if (!sub) - return false; - - if (sub == super) - return true; - - sub = sub->super.cls; - } -} - - -/* class_printflags ************************************************************ - - Prints flags of a class. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_printflags(classinfo *c) -{ - if (c == NULL) { - printf("NULL"); - return; - } - - if (c->flags & ACC_PUBLIC) printf(" PUBLIC"); - if (c->flags & ACC_PRIVATE) printf(" PRIVATE"); - if (c->flags & ACC_PROTECTED) printf(" PROTECTED"); - if (c->flags & ACC_STATIC) printf(" STATIC"); - if (c->flags & ACC_FINAL) printf(" FINAL"); - if (c->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED"); - if (c->flags & ACC_VOLATILE) printf(" VOLATILE"); - if (c->flags & ACC_TRANSIENT) printf(" TRANSIENT"); - if (c->flags & ACC_NATIVE) printf(" NATIVE"); - if (c->flags & ACC_INTERFACE) printf(" INTERFACE"); - if (c->flags & ACC_ABSTRACT) printf(" ABSTRACT"); -} -#endif - - -/* class_print ***************************************************************** - - Prints classname plus flags. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_print(classinfo *c) -{ - if (c == NULL) { - printf("NULL"); - return; - } - - utf_display_printable_ascii(c->name); - class_printflags(c); -} -#endif - - -/* class_classref_print ******************************************************** - - Prints classname plus referer class. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_classref_print(constant_classref *cr) -{ - if (cr == NULL) { - printf("NULL"); - return; - } - - utf_display_printable_ascii(cr->name); - printf("(ref.by "); - if (cr->referer) - class_print(cr->referer); - else - printf("NULL"); - printf(")"); -} -#endif - - -/* class_println *************************************************************** - - Prints classname plus flags and new line. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_println(classinfo *c) -{ - class_print(c); - printf("\n"); -} -#endif - - -/* class_classref_println ****************************************************** - - Prints classname plus referer class and new line. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_classref_println(constant_classref *cr) -{ - class_classref_print(cr); - printf("\n"); -} -#endif - - -/* class_classref_or_classinfo_print ******************************************* - - Prints classname plus referer class. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_classref_or_classinfo_print(classref_or_classinfo c) -{ - if (c.any == NULL) { - printf("(classref_or_classinfo) NULL"); - return; - } - if (IS_CLASSREF(c)) - class_classref_print(c.ref); - else - class_print(c.cls); -} -#endif - - -/* class_classref_or_classinfo_println ***************************************** - - Prints classname plus referer class and a newline. - -*******************************************************************************/ - -void class_classref_or_classinfo_println(classref_or_classinfo c) -{ - class_classref_or_classinfo_println(c); - printf("\n"); -} - - -/* class_showconstantpool ****************************************************** - - Dump the constant pool of the given class to stdout. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_showconstantpool (classinfo *c) -{ - u4 i; - voidptr e; - - printf ("---- dump of constant pool ----\n"); - - for (i=0; icpcount; i++) { - printf ("#%d: ", (int) i); - - e = c -> cpinfos [i]; - if (e) { - - switch (c -> cptags [i]) { - case CONSTANT_Class: - printf ("Classreference -> "); - utf_display_printable_ascii ( ((constant_classref*)e) -> name ); - break; - case CONSTANT_Fieldref: - printf ("Fieldref -> "); - field_fieldref_print((constant_FMIref *) e); - break; - case CONSTANT_Methodref: - printf ("Methodref -> "); - method_methodref_print((constant_FMIref *) e); - break; - case CONSTANT_InterfaceMethodref: - printf ("InterfaceMethod -> "); - method_methodref_print((constant_FMIref *) e); - break; - case CONSTANT_String: - printf ("String -> "); - utf_display_printable_ascii (e); - break; - case CONSTANT_Integer: - printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); - break; - case CONSTANT_Float: - printf ("Float -> %f", ((constant_float*)e) -> value); - break; - case CONSTANT_Double: - printf ("Double -> %f", ((constant_double*)e) -> value); - break; - case CONSTANT_Long: - { - u8 v = ((constant_long*)e) -> value; -#if U8_AVAILABLE - printf ("Long -> %ld", (long int) v); -#else - printf ("Long -> HI: %ld, LO: %ld\n", - (long int) v.high, (long int) v.low); -#endif - } - break; - case CONSTANT_NameAndType: - { - constant_nameandtype *cnt = e; - printf ("NameAndType: "); - utf_display_printable_ascii (cnt->name); - printf (" "); - utf_display_printable_ascii (cnt->descriptor); - } - break; - case CONSTANT_Utf8: - printf ("Utf8 -> "); - utf_display_printable_ascii (e); - break; - default: - log_text("Invalid type of ConstantPool-Entry"); - assert(0); - } - } - - printf ("\n"); - } -} -#endif /* !defined(NDEBUG) */ - - -/* class_showmethods *********************************************************** - - Dump info about the fields and methods of the given class to stdout. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void class_showmethods (classinfo *c) -{ - s4 i; - - printf("--------- Fields and Methods ----------------\n"); - printf("Flags: "); - class_printflags(c); - printf("\n"); - - printf("This: "); - utf_display_printable_ascii(c->name); - printf("\n"); - - if (c->super.cls) { - printf("Super: "); - utf_display_printable_ascii(c->super.cls->name); - printf ("\n"); - } - - printf("Index: %d\n", c->index); - - printf("Interfaces:\n"); - for (i = 0; i < c->interfacescount; i++) { - printf(" "); - utf_display_printable_ascii(c->interfaces[i].cls->name); - printf (" (%d)\n", c->interfaces[i].cls->index); - } - - printf("Fields:\n"); - for (i = 0; i < c->fieldscount; i++) - field_println(&(c->fields[i])); - - printf("Methods:\n"); - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - - if (!(m->flags & ACC_STATIC)) - printf("vftblindex: %d ", m->vftblindex); - - method_println(m); - } - - printf ("Virtual function table:\n"); - for (i = 0; i < c->vftbl->vftbllength; i++) - printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i])); -} -#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: - */ diff --git a/src/vm/class.h b/src/vm/class.h deleted file mode 100644 index 323a080e7..000000000 --- a/src/vm/class.h +++ /dev/null @@ -1,373 +0,0 @@ -/* src/vm/class.h - class related functions header - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: class.h 6251 2006-12-27 23:15:56Z twisti $ - -*/ - - -#ifndef _CLASS_H -#define _CLASS_H - -/* forward typedefs ***********************************************************/ - -typedef struct classinfo classinfo; -typedef struct innerclassinfo innerclassinfo; -typedef struct extra_classref extra_classref; - - -#include "config.h" -#include "vm/types.h" - -#include "vm/global.h" /* define java_objectheader for j.l.C */ - -#include "native/jni.h" - -#if defined(ENABLE_JAVAME_CLDC1_1) -# include "native/include/java_lang_String.h" -#endif - -#include "native/include/java_lang_Class.h" - -#include "toolbox/list.h" - -#if defined(ENABLE_JAVASE) -# include "vm/annotation.h" -#endif - -#include "vm/field.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/method.h" -#include "vm/references.h" -#include "vm/utf8.h" - - -/* class state defines ********************************************************/ - -#define CLASS_LOADING 0x0001 -#define CLASS_LOADED 0x0002 -#define CLASS_LINKING 0x0004 -#define CLASS_LINKED 0x0008 -#define CLASS_INITIALIZING 0x0010 -#define CLASS_INITIALIZED 0x0020 -#define CLASS_ERROR 0x0040 - - -/* some macros ****************************************************************/ - -#define CLASS_IS_OR_ALMOST_INITIALIZED(c) \ - (((c)->state & CLASS_INITIALIZING) || ((c)->state & CLASS_INITIALIZED)) - - -/* classinfo ******************************************************************/ - -struct classinfo { /* class structure */ - java_lang_Class object; /* classinfos are also j.l.C objects */ - - s4 flags; /* ACC flags */ - utf *name; /* class name */ - - s4 cpcount; /* number of entries in constant pool */ - u1 *cptags; /* constant pool tags */ - voidptr *cpinfos; /* pointer to constant pool info structures */ - - s4 classrefcount; /* number of symbolic class references */ - constant_classref *classrefs; /* table of symbolic class references */ - extra_classref *extclassrefs; /* additional classrefs */ - s4 parseddescsize; /* size of the parsed descriptors block */ - u1 *parseddescs; /* parsed descriptors */ - - classref_or_classinfo super; /* super class */ - classinfo *sub; /* sub class pointer */ - classinfo *nextsub; /* pointer to next class in sub class list */ - - s4 interfacescount; /* number of interfaces */ - classref_or_classinfo *interfaces; /* superinterfaces */ - - s4 fieldscount; /* number of fields */ - fieldinfo *fields; /* field table */ - - s4 methodscount; /* number of methods */ - methodinfo *methods; /* method table */ - - listnode listnode; /* linkage */ - - s4 state; /* current class state */ - s4 index; /* hierarchy depth (classes) or index */ - /* (interfaces) */ - s4 instancesize; /* size of an instance of this class */ - - vftbl_t *vftbl; /* pointer to virtual function table */ - - methodinfo *finalizer; /* finalizer method */ - - u2 innerclasscount; /* number of inner classes */ - innerclassinfo *innerclass; - -#if defined(ENABLE_JAVASE) - classref_or_classinfo enclosingclass; /* enclosing class */ - constant_nameandtype *enclosingmethod; /* enclosing method */ -#endif - - utf *packagename; /* full name of the package */ - utf *sourcefile; /* SourceFile attribute */ -#if defined(ENABLE_JAVASE) - utf *signature; /* Signature attribute */ - s4 runtimevisibleannotationscount; - annotation_t *runtimevisibleannotations; -#endif - java_objectheader *classloader; /* NULL for bootstrap classloader */ -}; - - -/* innerclassinfo *************************************************************/ - -struct innerclassinfo { - classref_or_classinfo inner_class; /* inner class pointer */ - classref_or_classinfo outer_class; /* outer class pointer */ - utf *name; /* innerclass name */ - s4 flags; /* ACC flags */ -}; - - -/* extra_classref ************************************************************** - - for classrefs not occurring within descriptors - -*******************************************************************************/ - -struct extra_classref { - extra_classref *next; - constant_classref classref; -}; - - -/* global variables ***********************************************************/ - -extern list unlinkedclasses; /* this is only used for eager class loading */ - - -/* frequently used classes ****************************************************/ - -/* important system classes */ - -extern classinfo *class_java_lang_Object; -extern classinfo *class_java_lang_Class; -extern classinfo *class_java_lang_ClassLoader; -extern classinfo *class_java_lang_Cloneable; -extern classinfo *class_java_lang_SecurityManager; -extern classinfo *class_java_lang_String; -extern classinfo *class_java_lang_System; -extern classinfo *class_java_lang_Thread; -extern classinfo *class_java_lang_ThreadGroup; -extern classinfo *class_java_lang_VMSystem; -extern classinfo *class_java_lang_VMThread; -extern classinfo *class_java_io_Serializable; - - -/* system exception classes required in cacao */ - -extern classinfo *class_java_lang_Throwable; -extern classinfo *class_java_lang_Error; -extern classinfo *class_java_lang_LinkageError; -extern classinfo *class_java_lang_NoClassDefFoundError; -extern classinfo *class_java_lang_OutOfMemoryError; -extern classinfo *class_java_lang_VirtualMachineError; - -#if defined(ENABLE_JAVASE) -extern classinfo *class_java_lang_AbstractMethodError; -extern classinfo *class_java_lang_NoSuchMethodError; -#endif - -#if defined(WITH_CLASSPATH_GNU) -extern classinfo *class_java_lang_VMThrowable; -#endif - -extern classinfo *class_java_lang_Exception; -extern classinfo *class_java_lang_ClassCastException; -extern classinfo *class_java_lang_ClassNotFoundException; -extern classinfo *class_java_lang_IllegalArgumentException; -extern classinfo *class_java_lang_IllegalMonitorStateException; - - -#if defined(ENABLE_JAVASE) -extern classinfo *class_java_lang_Void; -#endif - -extern classinfo *class_java_lang_Boolean; -extern classinfo *class_java_lang_Byte; -extern classinfo *class_java_lang_Character; -extern classinfo *class_java_lang_Short; -extern classinfo *class_java_lang_Integer; -extern classinfo *class_java_lang_Long; -extern classinfo *class_java_lang_Float; -extern classinfo *class_java_lang_Double; - - -/* some runtime exception */ - -extern classinfo *class_java_lang_NullPointerException; - - -/* some classes which may be used more often */ - -#if defined(ENABLE_JAVASE) -extern classinfo *class_java_lang_StackTraceElement; -extern classinfo *class_java_lang_reflect_Constructor; -extern classinfo *class_java_lang_reflect_Field; -extern classinfo *class_java_lang_reflect_Method; -extern classinfo *class_java_security_PrivilegedAction; -extern classinfo *class_java_util_Vector; - -extern classinfo *arrayclass_java_lang_Object; -#endif - - -/* pseudo classes for the type checker ****************************************/ - -/* - * pseudo_class_Arraystub - * (extends Object implements Cloneable, java.io.Serializable) - * - * If two arrays of incompatible component types are merged, - * the resulting reference has no accessible components. - * The result does, however, implement the interfaces Cloneable - * and java.io.Serializable. This pseudo class is used internally - * to represent such results. (They are *not* considered arrays!) - * - * pseudo_class_Null - * - * This pseudo class is used internally to represent the - * null type. - * - * pseudo_class_New - * - * This pseudo class is used internally to represent the - * the 'uninitialized object' type. - */ - -extern classinfo *pseudo_class_Arraystub; -extern classinfo *pseudo_class_Null; -extern classinfo *pseudo_class_New; - - -/* function prototypes ********************************************************/ - -/* create a new classinfo struct */ -classinfo *class_create_classinfo(utf *u); - -/* postset's the header.vftbl */ -void class_postset_header_vftbl(void); - -/* set the package name after the name has been set */ -void class_set_packagename(classinfo *c); - -bool class_load_attributes(classbuffer *cb); - -/* retrieve constantpool element */ -voidptr class_getconstant(classinfo *class, u4 pos, u4 ctype); -voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype); - -/* frees all resources used by the class */ -void class_free(classinfo *); - -/* return an array class with the given component class */ -classinfo *class_array_of(classinfo *component,bool link); - -/* return an array class with the given dimension and element class */ -classinfo *class_multiarray_of(s4 dim, classinfo *element,bool link); - -/* return a classref for the given class name */ -/* (does a linear search!) */ -constant_classref *class_lookup_classref(classinfo *cls,utf *name); - -/* return a classref for the given class name */ -/* (does a linear search!) */ -constant_classref *class_get_classref(classinfo *cls,utf *name); - -/* return a classref to the class itself */ -/* (does a linear search!) */ -constant_classref *class_get_self_classref(classinfo *cls); - -/* return a classref for an array with the given dimension of with the */ -/* given component type */ -constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref); - -/* return a classref for the component type of the given array type */ -constant_classref *class_get_classref_component_of(constant_classref *ref); - -/* get a class' field by name and descriptor */ -fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc); - -/* search 'classinfo'-structure for a field with the specified name */ -fieldinfo *class_findfield_by_name(classinfo *c, utf *name); -s4 class_findfield_index_by_name(classinfo *c, utf *name); - -/* search class for a field */ -fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, classinfo *referer, bool throwexception); - -/* search for a method with a specified name and descriptor */ -methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc); -methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *dest); -methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); -methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); - -bool class_issubclass(classinfo *sub, classinfo *super); - -/* some debugging functions */ - -#if !defined(NDEBUG) -void class_printflags(classinfo *c); -void class_print(classinfo *c); -void class_println(classinfo *c); -void class_classref_print(constant_classref *cr); -void class_classref_println(constant_classref *cr); -void class_classref_or_classinfo_print(classref_or_classinfo c); -void class_classref_or_classinfo_println(classref_or_classinfo c); -#endif - -/* debug purposes */ -void class_showmethods(classinfo *c); -void class_showconstantpool(classinfo *c); - -#endif /* _CLASS_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: - */ diff --git a/src/vm/classcache.c b/src/vm/classcache.c deleted file mode 100644 index ca3334345..000000000 --- a/src/vm/classcache.c +++ /dev/null @@ -1,1587 +0,0 @@ -/* src/vm/classcache.c - loaded class cache and loading constraints - - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - Christian Thalinger - - $Id: classcache.c 6286 2007-01-10 10:03:38Z twisti $ - -*/ - - -#include "config.h" -#include "vm/types.h" - -#include - -#include "mm/memory.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#endif - -#include "vm/classcache.h" -#include "vm/exceptions.h" -#include "vm/hashtable.h" -#include "vm/stringlocal.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() LOCK_MONITOR_ENTER(lock_hashtable_classcache) -# define CLASSCACHE_UNLOCK() LOCK_MONITOR_EXIT(lock_hashtable_classcache) -#else -# define CLASSCACHE_LOCK() -# define CLASSCACHE_UNLOCK() -#endif - -/*============================================================================*/ -/* GLOBAL VARIABLES */ -/*============================================================================*/ - -hashtable hashtable_classcache; - -#if defined(ENABLE_THREADS) -static java_objectheader *lock_hashtable_classcache; -#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) -{ - /* create the hashtable */ - - hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE); - -#if defined(ENABLE_THREADS) - /* create utf hashtable lock object */ - - lock_hashtable_classcache = NEW(java_objectheader); - - lock_init_object_lock(lock_hashtable_classcache); -#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 * 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_text(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 *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 *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 *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 *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_text(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 - dolog("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 */ - *exceptionptr = exceptions_new_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(stderr,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_text(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 - dolog("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(stderr,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 * 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, voidptr, 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 * a, - classloader * b, - utf * classname) -{ - classcache_name_entry *en; - classcache_class_entry *clsenA; - classcache_class_entry *clsenB; - - assert(classname); - -#ifdef CLASSCACHE_VERBOSE - fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b); - utf_fprint_printable_ascii_classname(stderr, classname); - fprintf(stderr, ")\n"); -#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 */ - *exceptionptr = exceptions_new_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 * a, - classloader * 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(); - - fprintf(file, "\n=== [loaded class cache] =====================================\n\n"); - fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size); - fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries); - fprintf(file, "\n"); - - 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) { - fprintf(file, " loaded %p\n", (void *) clsen->classobj); - } - else { - fprintf(file, " unresolved\n"); - } - fprintf(file, " loaders:"); - for (lden = clsen->loaders; lden; lden = lden->next) { - fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader); - } - fprintf(file, "\n constraints:"); - for (lden = clsen->constraints; lden; lden = lden->next) { - fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader); - } - fprintf(file, "\n"); - } - } - - 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: - */ diff --git a/src/vm/classcache.h b/src/vm/classcache.h deleted file mode 100644 index 9457aa71b..000000000 --- a/src/vm/classcache.h +++ /dev/null @@ -1,180 +0,0 @@ -/* src/vm/classcache.h - loaded class cache and loading constraints - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: Christian Thalinger - - $Id: classcache.h 6209 2006-12-16 21:14:23Z edwin $ - -*/ - - -#ifndef _CLASSCACHE_H -#define _CLASSCACHE_H - -#include "config.h" -#include "vm/types.h" - -#include /* for FILE */ - -#if defined(ENABLE_JVMTI) -# include "native/jni.h" -#endif - -#include "vm/hashtable.h" -#include "vm/references.h" - - -/* 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; - -typedef java_objectheader classloader; - -/* 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 *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 *initloader,utf *classname); -classinfo * classcache_lookup_defined(classloader *defloader,utf *classname); -classinfo * classcache_lookup_defined_or_initiated(classloader *loader,utf *classname); - -bool classcache_store_unique(classinfo *cls); -classinfo * classcache_store(classloader *initloader,classinfo *cls,bool mayfree); -classinfo * classcache_store_defined(classinfo *cls); - -#if defined(ENABLE_VERIFIER) -bool classcache_add_constraint(classloader *a,classloader *b,utf *classname); -bool classcache_add_constraints_for_params(classloader *a,classloader *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 - -#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: - */ - diff --git a/src/vm/descriptor.c b/src/vm/descriptor.c deleted file mode 100644 index c5e512d89..000000000 --- a/src/vm/descriptor.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* src/vm/descriptor.c - checking and parsing of field / method descriptors - - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - Christian Thalinger - Christian Ullrich - - $Id: descriptor.c 6286 2007-01-10 10:03:38Z twisti $ - -*/ - - -#include "config.h" - -#include - -#include "vm/types.h" - -#include "md-abi.h" - -#include "mm/memory.h" -#include "vm/descriptor.h" -#include "vm/exceptions.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/stringlocal.h" - - -/* constants (private to descriptor.c) ****************************************/ - -/* initial number of entries for the classrefhash of a descriptor_pool */ -/* (currently the hash is never grown!) */ -#define CLASSREFHASH_INIT_SIZE 64 - -/* initial number of entries for the descriptorhash of a descriptor_pool */ -/* (currently the hash is never grown!) */ -#define DESCRIPTORHASH_INIT_SIZE 128 - -/* data structures (private to descriptor.c) **********************************/ - -typedef struct classref_hash_entry classref_hash_entry; -typedef struct descriptor_hash_entry descriptor_hash_entry; - -/* entry struct for the classrefhash of descriptor_pool */ -struct classref_hash_entry { - classref_hash_entry *hashlink; /* for hash chaining */ - utf *name; /* name of the class refered to */ - u2 index; /* index into classref table */ -}; - -/* entry struct for the descriptorhash of descriptor_pool */ -struct descriptor_hash_entry { - descriptor_hash_entry *hashlink; - utf *desc; - parseddesc parseddesc; - s2 paramslots; /* number of params, LONG/DOUBLE counted as 2 */ -}; - - -/****************************************************************************/ -/* MACROS FOR DESCRIPTOR PARSING (private to descriptor.c) */ -/****************************************************************************/ - -/* SKIP_FIELDDESCRIPTOR: - * utf_ptr must point to the first character of a field descriptor. - * After the macro call utf_ptr points to the first character after - * the field descriptor. - * - * CAUTION: This macro does not check for an unexpected end of the - * descriptor. Better use SKIP_FIELDDESCRIPTOR_SAFE. - */ -#define SKIP_FIELDDESCRIPTOR(utf_ptr) \ - do { while (*(utf_ptr)=='[') (utf_ptr)++; \ - if (*(utf_ptr)++=='L') \ - while(*(utf_ptr)++ != ';') /* skip */; } while(0) - -/* SKIP_FIELDDESCRIPTOR_SAFE: - * utf_ptr must point to the first character of a field descriptor. - * After the macro call utf_ptr points to the first character after - * the field descriptor. - * - * Input: - * utf_ptr....points to first char of descriptor - * end_ptr....points to first char after the end of the string - * errorflag..must be initialized (to false) by the caller! - * Output: - * utf_ptr....points to first char after the descriptor - * errorflag..set to true if the string ended unexpectedly - */ -#define SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,errorflag) \ - do { while ((utf_ptr) != (end_ptr) && *(utf_ptr)=='[') (utf_ptr)++; \ - if ((utf_ptr) == (end_ptr)) \ - (errorflag) = true; \ - else \ - if (*(utf_ptr)++=='L') { \ - while((utf_ptr) != (end_ptr) && *(utf_ptr)++ != ';') \ - /* skip */; \ - if ((utf_ptr)[-1] != ';') \ - (errorflag) = true; }} while(0) - - -/****************************************************************************/ -/* DEBUG HELPERS */ -/****************************************************************************/ - -/*#define DESCRIPTOR_VERBOSE*/ - -/****************************************************************************/ -/* FUNCTIONS */ -/****************************************************************************/ - -/* descriptor_to_basic_type **************************************************** - - Return the basic type to use for a value with this descriptor. - - IN: - utf..............descriptor utf string - - OUT: - A TYPE_* constant. - - PRECONDITIONS: - This function assumes that the descriptor has passed - descriptor_pool_add checks and that it does not start with '('. - -*******************************************************************************/ - -u2 descriptor_to_basic_type(utf *descriptor) -{ - assert(descriptor->blength >= 1); - - switch (descriptor->text[0]) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': return TYPE_INT; - case 'D': return TYPE_DBL; - case 'F': return TYPE_FLT; - case 'J': return TYPE_LNG; - case 'L': - case '[': return TYPE_ADR; - } - - assert(0); - - return 0; /* keep the compiler happy */ -} - -/* descriptor_typesize**** **************************************************** - - Return the size in bytes needed for the given type. - - IN: - td..............typedesc describing the type - - OUT: - The number of bytes - -*******************************************************************************/ - -u2 descriptor_typesize(typedesc *td) -{ - assert(td); - - switch (td->type) { - case TYPE_INT: return 4; - case TYPE_LNG: return 8; - case TYPE_FLT: return 4; - case TYPE_DBL: return 8; - case TYPE_ADR: return sizeof(voidptr); - } - - assert(0); - - return 0; /* keep the compiler happy */ -} - -/* name_from_descriptor ******************************************************** - - Return the class name indicated by the given descriptor - (Internally used helper function) - - IN: - c................class containing the descriptor - utf_ptr..........first character of descriptor - end_ptr..........first character after the end of the string - mode.............a combination (binary or) of the following flags: - - (Flags marked with * are the default settings.) - - How to handle "V" descriptors: - - * DESCRIPTOR_VOID.....handle it like other primitive types - DESCRIPTOR_NOVOID...treat it as an error - - How to deal with extra characters after the end of the - descriptor: - - * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists) - DESCRIPTOR_CHECKEND.....treat them as an error - - OUT: - *next............if non-NULL, *next is set to the first character after - the descriptor. (Undefined if an error occurs.) - *name............set to the utf name of the class - - RETURN VALUE: - true.............descriptor parsed successfully - false............an exception has been thrown - -*******************************************************************************/ - -#define DESCRIPTOR_VOID 0 /* default */ -#define DESCRIPTOR_NOVOID 0x0040 -#define DESCRIPTOR_NOCHECKEND 0 /* default */ -#define DESCRIPTOR_CHECKEND 0x1000 - -static bool -name_from_descriptor(classinfo *c, - char *utf_ptr, char *end_ptr, - char **next, int mode, utf **name) -{ - char *start = utf_ptr; - bool error = false; - - assert(c); - assert(utf_ptr); - assert(end_ptr); - assert(name); - - *name = NULL; - SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); - - if (mode & DESCRIPTOR_CHECKEND) - error |= (utf_ptr != end_ptr); - - if (!error) { - if (next) *next = utf_ptr; - - switch (*start) { - case 'V': - if (mode & DESCRIPTOR_NOVOID) - break; - /* FALLTHROUGH! */ - case 'I': - case 'J': - case 'F': - case 'D': - case 'B': - case 'C': - case 'S': - case 'Z': - return true; - - case 'L': - start++; - utf_ptr--; - /* FALLTHROUGH! */ - case '[': - *name = utf_new(start, utf_ptr - start); - return true; - } - } - - *exceptionptr = new_classformaterror(c,"invalid descriptor"); - return false; -} - - -/* descriptor_to_typedesc ****************************************************** - - Parse the given type descriptor and fill a typedesc struct - (Internally used helper function) - - IN: - pool.............the descriptor pool - utf_ptr..........points to first character of type descriptor - end_pos..........points after last character of the whole descriptor - - OUT: - *next............set to next character after type descriptor - *d...............filled with parsed information - - RETURN VALUE: - true.............parsing succeeded - false............an exception has been thrown - -*******************************************************************************/ - -static bool -descriptor_to_typedesc(descriptor_pool *pool, char *utf_ptr, char *end_pos, - char **next, typedesc *td) -{ - utf *name; - - if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name)) - return false; - - if (name) { - /* a reference type */ - td->type = TYPE_ADR; - td->decltype = TYPE_ADR; - td->arraydim = 0; - for (utf_ptr = name->text; *utf_ptr == '['; ++utf_ptr) - td->arraydim++; - td->classref = descriptor_pool_lookup_classref(pool, name); - - } else { - /* a primitive type */ - switch (*utf_ptr) { - case 'B': - td->decltype = PRIMITIVETYPE_BYTE; - td->type = TYPE_INT; - break; - case 'C': - td->decltype = PRIMITIVETYPE_CHAR; - td->type = TYPE_INT; - break; - case 'S': - td->decltype = PRIMITIVETYPE_SHORT; - td->type = TYPE_INT; - break; - case 'Z': - td->decltype = PRIMITIVETYPE_BOOLEAN; - td->type = TYPE_INT; - break; - case 'I': - td->decltype = PRIMITIVETYPE_INT; - td->type = TYPE_INT; - break; - case 'D': - td->decltype = PRIMITIVETYPE_DOUBLE; - td->type = TYPE_DBL; - break; - case 'F': - td->decltype = PRIMITIVETYPE_FLOAT; - td->type = TYPE_FLT; - break; - case 'J': - td->decltype = PRIMITIVETYPE_LONG; - td->type = TYPE_LNG; - break; - case 'V': - td->decltype = PRIMITIVETYPE_VOID; - td->type = TYPE_VOID; - break; - default: - assert(false); - } - - td->arraydim = 0; - td->classref = NULL; - } - - return true; -} - - -/* descriptor_pool_new ********************************************************* - - Allocate a new descriptor_pool - - IN: - referer..........class for which to create the pool - - RETURN VALUE: - a pointer to the new descriptor_pool - -*******************************************************************************/ - -descriptor_pool * -descriptor_pool_new(classinfo *referer) -{ - descriptor_pool *pool; - u4 hashsize; - u4 slot; - - pool = DNEW(descriptor_pool); - assert(pool); - - pool->referer = referer; - pool->fieldcount = 0; - pool->methodcount = 0; - pool->paramcount = 0; - pool->descriptorsize = 0; - pool->descriptors = NULL; - pool->descriptors_next = NULL; - pool->classrefs = NULL; - pool->descriptor_kind = NULL; - pool->descriptor_kind_next = NULL; - - hashsize = CLASSREFHASH_INIT_SIZE; - pool->classrefhash.size = hashsize; - pool->classrefhash.entries = 0; - pool->classrefhash.ptr = DMNEW(voidptr,hashsize); - for (slot=0; slotclassrefhash.ptr[slot] = NULL; - - hashsize = DESCRIPTORHASH_INIT_SIZE; - pool->descriptorhash.size = hashsize; - pool->descriptorhash.entries = 0; - pool->descriptorhash.ptr = DMNEW(voidptr,hashsize); - for (slot=0; slotdescriptorhash.ptr[slot] = NULL; - - return pool; -} - - -/* descriptor_pool_add_class *************************************************** - - Add the given class reference to the pool - - IN: - pool.............the descriptor_pool - name.............the class reference to add - - RETURN VALUE: - true.............reference has been added - false............an exception has been thrown - -*******************************************************************************/ - -bool -descriptor_pool_add_class(descriptor_pool *pool, utf *name) -{ - u4 key,slot; - classref_hash_entry *c; - - assert(pool); - assert(name); - -#ifdef DESCRIPTOR_VERBOSE - fprintf(stderr,"descriptor_pool_add_class(%p,",(void*)pool); - utf_fprint_printable_ascii(stderr,name);fprintf(stderr,")\n"); -#endif - - /* find a place in the hashtable */ - - key = utf_hashkey(name->text, name->blength); - slot = key & (pool->classrefhash.size - 1); - c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; - - while (c) { - if (c->name == name) - return true; /* already stored */ - c = c->hashlink; - } - - /* check if the name is a valid classname */ - - if (!is_valid_name(name->text,UTF_END(name))) { - *exceptionptr = new_classformaterror(pool->referer, - "Invalid class name"); - return false; /* exception */ - } - - /* XXX check maximum array dimension */ - - c = DNEW(classref_hash_entry); - c->name = name; - c->index = pool->classrefhash.entries++; - c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot]; - pool->classrefhash.ptr[slot] = c; - - return true; -} - - -/* descriptor_pool_add ********************************************************* - - Check the given descriptor and add it to the pool - - IN: - pool.............the descriptor_pool - desc.............the descriptor to add. Maybe a field or method desc. - - OUT: - *paramslots......if non-NULL, set to the number of parameters. - LONG and DOUBLE are counted twice - - RETURN VALUE: - true.............descriptor has been added - false............an exception has been thrown - -*******************************************************************************/ - -bool -descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots) -{ - u4 key,slot; - descriptor_hash_entry *d; - char *utf_ptr; - char *end_pos; - utf *name; - s4 argcount = 0; - -#ifdef DESCRIPTOR_VERBOSE - fprintf(stderr,"descriptor_pool_add(%p,",(void*)pool); - utf_fprint_printable_ascii(stderr,desc);fprintf(stderr,")\n"); -#endif - - assert(pool); - assert(desc); - - /* find a place in the hashtable */ - - key = utf_hashkey(desc->text, desc->blength); - slot = key & (pool->descriptorhash.size - 1); - d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - - /* Save all method descriptors in the hashtable, since the parsed */ - /* descriptor may vary between differenf methods (static vs. non-static). */ - - utf_ptr = desc->text; - - if (*utf_ptr != '(') { - while (d) { - if (d->desc == desc) { - if (paramslots) - *paramslots = d->paramslots; - return true; /* already stored */ - } - d = d->hashlink; - } - } - - /* add the descriptor to the pool */ - - d = DNEW(descriptor_hash_entry); - d->desc = desc; - d->parseddesc.any = NULL; - d->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - pool->descriptorhash.ptr[slot] = d; - - /* now check the descriptor */ - - end_pos = UTF_END(desc); - - if (*utf_ptr == '(') { - /* a method descriptor */ - - pool->methodcount++; - utf_ptr++; - - /* check arguments */ - - while ((utf_ptr != end_pos) && (*utf_ptr != ')')) { - pool->paramcount++; - - /* We cannot count the `this' argument here because - * we don't know if the method is static. */ - - if (*utf_ptr == 'J' || *utf_ptr == 'D') - argcount += 2; - else - argcount++; - - if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr, - DESCRIPTOR_NOVOID, &name)) - return false; - - if (name) - if (!descriptor_pool_add_class(pool, name)) - return false; - } - - if (utf_ptr == end_pos) { - *exceptionptr = new_classformaterror(pool->referer,"Missing ')' in method descriptor"); - return false; - } - - utf_ptr++; /* skip ')' */ - - if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, - DESCRIPTOR_CHECKEND, &name)) - return false; - - if (name) - if (!descriptor_pool_add_class(pool,name)) - return false; - - if (argcount > 255) { - *exceptionptr = - new_classformaterror(pool->referer,"Too many arguments in signature"); - return false; - } - - } else { - /* a field descriptor */ - - pool->fieldcount++; - - if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, - DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND, - &name)) - return false; - - if (name) - if (!descriptor_pool_add_class(pool,name)) - return false; - } - - d->paramslots = argcount; - - if (paramslots) - *paramslots = argcount; - - return true; -} - - -/* descriptor_pool_create_classrefs ******************************************** - - Create a table containing all the classrefs which were added to the pool - - IN: - pool.............the descriptor_pool - - OUT: - *count...........if count is non-NULL, this is set to the number - of classrefs in the table - - RETURN VALUE: - a pointer to the constant_classref table - -*******************************************************************************/ - -constant_classref * -descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count) -{ - u4 nclasses; - u4 slot; - classref_hash_entry *c; - constant_classref *ref; - - assert(pool); - - nclasses = pool->classrefhash.entries; - pool->classrefs = MNEW(constant_classref,nclasses); - - /* fill the constant_classref structs */ - - for (slot = 0; slot < pool->classrefhash.size; ++slot) { - c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; - while (c) { - ref = pool->classrefs + c->index; - CLASSREF_INIT(*ref, pool->referer, c->name); - c = c->hashlink; - } - } - - if (count) - *count = nclasses; - - return pool->classrefs; -} - - -/* descriptor_pool_lookup_classref ********************************************* - - Return the constant_classref for the given class name - - IN: - pool.............the descriptor_pool - classname........name of the class to look up - - RETURN VALUE: - a pointer to the constant_classref, or - NULL if an exception has been thrown - -*******************************************************************************/ - -constant_classref * -descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname) -{ - u4 key,slot; - classref_hash_entry *c; - - assert(pool); - assert(pool->classrefs); - assert(classname); - - key = utf_hashkey(classname->text, classname->blength); - slot = key & (pool->classrefhash.size - 1); - c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; - - while (c) { - if (c->name == classname) - return pool->classrefs + c->index; - c = c->hashlink; - } - - exceptions_throw_internalerror("Class reference not found in descriptor pool"); - return NULL; -} - - -/* descriptor_pool_alloc_parsed_descriptors ************************************ - - Allocate space for the parsed descriptors - - IN: - pool.............the descriptor_pool - - NOTE: - This function must be called after all descriptors have been added - with descriptor_pool_add. - -*******************************************************************************/ - -void -descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool) -{ - u4 size; - - assert(pool); - - /* TWISTI: paramcount + 1: we don't know if the method is static or */ - /* not, i have no better solution yet. */ - - size = - pool->fieldcount * sizeof(typedesc) + - pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) + - pool->paramcount * sizeof(typedesc) + - pool->methodcount * sizeof(typedesc); /* possible `this' pointer */ - - pool->descriptorsize = size; - if (size) { - pool->descriptors = MNEW(u1, size); - pool->descriptors_next = pool->descriptors; - } - - size = pool->fieldcount + pool->methodcount; - if (size) { - pool->descriptor_kind = DMNEW(u1, size); - pool->descriptor_kind_next = pool->descriptor_kind; - } -} - - -/* descriptor_pool_parse_field_descriptor ************************************** - - Parse the given field descriptor - - IN: - pool.............the descriptor_pool - desc.............the field descriptor - - RETURN VALUE: - a pointer to the parsed field descriptor, or - NULL if an exception has been thrown - - NOTE: - descriptor_pool_alloc_parsed_descriptors must be called (once) - before this function is used. - -*******************************************************************************/ - -typedesc * -descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc) -{ - u4 key,slot; - descriptor_hash_entry *d; - typedesc *td; - - assert(pool); - assert(pool->descriptors); - assert(pool->descriptors_next); - - /* lookup the descriptor in the hashtable */ - - key = utf_hashkey(desc->text, desc->blength); - slot = key & (pool->descriptorhash.size - 1); - d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - - while (d) { - if (d->desc == desc) { - /* found */ - if (d->parseddesc.fd) - return d->parseddesc.fd; - break; - } - d = d->hashlink; - } - - assert(d); - - if (desc->text[0] == '(') { - *exceptionptr = new_classformaterror(pool->referer, - "Method descriptor used in field reference"); - return NULL; - } - - td = (typedesc *) pool->descriptors_next; - pool->descriptors_next += sizeof(typedesc); - - if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td)) - return NULL; - - *(pool->descriptor_kind_next++) = 'f'; - - d->parseddesc.fd = td; - - return td; -} - - -/* descriptor_pool_parse_method_descriptor ************************************* - - Parse the given method descriptor - - IN: - pool.............the descriptor_pool - desc.............the method descriptor - mflags...........the method flags - thisclass........classref to the class containing the method. - This is ignored if mflags contains ACC_STATIC. - The classref is stored for inserting the 'this' argument. - - RETURN VALUE: - a pointer to the parsed method descriptor, or - NULL if an exception has been thrown - - NOTE: - descriptor_pool_alloc_parsed_descriptors must be called - (once) before this function is used. - -*******************************************************************************/ - -methoddesc * -descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, - s4 mflags,constant_classref *thisclass) -{ - u4 key, slot; - descriptor_hash_entry *d; - methoddesc *md; - typedesc *td; - char *utf_ptr; - char *end_pos; - s2 paramcount = 0; - s2 paramslots = 0; - -#ifdef DESCRIPTOR_VERBOSE - fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,", - (void*)pool,(int)mflags,(void*)thisclass); - utf_fprint_printable_ascii(stderr,desc); fprintf(stderr,")\n"); -#endif - - assert(pool); - assert(pool->descriptors); - assert(pool->descriptors_next); - - /* check that it is a method descriptor */ - - if (desc->text[0] != '(') { - *exceptionptr = new_classformaterror(pool->referer, - "Field descriptor used in method reference"); - return NULL; - } - - /* lookup the descriptor in the hashtable */ - - key = utf_hashkey(desc->text, desc->blength); - slot = key & (pool->descriptorhash.size - 1); - d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - - /* find an un-parsed descriptor */ - - while (d) { - if (d->desc == desc) - if (!d->parseddesc.md) - break; - d = d->hashlink; - } - - assert(d); - - md = (methoddesc *) pool->descriptors_next; - pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc); - - utf_ptr = desc->text + 1; /* skip '(' */ - end_pos = UTF_END(desc); - - td = md->paramtypes; - - /* count the `this' pointer */ - - if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) { - td->type = TYPE_ADR; - td->decltype = TYPE_ADR; - td->arraydim = 0; - td->classref = thisclass; - - td++; - pool->descriptors_next += sizeof(typedesc); - paramcount++; - paramslots++; - } - - while (*utf_ptr != ')') { - /* parse a parameter type */ - - if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td)) - return NULL; - - if (IS_2_WORD_TYPE(td->type)) - paramslots++; - - td++; - pool->descriptors_next += sizeof(typedesc); - paramcount++; - paramslots++; - } - utf_ptr++; /* skip ')' */ - - /* Skip possible `this' pointer in paramtypes array to allow a possible */ - /* memory move later in parse. */ - /* We store the thisclass reference, so we can later correctly fill in */ - /* the parameter slot of the 'this' argument. */ - - if (mflags == ACC_UNDEF) { - td->classref = thisclass; - td++; - pool->descriptors_next += sizeof(typedesc); - } - - /* parse return type */ - - if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL, - &(md->returntype))) - return NULL; - - md->paramcount = paramcount; - md->paramslots = paramslots; - - /* If m != ACC_UNDEF we parse a real loaded method, so do param prealloc. */ - /* Otherwise we do this in stack analysis. */ - - if (mflags != ACC_UNDEF) { - if (md->paramcount > 0) { - /* allocate memory for params */ - - md->params = MNEW(paramdesc, md->paramcount); - } - else { - md->params = METHODDESC_NOPARAMS; - } - - /* fill the paramdesc */ - /* md_param_alloc has to be called if md->paramcount == 0, - too, so it can make the reservation for the Linkage Area, - Return Register... */ - -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (!opt_intrp) -# endif - md_param_alloc(md); -#endif - - } else { - /* params will be allocated later by - descriptor_params_from_paramtypes if necessary */ - - md->params = NULL; - } - - *(pool->descriptor_kind_next++) = 'm'; - - d->parseddesc.md = md; - - return md; -} - -/* descriptor_params_from_paramtypes ******************************************* - - Create the paramdescs for a method descriptor. This function is called - when we know whether the method is static or not. This function may only - be called once for each methoddesc, and only if md->params == NULL. - - IN: - md...............the parsed method descriptor - md->params MUST be NULL. - mflags...........the ACC_* access flags of the method. Only the - ACC_STATIC bit is checked. - The value ACC_UNDEF is NOT allowed. - - RETURN VALUE: - true.............the paramdescs were created successfully - false............an exception has been thrown - - POSTCONDITION: - md->parms != NULL - -*******************************************************************************/ - -bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags) -{ - typedesc *td; - - assert(md); - assert(md->params == NULL); - assert(mflags != ACC_UNDEF); - - td = md->paramtypes; - - /* check for `this' pointer */ - - if (!(mflags & ACC_STATIC)) { - constant_classref *thisclass; - - /* fetch class reference from reserved param slot */ - thisclass = td[md->paramcount].classref; - assert(thisclass); - - if (md->paramcount > 0) { - /* shift param types by 1 argument */ - MMOVE(td + 1, td, typedesc, md->paramcount); - } - - /* fill in first argument `this' */ - - td->type = TYPE_ADR; - td->decltype = TYPE_ADR; - td->arraydim = 0; - td->classref = thisclass; - - md->paramcount++; - md->paramslots++; - } - - /* if the method has params, process them */ - - if (md->paramcount > 0) { - /* allocate memory for params */ - - md->params = MNEW(paramdesc, md->paramcount); - - } else { - md->params = METHODDESC_NOPARAMS; - } - - /* fill the paramdesc */ - /* md_param_alloc has to be called if md->paramcount == 0, too, so - it can make the reservation for the Linkage Area, Return - Register.. */ - -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (!opt_intrp) -# endif - md_param_alloc(md); -#endif - - return true; -} - - -/* descriptor_pool_get_parsed_descriptors ************************************** - - Return a pointer to the block of parsed descriptors - - IN: - pool.............the descriptor_pool - - OUT: - *size............if size is non-NULL, this is set to the size of the - parsed descriptor block (in u1) - - RETURN VALUE: - a pointer to the block of parsed descriptors - - NOTE: - descriptor_pool_alloc_parsed_descriptors must be called (once) - before this function is used. - -*******************************************************************************/ - -void * -descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size) -{ - assert(pool); - assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); - - if (size) - *size = pool->descriptorsize; - - return pool->descriptors; -} - - -/* descriptor_pool_get_sizes *************************************************** - - Get the sizes of the class reference table and the parsed descriptors - - IN: - pool.............the descriptor_pool - - OUT: - *classrefsize....set to size of the class reference table - *descsize........set to size of the parsed descriptors - - NOTE: - This function may only be called after both - descriptor_pool_create_classrefs, and - descriptor_pool_alloc_parsed_descriptors - have been called. - -*******************************************************************************/ - -void -descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize) -{ - assert(pool); - assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); - assert(pool->classrefs); - assert(classrefsize); - assert(descsize); - - *classrefsize = pool->classrefhash.entries * sizeof(constant_classref); - *descsize = pool->descriptorsize; -} - - -/****************************************************************************/ -/* DEBUG HELPERS */ -/****************************************************************************/ - -#ifndef NDEBUG -/* descriptor_debug_print_typedesc ********************************************* - - Print the given typedesc to the given stream - - IN: - file.............stream to print to - d................the parsed descriptor - -*******************************************************************************/ - -void -descriptor_debug_print_typedesc(FILE *file,typedesc *d) -{ - int ch; - - if (!d) { - fprintf(file,"(typedesc *)NULL"); - return; - } - - if (d->type == TYPE_ADR) { - if (d->classref) - utf_fprint_printable_ascii(file,d->classref->name); - else - fprintf(file,""); - } - else { - switch (d->decltype) { - case PRIMITIVETYPE_INT : ch='I'; break; - case PRIMITIVETYPE_CHAR : ch='C'; break; - case PRIMITIVETYPE_BYTE : ch='B'; break; - case PRIMITIVETYPE_SHORT : ch='S'; break; - case PRIMITIVETYPE_BOOLEAN: ch='Z'; break; - case PRIMITIVETYPE_LONG : ch='J'; break; - case PRIMITIVETYPE_FLOAT : ch='F'; break; - case PRIMITIVETYPE_DOUBLE : ch='D'; break; - case PRIMITIVETYPE_VOID : ch='V'; break; - default : ch='!'; - } - fputc(ch,file); - } - if (d->arraydim) - fprintf(file,"[%d]",d->arraydim); -} - -/* descriptor_debug_print_paramdesc ******************************************** - - Print the given paramdesc to the given stream - - IN: - file.............stream to print to - d................the parameter descriptor - -*******************************************************************************/ - -void -descriptor_debug_print_paramdesc(FILE *file,paramdesc *d) -{ - if (!d) { - fprintf(file,"(paramdesc *)NULL"); - return; - } - - if (d->inmemory) { - fprintf(file,"",d->regoff); - } - else { - fprintf(file,"",d->regoff); - } -} - -/* descriptor_debug_print_methoddesc ******************************************* - - Print the given methoddesc to the given stream - - IN: - file.............stream to print to - d................the parsed descriptor - -*******************************************************************************/ - -void -descriptor_debug_print_methoddesc(FILE *file,methoddesc *d) -{ - int i; - - if (!d) { - fprintf(file,"(methoddesc *)NULL"); - return; - } - - fputc('(',file); - for (i=0; iparamcount; ++i) { - if (i) - fputc(',',file); - descriptor_debug_print_typedesc(file,d->paramtypes + i); - if (d->params) { - descriptor_debug_print_paramdesc(file,d->params + i); - } - } - if (d->params == METHODDESC_NOPARAMS) - fputs("",file); - fputc(')',file); - descriptor_debug_print_typedesc(file,&(d->returntype)); -} - -/* descriptor_pool_debug_dump ************************************************** - - Print the state of the descriptor_pool to the given stream - - IN: - pool.............the descriptor_pool - file.............stream to print to - -*******************************************************************************/ - -void -descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) -{ - u4 slot; - u1 *pos; - u1 *kind; - u4 size; - - fprintf(file,"======[descriptor_pool for "); - utf_fprint_printable_ascii(file,pool->referer->name); - fprintf(file,"]======\n"); - - fprintf(file,"fieldcount: %d\n",pool->fieldcount); - fprintf(file,"methodcount: %d\n",pool->methodcount); - fprintf(file,"paramcount: %d\n",pool->paramcount); - fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries); - fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize); - fprintf(file,"classrefsize: %d bytes\n", - (int)(pool->classrefhash.entries * sizeof(constant_classref))); - - fprintf(file,"class references:\n"); - for (slot=0; slotclassrefhash.size; ++slot) { - classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; - while (c) { - fprintf(file," %4d: ",c->index); - utf_fprint_printable_ascii(file,c->name); - fprintf(file,"\n"); - c = c->hashlink; - } - } - - fprintf(file,"hashed descriptors:\n"); - for (slot=0; slotdescriptorhash.size; ++slot) { - descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; - while (c) { - fprintf(file," %p: ",c->parseddesc.any); - utf_fprint_printable_ascii(file,c->desc); - fprintf(file,"\n"); - c = c->hashlink; - } - } - - fprintf(file,"descriptors:\n"); - if (pool->descriptors) { - pos = pool->descriptors; - size = pool->descriptors_next - pool->descriptors; - fprintf(file," size: %d bytes\n",size); - - if (pool->descriptor_kind) { - kind = pool->descriptor_kind; - - while (pos < (pool->descriptors + size)) { - fprintf(file," %p: ",pos); - switch (*kind++) { - case 'f': - descriptor_debug_print_typedesc(file,(typedesc*)pos); - pos += sizeof(typedesc); - break; - case 'm': - descriptor_debug_print_methoddesc(file,(methoddesc*)pos); - pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc); - pos += sizeof(methoddesc) - sizeof(typedesc); - break; - default: - fprintf(file,"INVALID KIND"); - } - fputc('\n',file); - } - } - else { - while (size >= sizeof(voidptr)) { - fprintf(file," %p\n",*((voidptr*)pos)); - pos += sizeof(voidptr); - size -= sizeof(voidptr); - } - } - } - - fprintf(file,"==========================================================\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: - */ - diff --git a/src/vm/descriptor.h b/src/vm/descriptor.h deleted file mode 100644 index 9183fffd9..000000000 --- a/src/vm/descriptor.h +++ /dev/null @@ -1,199 +0,0 @@ -/* vm/descriptor.h - checking and parsing of field / method descriptors - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id: descriptor.h 6012 2006-11-16 19:45:15Z twisti $ - -*/ - - -#ifndef _DESCRIPTOR_H -#define _DESCRIPTOR_H - -/* forward typedefs ***********************************************************/ - -typedef struct descriptor_pool descriptor_pool; -typedef struct typedesc typedesc; -typedef struct paramdesc paramdesc; -typedef struct methoddesc methoddesc; - - -#include "vm/class.h" -#include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/method.h" -#include "vm/references.h" - - -/* data structures ************************************************************/ - -/*----------------------------------------------------------------------------*/ -/* Descriptor Pools */ -/* */ -/* A descriptor_pool is a temporary data structure used during loading of */ -/* a class. The descriptor_pool is used to allocate the table of */ -/* constant_classrefs the class uses, and for parsing the field and method */ -/* descriptors which occurr within the class. The inner workings of */ -/* descriptor_pool are not important for outside code. */ -/* */ -/* You use a descriptor_pool as follows: */ -/* */ -/* 1. create one with descriptor_pool_new */ -/* 2. add all explicit class references with descriptor_pool_add_class */ -/* 3. add all field/method descriptors with descriptor_pool_add */ -/* 4. call descriptor_pool_create_classrefs */ -/* You can now lookup classrefs with descriptor_pool_lookup_classref */ -/* 5. call descriptor_pool_alloc_parsed_descriptors */ -/* 6. for each field descriptor call descriptor_pool_parse_field_descriptor */ -/* for each method descriptor call descriptor_pool_parse_method_descriptor */ -/* 7. call descriptor_pool_get_parsed_descriptors */ -/* */ -/* IMPORTANT: The descriptor_pool functions use DNEW and DMNEW for allocating */ -/* memory which can be thrown away when the steps above have been */ -/* done. */ -/*----------------------------------------------------------------------------*/ - -struct descriptor_pool { - classinfo *referer; - u4 fieldcount; - u4 methodcount; - u4 paramcount; - u4 descriptorsize; - u1 *descriptors; - u1 *descriptors_next; - hashtable descriptorhash; - constant_classref *classrefs; - hashtable classrefhash; - u1 *descriptor_kind; /* useful for debugging */ - u1 *descriptor_kind_next; /* useful for debugging */ -}; - - -/* data structures for parsed field/method descriptors ************************/ - -struct typedesc { - constant_classref *classref; /* class reference for TYPE_ADR types */ - u1 type; /* TYPE_??? constant [1] */ - u1 decltype; /* (PRIMITIVE)TYPE_??? constant [2] */ - u1 arraydim; /* array dimension (0 if no array) */ -}; - -/* [1]...the type field contains the basic type used within the VM. So ints, */ -/* shorts, chars, bytes, booleans all have TYPE_INT. */ -/* [2]...the decltype field contains the declared type. */ -/* So short is PRIMITIVETYPE_SHORT, char is PRIMITIVETYPE_CHAR. */ -/* For non-primitive types decltype is TYPE_ADR. */ - -struct paramdesc { -#if defined(__MIPS__) - u1 type; /* TYPE_??? of the register allocated */ -#endif - bool inmemory; /* argument in register or on stack */ - s4 regoff; /* register index or stack offset */ -}; - -struct methoddesc { - s2 paramcount; /* number of parameters */ - s2 paramslots; /* like above but LONG,DOUBLE count twice */ - s4 argintreguse; /* number of used integer argument registers */ - s4 argfltreguse; /* number of used float argument registers */ - s4 memuse; /* number of stack slots used */ - paramdesc *params; /* allocated parameter descriptions [3] */ - typedesc returntype; /* parsed descriptor of the return type */ - typedesc paramtypes[1]; /* parameter types, variable length! */ -}; - -/* [3]...If params is NULL, the parameter descriptions have not yet been */ -/* allocated. In this case ___the possible 'this' pointer of the method */ -/* is NOT counted in paramcount/paramslots and it is NOT included in */ -/* the paramtypes array___. */ -/* If params != NULL, the parameter descriptions have been */ -/* allocated, and the 'this' pointer of the method, if any, IS included.*/ -/* In case the method has no parameters at all, the special value */ -/* METHODDESC_NO_PARAMS is used (see below). */ - -/* METHODDESC_NO_PARAMS is a special value for the methoddesc.params field */ -/* indicating that the method is a static method without any parameters. */ -/* This special value must be != NULL and it may only be set if */ -/* md->paramcount == 0. */ - -#define METHODDESC_NOPARAMS ((paramdesc*)1) - -/* function prototypes ********************************************************/ - -descriptor_pool * descriptor_pool_new(classinfo *referer); - -bool descriptor_pool_add_class(descriptor_pool *pool,utf *name); -bool descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots); - -u2 descriptor_to_basic_type(utf *desc); -u2 descriptor_typesize(typedesc *td); - -constant_classref * descriptor_pool_create_classrefs(descriptor_pool *pool, - s4 *count); -constant_classref * descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname); - -void descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool); - -typedesc *descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc); -methoddesc *descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, s4 mflags, - constant_classref *thisclass); - -bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags); - -void *descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size); -void descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, - u4 *descsize); - -#ifndef NDEBUG -void descriptor_debug_print_typedesc(FILE *file,typedesc *d); -void descriptor_debug_print_methoddesc(FILE *file,methoddesc *d); -void descriptor_debug_print_paramdesc(FILE *file,paramdesc *d); -void descriptor_pool_debug_dump(descriptor_pool *pool, FILE *file); -#endif /* !defined(NDEBUG) */ - -/* machine dependent descriptor function */ -void md_param_alloc(methoddesc *md); - -#endif /* _DESCRIPTOR_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: - */ diff --git a/src/vm/exceptions.c b/src/vm/exceptions.c index ada417089..24fb984eb 100644 --- a/src/vm/exceptions.c +++ b/src/vm/exceptions.c @@ -1,6 +1,6 @@ /* src/vm/exceptions.c - exception related functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Edwin Steiner - - $Id: exceptions.c 7228 2007-01-19 01:13:48Z edwin $ + $Id: exceptions.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -42,23 +37,35 @@ #include "vm/types.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" #include "native/include/java_lang_String.h" #include "native/include/java_lang_Throwable.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/threads.h" +#else +# include "threads/none/threads.h" +#endif + #include "toolbox/logging.h" #include "toolbox/util.h" -#include "vm/class.h" + +#include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" #include "vm/jit/methodheader.h" +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" + /* for raising exceptions from native methods *********************************/ @@ -89,13 +96,6 @@ bool exceptions_init(void) return false; #if defined(ENABLE_JAVASE) - /* java/lang/AbstractMethodError */ - - if (!(class_java_lang_AbstractMethodError = - load_class_bootstrap(utf_java_lang_AbstractMethodError)) || - !link_class(class_java_lang_AbstractMethodError)) - return false; - /* java/lang/LinkageError */ if (!(class_java_lang_LinkageError = @@ -111,15 +111,6 @@ bool exceptions_init(void) !link_class(class_java_lang_NoClassDefFoundError)) return false; -#if defined(ENABLE_JAVASE) - /* java/lang/NoSuchMethodError */ - - if (!(class_java_lang_NoSuchMethodError = - load_class_bootstrap(utf_java_lang_NoSuchMethodError)) || - !link_class(class_java_lang_NoSuchMethodError)) - return false; -#endif - /* java/lang/OutOfMemoryError */ if (!(class_java_lang_OutOfMemoryError = @@ -156,20 +147,6 @@ bool exceptions_init(void) !link_class(class_java_lang_ClassNotFoundException)) return false; - /* java/lang/IllegalArgumentException */ - - if (!(class_java_lang_IllegalArgumentException = - load_class_bootstrap(utf_java_lang_IllegalArgumentException)) || - !link_class(class_java_lang_IllegalArgumentException)) - return false; - - /* java/lang/IllegalMonitorStateException */ - - if (!(class_java_lang_IllegalMonitorStateException = - load_class_bootstrap(utf_java_lang_IllegalMonitorStateException)) || - !link_class(class_java_lang_IllegalMonitorStateException)) - return false; - /* java/lang/NullPointerException */ if (!(class_java_lang_NullPointerException = @@ -322,72 +299,138 @@ void throw_cacao_exception_exit(const char *exception, const char *message, ...) } -/* new_exception *************************************************************** +/* exceptions_new_class ******************************************************** - Creates an exception object with the given name and initalizes it. + Creates an exception object from the given class and initalizes it. IN: - classname....class name in UTF-8 - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). + class....class pointer *******************************************************************************/ -java_objectheader *new_exception(const char *classname) +static java_objectheader *exceptions_new_class(classinfo *c) { java_objectheader *o; - classinfo *c; - - if (!(c = load_class_bootstrap(utf_new_char(classname)))) - return *exceptionptr; o = native_new_and_init(c); - if (!o) + if (o == NULL) return *exceptionptr; return o; } -/* new_exception_message ******************************************************* +/* exceptions_new_utf ********************************************************** - Creates an exception object with the given name and initalizes it - with the given char message. + Creates an exception object with the given name and initalizes it. IN: classname....class name in UTF-8 - message......message in UTF-8 - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). *******************************************************************************/ -java_objectheader *new_exception_message(const char *classname, - const char *message) +static java_objectheader *exceptions_new_utf(utf *classname) { - java_lang_String *s; + classinfo *c; + java_objectheader *o; - s = javastring_new_from_utf_string(message); - if (!s) + c = load_class_bootstrap(classname); + + if (c == NULL) return *exceptionptr; - return new_exception_javastring(classname, s); + o = exceptions_new_class(c); + + return o; } -/* new_exception_throwable ***************************************************** +/* exceptions_throw_class ****************************************************** + + Creates an exception object from the given class, initalizes and + throws it. + + IN: + class....class pointer + +*******************************************************************************/ + +static void exceptions_throw_class(classinfo *c) +{ + java_objectheader *o; + + o = exceptions_new_class(c); + + if (o == NULL) + return; + + *exceptionptr = o; +} + + +/* exceptions_throw_utf ******************************************************** + + Creates an exception object with the given name, initalizes and + throws it. + + IN: + classname....class name in UTF-8 + +*******************************************************************************/ + +static void exceptions_throw_utf(utf *classname) +{ + classinfo *c; + + c = load_class_bootstrap(classname); + + if (c == NULL) + return; + + exceptions_throw_class(c); +} + + +/* exceptions_throw_utf_throwable ********************************************** Creates an exception object with the given name and initalizes it with the given java/lang/Throwable exception. IN: classname....class name in UTF-8 - throwable....the given Throwable + cause........the given Throwable + +*******************************************************************************/ + +static void exceptions_throw_utf_throwable(utf *classname, + java_objectheader *cause) +{ + java_objectheader *o; + classinfo *c; + + c = load_class_bootstrap(classname); + + if (c == NULL) + return; + + o = native_new_and_init_throwable(c, cause); + + if (o == NULL) + return; + + *exceptionptr = o; +} + + +/* exceptions_new_utf_javastring *********************************************** + + Creates an exception object with the given name and initalizes it + with the given java/lang/String message. + + IN: + classname....class name in UTF-8 + message......the message as a java.lang.String RETURN VALUE: an exception pointer (in any case -- either it is the newly created @@ -395,25 +438,56 @@ java_objectheader *new_exception_message(const char *classname, *******************************************************************************/ -java_objectheader *new_exception_throwable(const char *classname, - java_lang_Throwable *throwable) +static java_objectheader *exceptions_new_utf_javastring(utf *classname, + java_objectheader *message) { java_objectheader *o; classinfo *c; - if (!(c = load_class_bootstrap(utf_new_char(classname)))) + c = load_class_bootstrap(classname); + + if (c == NULL) return *exceptionptr; - o = native_new_and_init_throwable(c, throwable); + o = native_new_and_init_string(c, message); - if (!o) + if (o == NULL) return *exceptionptr; return o; } -/* new_exception_utfmessage **************************************************** +/* exceptions_new_class_utf **************************************************** + + Creates an exception object of the given class and initalizes it. + + IN: + c..........class pointer + message....the message as UTF-8 string + +*******************************************************************************/ + +static java_objectheader *exceptions_new_class_utf(classinfo *c, utf *message) +{ + java_objectheader *o; + java_objectheader *s; + + s = javastring_new(message); + + if (s == NULL) + return *exceptionptr; + + o = native_new_and_init_string(c, s); + + if (o == NULL) + return *exceptionptr; + + return o; +} + + +/* exceptions_new_utf_utf ****************************************************** Creates an exception object with the given name and initalizes it with the given utf message. @@ -428,26 +502,30 @@ java_objectheader *new_exception_throwable(const char *classname, *******************************************************************************/ -java_objectheader *new_exception_utfmessage(const char *classname, utf *message) +static java_objectheader *exceptions_new_utf_utf(utf *classname, utf *message) { - java_lang_String *s; + classinfo *c; + java_objectheader *o; - s = javastring_new(message); - if (!s) + c = load_class_bootstrap(classname); + + if (c == NULL) return *exceptionptr; - return new_exception_javastring(classname, s); + o = exceptions_new_class_utf(c, message); + + return o; } -/* new_exception_javastring **************************************************** +/* new_exception_message ******************************************************* Creates an exception object with the given name and initalizes it - with the given java/lang/String message. + with the given char message. IN: classname....class name in UTF-8 - message......the message as a java.lang.String + message......message in UTF-8 RETURN VALUE: an exception pointer (in any case -- either it is the newly created @@ -455,24 +533,57 @@ java_objectheader *new_exception_utfmessage(const char *classname, utf *message) *******************************************************************************/ -java_objectheader *new_exception_javastring(const char *classname, - java_lang_String *message) +static java_objectheader *new_exception_message(const char *classname, + const char *message) { java_objectheader *o; - classinfo *c; - - if (!(c = load_class_bootstrap(utf_new_char(classname)))) - return *exceptionptr; + java_objectheader *s; - o = native_new_and_init_string(c, message); + s = javastring_new_from_utf_string(message); - if (!o) + if (s == NULL) return *exceptionptr; + o = exceptions_new_utf_javastring(classname, s); + return o; } +/* exceptions_throw_class_utf ************************************************** + + Creates an exception object of the given class, initalizes and + throws it with the given utf message. + + IN: + c..........class pointer + message....the message as an UTF-8 + +*******************************************************************************/ + +static void exceptions_throw_class_utf(classinfo *c, utf *message) +{ + *exceptionptr = exceptions_new_class_utf(c, message); +} + + +/* exceptions_throw_utf_utf **************************************************** + + Creates an exception object with the given name, initalizes and + throws it with the given utf message. + + IN: + classname....class name in UTF-8 + message......the message as an utf * + +*******************************************************************************/ + +static void exceptions_throw_utf_utf(utf *classname, utf *message) +{ + *exceptionptr = exceptions_new_utf_utf(classname, message); +} + + /* new_exception_int *********************************************************** Creates an exception object with the given name and initalizes it @@ -505,39 +616,20 @@ java_objectheader *new_exception_int(const char *classname, s4 i) } -/* exceptions_new_abstractmethoderror ****************************************** +/* exceptions_new_abstractmethoderror **************************************** Generates a java.lang.AbstractMethodError for the VM. *******************************************************************************/ -#if defined(ENABLE_JAVASE) java_objectheader *exceptions_new_abstractmethoderror(void) { - java_objectheader *e; - - e = native_new_and_init(class_java_lang_AbstractMethodError); - - if (e == NULL) - return *exceptionptr; - - return e; -} -#endif - - -/* exceptions_throw_abstractmethoderror **************************************** - - Generates a java.lang.AbstractMethodError for the VM and throws it. + java_objectheader *o; -*******************************************************************************/ + o = exceptions_new_utf(utf_java_lang_AbstractMethodError); -#if defined(ENABLE_JAVASE) -void exceptions_throw_abstractmethoderror(void) -{ - *exceptionptr = exceptions_new_abstractmethoderror(); + return o; } -#endif /* exceptions_asm_new_abstractmethoderror ************************************** @@ -574,21 +666,84 @@ java_objectheader *exceptions_asm_new_abstractmethoderror(u1 *sp, u1 *ra) } -/* new_classformaterror ******************************************************** +/* exceptions_new_arraystoreexception ****************************************** + + Generates a java.lang.ArrayStoreException for the VM. + +*******************************************************************************/ + +java_objectheader *exceptions_new_arraystoreexception(void) +{ + java_objectheader *o; + + o = exceptions_new_utf(utf_java_lang_ArrayStoreException); + + return o; +} + + +/* exceptions_throw_abstractmethoderror **************************************** + + Generates and throws a java.lang.AbstractMethodError for the VM. + +*******************************************************************************/ + +void exceptions_throw_abstractmethoderror(void) +{ + exceptions_throw_utf(utf_java_lang_AbstractMethodError); +} + + +/* exceptions_throw_classcircularityerror ************************************** - generates a java.lang.ClassFormatError for the classloader + Generates and throws a java.lang.ClassCircularityError for the + classloader. IN: c............the class in which the error was found - message......UTF-8 format string - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). +*******************************************************************************/ + +void exceptions_throw_classcircularityerror(classinfo *c) +{ + java_objectheader *o; + char *msg; + s4 msglen; + + /* calculate message length */ + + msglen = utf_bytes(c->name) + strlen("0"); + + /* allocate a buffer */ + + msg = MNEW(char, msglen); + + /* print message into allocated buffer */ + + utf_copy_classname(msg, c->name); + + o = new_exception_message(utf_java_lang_ClassCircularityError, msg); + + MFREE(msg, char, msglen); + + if (o == NULL) + return; + + *exceptionptr = o; +} + + +/* exceptions_throw_classformaterror ******************************************* + + Generates and throws a java.lang.ClassFormatError for the VM. + + IN: + c............the class in which the error was found + message......UTF-8 format string *******************************************************************************/ -java_objectheader *new_classformaterror(classinfo *c, const char *message, ...) +void exceptions_throw_classformaterror(classinfo *c, const char *message, ...) { java_objectheader *o; char *msg; @@ -599,14 +754,14 @@ java_objectheader *new_classformaterror(classinfo *c, const char *message, ...) msglen = 0; - if (c) + if (c != NULL) msglen += utf_bytes(c->name) + strlen(" ("); va_start(ap, message); msglen += get_variable_message_length(message, ap); va_end(ap); - if (c) + if (c != NULL) msglen += strlen(")"); msglen += strlen("0"); @@ -617,7 +772,7 @@ java_objectheader *new_classformaterror(classinfo *c, const char *message, ...) /* print message into allocated buffer */ - if (c) { + if (c != NULL) { utf_copy_classname(msg, c->name); strcat(msg, " ("); } @@ -626,141 +781,161 @@ java_objectheader *new_classformaterror(classinfo *c, const char *message, ...) vsprintf(msg + strlen(msg), message, ap); va_end(ap); - if (c) + if (c != NULL) strcat(msg, ")"); - o = new_exception_message(string_java_lang_ClassFormatError, msg); + o = new_exception_message(utf_java_lang_ClassFormatError, msg); MFREE(msg, char, msglen); - return o; + *exceptionptr = o; } -/* exceptions_throw_classformaterror ******************************************* +/* exceptions_throw_classnotfoundexception ************************************* - Generate a java.lang.ClassFormatError for the VM system and throw it. + Generates and throws a java.lang.ClassNotFoundException for the + VM. IN: - c............the class in which the error was found - message......UTF-8 format string - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). + name.........name of the class not found as a utf * *******************************************************************************/ -void exceptions_throw_classformaterror(classinfo *c, const char *message, ...) +void exceptions_throw_classnotfoundexception(utf *name) { - va_list ap; + /* we use class here, as this one is rather frequent */ - va_start(ap, message); - *exceptionptr = new_classformaterror(c, message, ap); - va_end(ap); + exceptions_throw_class_utf(class_java_lang_ClassNotFoundException, name); } -/* new_classnotfoundexception ************************************************** +/* exceptions_throw_noclassdeffounderror *************************************** - Generates a java.lang.ClassNotFoundException for the classloader. + Generates and throws a java.lang.NoClassDefFoundError. IN: name.........name of the class not found as a utf * - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). +*******************************************************************************/ + +void exceptions_throw_noclassdeffounderror(utf *name) +{ + exceptions_throw_class_utf(class_java_lang_NoClassDefFoundError, name); +} + + +/* classnotfoundexception_to_noclassdeffounderror ****************************** + + Check the *exceptionptr for a ClassNotFoundException. If it is one, + convert it to a NoClassDefFoundError. *******************************************************************************/ -java_objectheader *new_classnotfoundexception(utf *name) +void classnotfoundexception_to_noclassdeffounderror(void) { - java_objectheader *o; - java_lang_String *s; + java_objectheader *xptr; + java_objectheader *cause; + java_lang_Throwable *t; + java_lang_String *s; - s = javastring_new(name); - if (!s) - return *exceptionptr; + /* get the cause */ - o = native_new_and_init_string(class_java_lang_ClassNotFoundException, s); + cause = *exceptionptr; - if (!o) - return *exceptionptr; + /* convert ClassNotFoundException's to NoClassDefFoundError's */ - return o; -} + if (builtin_instanceof(cause, class_java_lang_ClassNotFoundException)) { + /* clear exception, because we are calling jit code again */ + *exceptionptr = NULL; -/* new_noclassdeffounderror **************************************************** + /* create new error */ - Generates a java.lang.NoClassDefFoundError + t = (java_lang_Throwable *) cause; + s = t->detailMessage; - IN: - name.........name of the class not found as a utf * + xptr = exceptions_new_utf_javastring(utf_java_lang_NoClassDefFoundError, s); - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). + /* we had an exception while creating the error */ -*******************************************************************************/ + if (*exceptionptr) + return; -java_objectheader *new_noclassdeffounderror(utf *name) -{ - java_objectheader *o; - java_lang_String *s; + /* set new exception */ - s = javastring_new(name); - if (!s) - return *exceptionptr; + *exceptionptr = xptr; + } +} - o = native_new_and_init_string(class_java_lang_NoClassDefFoundError, s); - if (!o) - return *exceptionptr; +/* exceptions_throw_exceptionininitializererror ******************************** - return o; + Generates and throws a java.lang.ExceptionInInitializerError for + the VM. + + IN: + cause......cause exception object + +*******************************************************************************/ + +void exceptions_throw_exceptionininitializererror(java_objectheader *cause) +{ + exceptions_throw_utf_throwable(utf_java_lang_ExceptionInInitializerError, + cause); } -/* classnotfoundexception_to_noclassdeffounderror ****************************** +/* exceptions_throw_incompatibleclasschangeerror ******************************* - Check the *exceptionptr for a ClassNotFoundException. If it is one, - convert it to a NoClassDefFoundError. + Generates and throws a java.lang.IncompatibleClassChangeError for + the VM. + + IN: + message......UTF-8 message format string *******************************************************************************/ -void classnotfoundexception_to_noclassdeffounderror(void) +void exceptions_throw_incompatibleclasschangeerror(classinfo *c, const char *message) { - java_objectheader *xptr; - java_objectheader *cause; + java_objectheader *o; + char *msg; + s4 msglen; - /* get the cause */ + /* calculate exception message length */ - cause = *exceptionptr; + msglen = utf_bytes(c->name) + strlen(message) + strlen("0"); - /* convert ClassNotFoundException's to NoClassDefFoundError's */ + /* allocate memory */ - if (builtin_instanceof(cause, class_java_lang_ClassNotFoundException)) { - /* clear exception, because we are calling jit code again */ + msg = MNEW(char, msglen); + + utf_copy_classname(msg, c->name); + strcat(msg, message); + + o = native_new_and_init_string(utf_java_lang_IncompatibleClassChangeError, + javastring_new_from_utf_string(msg)); + + /* free memory */ + + MFREE(msg, char, msglen); - *exceptionptr = NULL; + if (o == NULL) + return; - /* create new error */ + *exceptionptr = o; +} - xptr = - new_exception_javastring(string_java_lang_NoClassDefFoundError, - ((java_lang_Throwable *) cause)->detailMessage); - /* we had an exception while creating the error */ +/* exceptions_throw_instantiationerror ***************************************** - if (*exceptionptr) - return; + Generates and throws a java.lang.InstantiationError for the VM. - /* set new exception */ +*******************************************************************************/ - *exceptionptr = xptr; - } +void exceptions_throw_instantiationerror(classinfo *c) +{ + exceptions_throw_utf_utf(utf_java_lang_InstantiationError, c->name); } @@ -798,7 +973,7 @@ void exceptions_throw_internalerror(const char *message, ...) /* create exception object */ - o = new_exception_message(string_java_lang_InternalError, msg); + o = new_exception_message(utf_java_lang_InternalError, msg); /* free memory */ @@ -811,23 +986,18 @@ void exceptions_throw_internalerror(const char *message, ...) } -/* exceptions_new_linkageerror ************************************************* +/* exceptions_throw_linkageerror *********************************************** - Generates a java.lang.LinkageError with an error message. + Generates and throws java.lang.LinkageError with an error message. IN: message......UTF-8 message c............class related to the error. If this is != NULL the name of c is appended to the error message. - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). - *******************************************************************************/ -java_objectheader *exceptions_new_linkageerror(const char *message, - classinfo *c) +void exceptions_throw_linkageerror(const char *message, classinfo *c) { java_objectheader *o; char *msg; @@ -836,9 +1006,9 @@ java_objectheader *exceptions_new_linkageerror(const char *message, /* calculate exception message length */ msglen = strlen(message) + 1; - if (c) { + + if (c != NULL) msglen += utf_bytes(c->name); - } /* allocate memory */ @@ -847,9 +1017,9 @@ java_objectheader *exceptions_new_linkageerror(const char *message, /* generate message */ strcpy(msg,message); - if (c) { + + if (c != NULL) utf_cat_classname(msg, c->name); - } o = native_new_and_init_string(class_java_lang_LinkageError, javastring_new_from_utf_string(msg)); @@ -858,40 +1028,33 @@ java_objectheader *exceptions_new_linkageerror(const char *message, MFREE(msg, char, msglen); - if (!o) - return *exceptionptr; + if (o == NULL) + return; - return o; + *exceptionptr = o; } -/* exceptions_new_nosuchmethoderror ******************************************** +/* exceptions_throw_nosuchfielderror ******************************************* - Generates a java.lang.NoSuchMethodError with an error message. + Generates and throws a java.lang.NoSuchFieldError with an error + message. IN: - c............class in which the method was not found - name.........name of the method - desc.........descriptor of the method - - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). + c............class in which the field was not found + name.........name of the field *******************************************************************************/ -#if defined(ENABLE_JAVASE) -java_objectheader *exceptions_new_nosuchmethoderror(classinfo *c, - utf *name, utf *desc) +void exceptions_throw_nosuchfielderror(classinfo *c, utf *name) { - java_objectheader *o; - char *msg; - s4 msglen; + char *msg; + s4 msglen; + utf *u; /* calculate exception message length */ - msglen = utf_bytes(c->name) + strlen(".") + utf_bytes(name) + - utf_bytes(desc) + strlen("0"); + msglen = utf_bytes(c->name) + strlen(".") + utf_bytes(name) + strlen("0"); /* allocate memory */ @@ -902,26 +1065,21 @@ java_objectheader *exceptions_new_nosuchmethoderror(classinfo *c, utf_copy_classname(msg, c->name); strcat(msg, "."); utf_cat(msg, name); - utf_cat(msg, desc); - o = native_new_and_init_string(class_java_lang_NoSuchMethodError, - javastring_new_from_utf_string(msg)); + u = utf_new_char(msg); /* free memory */ MFREE(msg, char, msglen); - if (o == NULL) - return *exceptionptr; - - return o; + exceptions_throw_utf_utf(utf_java_lang_NoSuchFieldError, u); } -#endif /* exceptions_throw_nosuchmethoderror ****************************************** - Generates a java.lang.NoSuchMethodError with an error message. + Generates and throws a java.lang.NoSuchMethodError with an error + message. IN: c............class in which the method was not found @@ -930,12 +1088,36 @@ java_objectheader *exceptions_new_nosuchmethoderror(classinfo *c, *******************************************************************************/ -#if defined(ENABLE_JAVASE) void exceptions_throw_nosuchmethoderror(classinfo *c, utf *name, utf *desc) { - *exceptionptr = exceptions_new_nosuchmethoderror(c, name, desc); + char *msg; + s4 msglen; + utf *u; + + /* calculate exception message length */ + + msglen = utf_bytes(c->name) + strlen(".") + utf_bytes(name) + + utf_bytes(desc) + strlen("0"); + + /* allocate memory */ + + msg = MNEW(char, msglen); + + /* generate message */ + + utf_copy_classname(msg, c->name); + strcat(msg, "."); + utf_cat(msg, name); + utf_cat(msg, desc); + + u = utf_new_char(msg); + + /* free memory */ + + MFREE(msg, char, msglen); + + exceptions_throw_utf_utf(utf_java_lang_NoSuchMethodError, u); } -#endif /* exceptions_throw_outofmemoryerror ******************************************* @@ -946,45 +1128,49 @@ void exceptions_throw_nosuchmethoderror(classinfo *c, utf *name, utf *desc) void exceptions_throw_outofmemoryerror(void) { - java_objectheader *e; + exceptions_throw_class(class_java_lang_OutOfMemoryError); +} - e = native_new_and_init(class_java_lang_OutOfMemoryError); - if (e == NULL) - return; +/* exceptions_throw_unsatisfiedlinkerror *************************************** + + Generates and throws a java.lang.UnsatisfiedLinkError for the + classloader. + + IN: + name......UTF-8 name string - *exceptionptr = e; +*******************************************************************************/ + +void exceptions_throw_unsatisfiedlinkerror(utf *name) +{ + exceptions_throw_utf_utf(utf_java_lang_UnsatisfiedLinkError, name); } -/* new_unsupportedclassversionerror ******************************************** +/* exceptions_throw_unsupportedclassversionerror ******************************* - Generate a java.lang.UnsupportedClassVersionError for the classloader + Generates and throws a java.lang.UnsupportedClassVersionError for + the classloader. IN: c............class in which the method was not found message......UTF-8 format string - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). - *******************************************************************************/ -java_objectheader *new_unsupportedclassversionerror(classinfo *c, const char *message, ...) +void exceptions_throw_unsupportedclassversionerror(classinfo *c, u4 ma, u4 mi) { java_objectheader *o; - va_list ap; char *msg; s4 msglen; /* calculate exception message length */ - msglen = utf_bytes(c->name) + strlen(" (") + strlen(")") + strlen("0"); - - va_start(ap, message); - msglen += get_variable_message_length(message, ap); - va_end(ap); + msglen = + utf_bytes(c->name) + + strlen(" (Unsupported major.minor version 00.0)") + + strlen("0"); /* allocate memory */ @@ -993,43 +1179,35 @@ java_objectheader *new_unsupportedclassversionerror(classinfo *c, const char *me /* generate message */ utf_copy_classname(msg, c->name); - strcat(msg, " ("); - - va_start(ap, message); - vsprintf(msg + strlen(msg), message, ap); - va_end(ap); - - strcat(msg, ")"); + sprintf(msg + strlen(msg), " (Unsupported major.minor version %d.%d)", + ma, mi); /* create exception object */ - o = new_exception_message(string_java_lang_UnsupportedClassVersionError, - msg); + o = new_exception_message(utf_java_lang_UnsupportedClassVersionError, msg); /* free memory */ MFREE(msg, char, msglen); - return o; + if (o == NULL) + return; + + *exceptionptr = o; } -/* exceptions_new_verifyerror ************************************************** +/* exceptions_throw_verifyerror ************************************************ - Generates a java.lang.VerifyError for the JIT compiler. + Generates and throws a java.lang.VerifyError for the JIT compiler. IN: m............method in which the error was found message......UTF-8 format string - RETURN VALUE: - an exception pointer (in any case -- either it is the newly created - exception, or an exception thrown while trying to create it). - *******************************************************************************/ -java_objectheader *exceptions_new_verifyerror(methodinfo *m, - const char *message, ...) +void exceptions_throw_verifyerror(methodinfo *m, const char *message, ...) { java_objectheader *o; va_list ap; @@ -1040,8 +1218,9 @@ java_objectheader *exceptions_new_verifyerror(methodinfo *m, msglen = 0; - if (m) - msglen = strlen("(class: ") + utf_bytes(m->class->name) + + if (m != NULL) + msglen = + strlen("(class: ") + utf_bytes(m->class->name) + strlen(", method: ") + utf_bytes(m->name) + strlen(" signature: ") + utf_bytes(m->descriptor) + strlen(") ") + strlen("0"); @@ -1056,7 +1235,7 @@ java_objectheader *exceptions_new_verifyerror(methodinfo *m, /* generate message */ - if (m) { + if (m != NULL) { strcpy(msg, "(class: "); utf_cat_classname(msg, m->class->name); strcat(msg, ", method: "); @@ -1072,25 +1251,13 @@ java_objectheader *exceptions_new_verifyerror(methodinfo *m, /* create exception object */ - o = new_exception_message(string_java_lang_VerifyError, msg); + o = new_exception_message(utf_java_lang_VerifyError, msg); /* free memory */ MFREE(msg, char, msglen); - return o; -} - - -/* exceptions_throw_verifyerror ************************************************ - - Throws a java.lang.VerifyError for the VM system. - -*******************************************************************************/ - -void exceptions_throw_verifyerror(methodinfo *m, const char *message, ...) -{ - *exceptionptr = exceptions_new_verifyerror(m, message); + *exceptionptr = o; } @@ -1160,7 +1327,7 @@ void exceptions_throw_verifyerror_for_stack(methodinfo *m,int type) /* create exception object */ - o = new_exception_message(string_java_lang_VerifyError, msg); + o = new_exception_message(utf_java_lang_VerifyError, msg); /* free memory */ @@ -1170,54 +1337,34 @@ void exceptions_throw_verifyerror_for_stack(methodinfo *m,int type) } -/* exceptions_new_virtualmachineerror ****************************************** - - Generates a java.lang.VirtualMachineError for the VM system. - -*******************************************************************************/ - -java_objectheader *exceptions_new_virtualmachineerror(void) -{ - java_objectheader *e; - - e = native_new_and_init(class_java_lang_VirtualMachineError); - - if (e == NULL) - return *exceptionptr; - - return e; -} - - /* exceptions_throw_virtualmachineerror **************************************** - Throws a java.lang.VirtualMachineError for the VM system. + Generates and throws a java.lang.VirtualMachineError for the VM. *******************************************************************************/ void exceptions_throw_virtualmachineerror(void) { - *exceptionptr = exceptions_new_virtualmachineerror(); + exceptions_throw_class(class_java_lang_VirtualMachineError); } -/* new_arithmeticexception ***************************************************** +/* exceptions_new_arithmeticexception ****************************************** - Generates a java.lang.ArithmeticException for the jit compiler. + Generates a java.lang.ArithmeticException for the JIT compiler. *******************************************************************************/ -java_objectheader *new_arithmeticexception(void) +java_objectheader *exceptions_new_arithmeticexception(void) { - java_objectheader *e; + java_objectheader *o; - e = new_exception_message(string_java_lang_ArithmeticException, - string_java_lang_ArithmeticException_message); + o = new_exception_message(utf_java_lang_ArithmeticException, "/ by zero"); - if (!e) + if (o == NULL) return *exceptionptr; - return e; + return o; } @@ -1228,12 +1375,11 @@ java_objectheader *new_arithmeticexception(void) *******************************************************************************/ -java_objectheader *new_arrayindexoutofboundsexception(s4 index) +java_objectheader *exceptions_new_arrayindexoutofboundsexception(s4 index) { - java_objectheader *e; - methodinfo *m; java_objectheader *o; - java_lang_String *s; + methodinfo *m; + java_objectheader *s; /* convert the index into a String, like Sun does */ @@ -1246,73 +1392,44 @@ java_objectheader *new_arrayindexoutofboundsexception(s4 index) if (m == NULL) return *exceptionptr; - o = vm_call_method(m, NULL, index); - - s = (java_lang_String *) o; + s = vm_call_method(m, NULL, index); if (s == NULL) return *exceptionptr; - e = new_exception_javastring(string_java_lang_ArrayIndexOutOfBoundsException, - s); + o = exceptions_new_utf_javastring(utf_java_lang_ArrayIndexOutOfBoundsException, + s); - if (e == NULL) + if (o == NULL) return *exceptionptr; - return e; + return o; } /* exceptions_throw_arrayindexoutofboundsexception ***************************** - Generates a java.lang.ArrayIndexOutOfBoundsException for the VM - system. + Generates and throws a java.lang.ArrayIndexOutOfBoundsException for + the VM. *******************************************************************************/ void exceptions_throw_arrayindexoutofboundsexception(void) { - java_objectheader *e; - - e = new_exception(string_java_lang_ArrayIndexOutOfBoundsException); - - if (!e) - return; - - *exceptionptr = e; -} - - -/* exceptions_new_arraystoreexception ****************************************** - - Generates a java.lang.ArrayStoreException for the VM compiler. - -*******************************************************************************/ - -java_objectheader *exceptions_new_arraystoreexception(void) -{ - java_objectheader *e; - - e = new_exception(string_java_lang_ArrayStoreException); -/* e = native_new_and_init(class_java_lang_ArrayStoreException); */ - - if (!e) - return *exceptionptr; - - return e; + exceptions_throw_utf(utf_java_lang_ArrayIndexOutOfBoundsException); } /* exceptions_throw_arraystoreexception **************************************** - Generates a java.lang.ArrayStoreException for the VM system and - throw it in the VM system. + Generates and throws a java.lang.ArrayStoreException for the VM. *******************************************************************************/ void exceptions_throw_arraystoreexception(void) { - *exceptionptr = exceptions_new_arraystoreexception(); + exceptions_throw_utf(utf_java_lang_ArrayStoreException); +/* e = native_new_and_init(class_java_lang_ArrayStoreException); */ } @@ -1341,99 +1458,110 @@ java_objectheader *exceptions_new_classcastexception(java_objectheader *o) } -/* exceptions_new_illegalargumentexception ************************************* +/* exceptions_throw_clonenotsupportedexception ********************************* - Generates a java.lang.IllegalArgumentException for the VM system. + Generates and throws a java.lang.CloneNotSupportedException for the + VM. *******************************************************************************/ -java_objectheader *new_illegalargumentexception(void) +void exceptions_throw_clonenotsupportedexception(void) { - java_objectheader *e; + exceptions_throw_utf(utf_java_lang_CloneNotSupportedException); +} - e = native_new_and_init(class_java_lang_IllegalArgumentException); - if (!e) - return *exceptionptr; +/* exceptions_throw_illegalaccessexception ************************************* - return e; + Generates and throws a java.lang.IllegalAccessException for the VM. + +*******************************************************************************/ + +void exceptions_throw_illegalaccessexception(classinfo *c) +{ + /* XXX handle argument */ + + exceptions_throw_utf(utf_java_lang_IllegalAccessException); } /* exceptions_throw_illegalargumentexception *********************************** - Generates a java.lang.IllegalArgumentException for the VM system - and throw it in the VM system. + Generates and throws a java.lang.IllegalArgumentException for the + VM. *******************************************************************************/ void exceptions_throw_illegalargumentexception(void) { - *exceptionptr = new_illegalargumentexception(); + exceptions_throw_utf(utf_java_lang_IllegalArgumentException); } -/* exceptions_new_illegalmonitorstateexception ********************************* +/* exceptions_throw_illegalmonitorstateexception ******************************* - Generates a java.lang.IllegalMonitorStateException for the VM - thread system. + Generates and throws a java.lang.IllegalMonitorStateException for + the VM. *******************************************************************************/ -java_objectheader *exceptions_new_illegalmonitorstateexception(void) +void exceptions_throw_illegalmonitorstateexception(void) { - java_objectheader *e; - - e = native_new_and_init(class_java_lang_IllegalMonitorStateException); - - if (e == NULL) - return *exceptionptr; - - return e; + exceptions_throw_utf(utf_java_lang_IllegalMonitorStateException); } -/* exceptions_throw_illegalmonitorstateexception ******************************* +/* exceptions_throw_instantiationexception ************************************* - Generates a java.lang.IllegalMonitorStateException for the VM - system and throw it in the VM system. + Generates and throws a java.lang.InstantiationException for the VM. *******************************************************************************/ -void exceptions_throw_illegalmonitorstateexception(void) +void exceptions_throw_instantiationexception(classinfo *c) { - *exceptionptr = exceptions_new_illegalmonitorstateexception(); + exceptions_throw_utf_utf(utf_java_lang_InstantiationException, c->name); } -/* exceptions_new_negativearraysizeexception *********************************** +/* exceptions_throw_interruptedexception *************************************** - Generates a java.lang.NegativeArraySizeException for the VM system. + Generates and throws a java.lang.InterruptedException for the VM. *******************************************************************************/ -java_objectheader *new_negativearraysizeexception(void) +void exceptions_throw_interruptedexception(void) { - java_objectheader *e; + exceptions_throw_utf(utf_java_lang_InterruptedException); +} - e = new_exception(string_java_lang_NegativeArraySizeException); - if (!e) - return *exceptionptr; +/* exceptions_throw_invocationtargetexception ********************************** - return e; + Generates and throws a java.lang.InvocationTargetException for the + VM. + + IN: + cause......cause exception object + +*******************************************************************************/ + +void exceptions_throw_invocationtargetexception(java_objectheader *cause) +{ + exceptions_throw_utf_throwable(utf_java_lang_InvocationTargetException, + cause); } /* exceptions_throw_negativearraysizeexception ********************************* - Generates a java.lang.NegativeArraySizeException for the VM system. + Generates and throws a java.lang.NegativeArraySizeException for the + VM. *******************************************************************************/ void exceptions_throw_negativearraysizeexception(void) { - *exceptionptr = new_negativearraysizeexception(); + exceptions_throw_utf(utf_java_lang_NegativeArraySizeException); } @@ -1445,14 +1573,11 @@ void exceptions_throw_negativearraysizeexception(void) java_objectheader *exceptions_new_nullpointerexception(void) { - java_objectheader *e; - - e = native_new_and_init(class_java_lang_NullPointerException); + java_objectheader *o; - if (e == NULL) - return *exceptionptr; + o = exceptions_new_class(class_java_lang_NullPointerException); - return e; + return o; } @@ -1465,40 +1590,62 @@ java_objectheader *exceptions_new_nullpointerexception(void) void exceptions_throw_nullpointerexception(void) { - *exceptionptr = exceptions_new_nullpointerexception(); + exceptions_throw_class(class_java_lang_NullPointerException); } -/* exceptions_new_stringindexoutofboundsexception ****************************** +/* exceptions_throw_stringindexoutofboundsexception **************************** - Generates a java.lang.StringIndexOutOfBoundsException for the VM - system. + Generates and throws a java.lang.StringIndexOutOfBoundsException + for the VM. *******************************************************************************/ -java_objectheader *exceptions_new_stringindexoutofboundsexception(void) +void exceptions_throw_stringindexoutofboundsexception(void) { - java_objectheader *e; + exceptions_throw_utf(utf_java_lang_StringIndexOutOfBoundsException); +} - e = new_exception(string_java_lang_StringIndexOutOfBoundsException); - if (e == NULL) - return *exceptionptr; +/* exceptions_get_exception **************************************************** - return e; + Returns the current exception pointer of the current thread. + +*******************************************************************************/ + +java_objectheader *exceptions_get_exception(void) +{ + /* return the exception */ + + return *exceptionptr; } -/* exceptions_throw_stringindexoutofboundsexception **************************** +/* exceptions_set_exception **************************************************** - Throws a java.lang.StringIndexOutOfBoundsException for the VM - system. + Sets the exception pointer of the current thread. *******************************************************************************/ -void exceptions_throw_stringindexoutofboundsexception(void) +void exceptions_set_exception(java_objectheader *o) +{ + /* set the exception */ + + *exceptionptr = o; +} + + +/* exceptions_clear_exception ************************************************** + + Clears the current exception pointer of the current thread. + +*******************************************************************************/ + +void exceptions_clear_exception(void) { - *exceptionptr = exceptions_new_stringindexoutofboundsexception(); + /* and clear the exception */ + + *exceptionptr = NULL; } @@ -1761,6 +1908,23 @@ void exceptions_print_exception(java_objectheader *xptr) } +/* exceptions_print_current_exception ****************************************** + + Prints the current pending exception, the detail message and the + cause, if available, with CACAO internal functions to stdout. + +*******************************************************************************/ + +void exceptions_print_current_exception(void) +{ + java_objectheader *xptr; + + xptr = *exceptionptr; + + exceptions_print_exception(xptr); +} + + /* * 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 diff --git a/src/vm/exceptions.h b/src/vm/exceptions.h index 70e9088e2..0c8a21cfc 100644 --- a/src/vm/exceptions.h +++ b/src/vm/exceptions.h @@ -1,6 +1,6 @@ /* src/vm/exceptions.h - exception related functions prototypes - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Edwin Steiner - - $Id: exceptions.h 6286 2007-01-10 10:03:38Z twisti $ + $Id: exceptions.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,12 +36,9 @@ #include "vm/types.h" #include "vm/global.h" -#include "native/jni.h" -#include "native/include/java_lang_String.h" -#include "native/include/java_lang_Throwable.h" -#include "vm/builtin.h" -#include "vm/references.h" -#include "vm/method.h" + +#include "vmcore/references.h" +#include "vmcore/method.h" /* hardware-exception defines ************************************************** @@ -68,19 +60,6 @@ #define EXCEPTION_LOAD_DISP_PATCHER 5 -/* exception pointer **********************************************************/ - -#if defined(ENABLE_THREADS) -#define exceptionptr &(THREADOBJECT->_exceptionptr) -#else -#define exceptionptr &_no_threads_exceptionptr -#endif - -#if !defined(ENABLE_THREADS) -extern java_objectheader *_no_threads_exceptionptr; -#endif - - /* function prototypes ********************************************************/ /* load and link exceptions used in the system */ @@ -101,90 +80,68 @@ void throw_cacao_exception_exit(const char *exception, /* initialize new exceptions */ -java_objectheader *new_exception(const char *classname); - -java_objectheader *new_exception_message(const char *classname, - const char *message); - -java_objectheader *new_exception_throwable(const char *classname, - java_lang_Throwable *cause); - java_objectheader *new_exception_utfmessage(const char *classname, utf *message); -java_objectheader *new_exception_javastring(const char *classname, - java_lang_String *message); - java_objectheader *new_exception_int(const char *classname, s4 i); /* functions to generate compiler exceptions */ -#if defined(ENABLE_JAVASE) java_objectheader *exceptions_new_abstractmethoderror(void); -void exceptions_throw_abstractmethoderror(void); -#endif - java_objectheader *exceptions_asm_new_abstractmethoderror(u1 *sp, u1 *ra); +java_objectheader *exceptions_new_arraystoreexception(void); -java_objectheader *new_classformaterror(classinfo *c, const char *message, ...); +void exceptions_throw_abstractmethoderror(void); +void exceptions_throw_classcircularityerror(classinfo *c); void exceptions_throw_classformaterror(classinfo *c, const char *message, ...); - -java_objectheader *new_classnotfoundexception(utf *name); -java_objectheader *new_noclassdeffounderror(utf *name); -java_objectheader *exceptions_new_linkageerror(const char *message,classinfo *c); - -#if defined(ENABLE_JAVASE) -java_objectheader *exceptions_new_nosuchmethoderror(classinfo *c, - utf *name, utf *desc); +void exceptions_throw_classnotfoundexception(utf *name); +void exceptions_throw_noclassdeffounderror(utf *name); +void exceptions_throw_linkageerror(const char *message, classinfo *c); +void exceptions_throw_nosuchfielderror(classinfo *c, utf *name); void exceptions_throw_nosuchmethoderror(classinfo *c, utf *name, utf *desc); -#endif - +void exceptions_throw_exceptionininitializererror(java_objectheader *cause); +void exceptions_throw_incompatibleclasschangeerror(classinfo *c, + const char *message); +void exceptions_throw_instantiationerror(classinfo *c); void exceptions_throw_internalerror(const char *message, ...); - void exceptions_throw_outofmemoryerror(void); - -java_objectheader *exceptions_new_verifyerror(methodinfo *m, - const char *message, ...); void exceptions_throw_verifyerror(methodinfo *m, const char *message, ...); void exceptions_throw_verifyerror_for_stack(methodinfo *m, int type); +void exceptions_throw_virtualmachineerror(void); +void exceptions_throw_unsatisfiedlinkerror(utf *name); +void exceptions_throw_unsupportedclassversionerror(classinfo *c, u4 ma, u4 mi); -java_objectheader *exceptions_new_virtualmachineerror(void); -void exceptions_throw_virtualmachineerror(void); - -java_objectheader *new_unsupportedclassversionerror(classinfo *c, - const char *message, ...); +java_objectheader *exceptions_new_arithmeticexception(void); -java_objectheader *new_arithmeticexception(void); - -java_objectheader *new_arrayindexoutofboundsexception(s4 index); +java_objectheader *exceptions_new_arrayindexoutofboundsexception(s4 index); void exceptions_throw_arrayindexoutofboundsexception(void); - -java_objectheader *exceptions_new_arraystoreexception(void); void exceptions_throw_arraystoreexception(void); java_objectheader *exceptions_new_classcastexception(java_objectheader *o); -java_objectheader *new_illegalargumentexception(void); +void exceptions_throw_clonenotsupportedexception(void); +void exceptions_throw_illegalaccessexception(classinfo *c); void exceptions_throw_illegalargumentexception(void); - -java_objectheader *exceptions_new_illegalmonitorstateexception(void); -void exceptions_throw_illegalmonitorstateexception(void); - -java_objectheader *new_negativearraysizeexception(void); +void exceptions_throw_illegalmonitorstateexception(void); +void exceptions_throw_interruptedexception(void); +void exceptions_throw_instantiationexception(classinfo *c); +void exceptions_throw_invocationtargetexception(java_objectheader *cause); void exceptions_throw_negativearraysizeexception(void); java_objectheader *exceptions_new_nullpointerexception(void); void exceptions_throw_nullpointerexception(void); - -java_objectheader *exceptions_new_stringindexoutofboundsexception(void); void exceptions_throw_stringindexoutofboundsexception(void); void classnotfoundexception_to_noclassdeffounderror(void); +java_objectheader *exceptions_get_exception(void); +void exceptions_set_exception(java_objectheader *o); +void exceptions_clear_exception(void); java_objectheader *exceptions_get_and_clear_exception(void); void exceptions_print_exception(java_objectheader *xptr); +void exceptions_print_current_exception(void); #endif /* _EXCEPTIONS_H */ diff --git a/src/vm/field.c b/src/vm/field.c deleted file mode 100644 index 08eee657d..000000000 --- a/src/vm/field.c +++ /dev/null @@ -1,184 +0,0 @@ -/* src/vm/field.c - field functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Andreas Krall - Roman Obermaiser - Mark Probst - Edwin Steiner - Christian Thalinger - - $Id: field.c 4879 2006-05-05 17:34:49Z edwin $ - -*/ - - -#include "config.h" - -#include - -#include "vm/types.h" - -#include "vm/field.h" -#include "vm/utf8.h" - - -/* field_free ****************************************************************** - - Frees a fields' resources. - -*******************************************************************************/ - -void field_free(fieldinfo *f) -{ - /* empty */ -} - - -/* field_printflags ************************************************************ - - (debugging only) - -*******************************************************************************/ - -#if !defined(NDEBUG) -void field_printflags(fieldinfo *f) -{ - if (f == NULL) { - printf("NULL"); - return; - } - - if (f->flags & ACC_PUBLIC) printf(" PUBLIC"); - if (f->flags & ACC_PRIVATE) printf(" PRIVATE"); - if (f->flags & ACC_PROTECTED) printf(" PROTECTED"); - if (f->flags & ACC_STATIC) printf(" STATIC"); - if (f->flags & ACC_FINAL) printf(" FINAL"); - if (f->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED"); - if (f->flags & ACC_VOLATILE) printf(" VOLATILE"); - if (f->flags & ACC_TRANSIENT) printf(" TRANSIENT"); - if (f->flags & ACC_NATIVE) printf(" NATIVE"); - if (f->flags & ACC_INTERFACE) printf(" INTERFACE"); - if (f->flags & ACC_ABSTRACT) printf(" ABSTRACT"); -} -#endif - - -/* field_print ***************************************************************** - - (debugging only) - -*******************************************************************************/ - -#if !defined(NDEBUG) -void field_print(fieldinfo *f) -{ - if (f == NULL) { - printf("(fieldinfo*)NULL"); - return; - } - - utf_display_printable_ascii_classname(f->class->name); - printf("."); - utf_display_printable_ascii(f->name); - printf(" "); - utf_display_printable_ascii(f->descriptor); - - field_printflags(f); -} -#endif - - -/* field_println *************************************************************** - - (debugging only) - -*******************************************************************************/ - -#if !defined(NDEBUG) -void field_println(fieldinfo *f) -{ - field_print(f); - printf("\n"); -} -#endif - -/* field_fieldref_print ******************************************************** - - (debugging only) - -*******************************************************************************/ - -#if !defined(NDEBUG) -void field_fieldref_print(constant_FMIref *fr) -{ - if (fr == NULL) { - printf("(constant_FMIref *)NULL"); - return; - } - - if (IS_FMIREF_RESOLVED(fr)) { - printf(" "); - field_print(fr->p.field); - } - else { - printf(" "); - utf_display_printable_ascii_classname(fr->p.classref->name); - printf("."); - utf_display_printable_ascii(fr->name); - printf(" "); - utf_display_printable_ascii(fr->descriptor); - } -} -#endif - -/* field_fieldref_println ****************************************************** - - (debugging only) - -*******************************************************************************/ - -#if !defined(NDEBUG) -void field_fieldref_println(constant_FMIref *fr) -{ - field_fieldref_print(fr); - printf("\n"); -} -#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: - */ diff --git a/src/vm/field.h b/src/vm/field.h deleted file mode 100644 index 9847658d2..000000000 --- a/src/vm/field.h +++ /dev/null @@ -1,102 +0,0 @@ -/* src/vm/field.h - field functions header - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Christian Thalinger - - $Id: field.h 6012 2006-11-16 19:45:15Z twisti $ -*/ - - -#ifndef _FIELD_H -#define _FIELD_H - -/* forward typedefs ***********************************************************/ - -typedef struct fieldinfo fieldinfo; - - -#include "config.h" -#include "vm/types.h" - -#include "vm/global.h" -#include "vm/utf8.h" -#include "vm/references.h" -#include "vm/descriptor.h" - - -/* fieldinfo ******************************************************************/ - -struct fieldinfo { /* field of a class */ - - /* CAUTION: The first field must be a pointer that is never the same */ - /* value as CLASSREF_PSEUDO_VFTBL! This is used to check whether */ - /* a constant_FMIref has been resolved. */ - - classinfo *class; /* needed by typechecker. Could be optimized */ - /* away by using constant_FMIref instead of */ - /* fieldinfo throughout the compiler. */ - - s4 flags; /* ACC flags */ - s4 type; /* basic data type */ - utf *name; /* name of field */ - utf *descriptor;/* JavaVM descriptor string of field */ - utf *signature; /* Signature attribute string */ - typedesc *parseddesc;/* parsed descriptor */ - - s4 offset; /* offset from start of object (instance variables) */ - - imm_union value; /* storage for static values (class variables) */ -}; - - -/* function prototypes ********************************************************/ - -void field_free(fieldinfo *f); - -#if !defined(NDEBUG) -void field_printflags(fieldinfo *f); -void field_print(fieldinfo *f); -void field_println(fieldinfo *f); -void field_fieldref_print(constant_FMIref *fr); -void field_fieldref_println(constant_FMIref *fr); -#endif - -#endif /* _FIELD_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: - */ diff --git a/src/vm/finalizer.c b/src/vm/finalizer.c index 7f9632bd8..7154e8595 100644 --- a/src/vm/finalizer.c +++ b/src/vm/finalizer.c @@ -1,6 +1,6 @@ /* src/vm/finalizer.c - finalizer linked list and thread - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: finalizer.c 6251 2006-12-27 23:15:56Z twisti $ + $Id: finalizer.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -46,17 +42,20 @@ #endif #if defined(ENABLE_THREADS) +# include "threads/native/threads.h" # include "threads/native/lock.h" #endif #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" +#include "vmcore/options.h" + /* global variables ***********************************************************/ diff --git a/src/vm/hashtable.c b/src/vm/hashtable.c deleted file mode 100644 index a15d12301..000000000 --- a/src/vm/hashtable.c +++ /dev/null @@ -1,141 +0,0 @@ -/* src/vm/hashtable.c - functions for internal hashtables - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Mark Probst - Andreas Krall - Christian Thalinger - - $Id: hashtable.c 4921 2006-05-15 14:24:36Z twisti $ - -*/ - - -#include "config.h" -#include "vm/types.h" - -#include "mm/memory.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif - -#include "vm/hashtable.h" - - -/* hashtable_create ************************************************************ - - Initializes a hashtable structure and allocates memory. The - parameter size specifies the initial size of the hashtable. - -*******************************************************************************/ - -void hashtable_create(hashtable *hash, u4 size) -{ - /* initialize locking pointer */ - -#if defined(ENABLE_THREADS) - /* We need to seperately allocate a java_objectheader here, as we - need to store the lock object in the new hashtable if it's - resized. Otherwise we get an IllegalMonitorStateException. */ - - hash->header = NEW(java_objectheader); - - lock_init_object_lock(hash->header); -#endif - - /* set initial hash values */ - - hash->size = size; - hash->entries = 0; - hash->ptr = MNEW(void*, size); - - /* MNEW always allocates memory zeroed out, no need to clear the table */ -} - - -/* hashtable_resize ************************************************************ - - Creates a new hashtable with specified size and moves the important - stuff from the old hashtable. - -*******************************************************************************/ - -hashtable *hashtable_resize(hashtable *hash, u4 size) -{ - hashtable *newhash; - - /* create new hashtable with specified size */ - - newhash = NEW(hashtable); - - hashtable_create(newhash, size); - -#if defined(ENABLE_THREADS) - /* We need to store the old lock object in the new hashtable. - Otherwise we get an IllegalMonitorStateException. */ - - FREE(newhash->header, java_objectheader); - - newhash->header = hash->header; -#endif - - /* store the number of entries in the new hashtable */ - - newhash->entries = hash->entries; - - return newhash; -} - - -/* hashtable_free ************************************************************** - - Simply frees the hashtable. - - ATTENTION: It does NOT free the lock object! - -*******************************************************************************/ - -void hashtable_free(hashtable *hash) -{ - MFREE(hash->ptr, void*, hash->size); - FREE(hash, hashtable); -} - - -/* - * 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: - */ diff --git a/src/vm/hashtable.h b/src/vm/hashtable.h deleted file mode 100644 index 7f718c258..000000000 --- a/src/vm/hashtable.h +++ /dev/null @@ -1,137 +0,0 @@ -/* src/vm/hashtable.h - functions for internal hashtables - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Christian Thalinger - - $Id: hashtable.h 4921 2006-05-15 14:24:36Z twisti $ - -*/ - - -#ifndef _HASHTABLE_H -#define _HASHTABLE_H - -/* forward typedefs ***********************************************************/ - -typedef struct hashtable hashtable; - -#include "config.h" -#include "vm/types.h" - -#include "vm/utf8.h" - - -/* data structures for hashtables ******************************************** - - All utf-symbols, javastrings and classes are stored in global - hashtables, so every symbol exists only once. Equal symbols have - identical pointers. The functions for adding hashtable elements - search the table for the element with the specified name/text and - return it on success. Otherwise a new hashtable element is created. - - The hashtables use external linking for handling collisions. The - hashtable structure contains a pointer to the array of - hashtable slots. The number of hashtable slots and therefore the - size of this array is specified by the element of hashtable - structure. contains the number of all hashtable elements - stored in the table, including those in the external chains. The - hashtable element structures (utf, literalstring, classinfo) - contain both a pointer to the next hashtable element as a link for - the external hash chain and the key of the element. The key is - computed from the text of the string or the classname by using up - to 8 characters. - - If the number of entries in the hashtable exceeds twice the size of - the hashtableslot-array it is supposed that the average length of - the external chains has reached a value beyond 2. Therefore the - functions for adding hashtable elements (utf_new, class_new, - literalstring_new) double the hashtableslot-array. In this - restructuring process all elements have to be inserted into the new - hashtable and new external chains must be built. - - Example for the layout of a hashtable: - -hashtable.ptr-->+-------------------+ - | | - ... - | | - +-------------------+ +-------------------+ +-------------------+ - | hashtable element |-->| hashtable element |-->| hashtable element |-->NULL - +-------------------+ +-------------------+ +-------------------+ - | hashtable element | - +-------------------+ +-------------------+ - | hashtable element |-->| hashtable element |-->NULL - +-------------------+ +-------------------+ - | hashtable element |-->NULL - +-------------------+ - | | - ... - | | - +-------------------+ - -*/ - - -/* hashtable ******************************************************************/ - -struct hashtable { -#if defined(ENABLE_THREADS) - java_objectheader *header; /* required for locking */ -#endif - u4 size; /* current size of the hashtable */ - u4 entries; /* number of entries in the table */ - void **ptr; /* pointer to hashtable */ -}; - - -/* function prototypes ********************************************************/ - -/* create hashtable */ -void hashtable_create(hashtable *hash, u4 size); - -/* creates and resizes a hashtable */ -hashtable *hashtable_resize(hashtable *hash, u4 size); - -/* frees a hashtable */ -void hashtable_free(hashtable *hash); - -#endif /* _HASHTABLE_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: - */ diff --git a/src/vm/initialize.c b/src/vm/initialize.c index c3a86b719..366f85f9d 100644 --- a/src/vm/initialize.c +++ b/src/vm/initialize.c @@ -1,6 +1,6 @@ /* src/vm/initialize.c - static class initializer functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Mark Probst - Andreas Krall - Christian Thalinger - - $Id: initialize.c 5123 2006-07-12 21:45:34Z twisti $ + $Id: initialize.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -50,15 +42,20 @@ #include "vm/global.h" #include "vm/initialize.h" #include "vm/builtin.h" -#include "vm/class.h" -#include "vm/loader.h" #include "vm/exceptions.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + /* private functions **********************************************************/ @@ -95,7 +92,7 @@ bool initialize_class(classinfo *c) error and we have to throw a NoClassDefFoundError */ if (c->state & CLASS_ERROR) { - *exceptionptr = new_noclassdeffounderror(c->name); + exceptions_throw_noclassdeffounderror(c->name); LOCK_MONITOR_EXIT(c); @@ -196,9 +193,9 @@ static bool initialize_class_intern(classinfo *c) /* we have an exception or error */ - xptr = *exceptionptr; + xptr = exceptions_get_exception(); - if (xptr) { + if (xptr != NULL) { /* class is NOT initialized and is marked with error */ c->state |= CLASS_ERROR; @@ -208,13 +205,11 @@ static bool initialize_class_intern(classinfo *c) if (builtin_instanceof(xptr, class_java_lang_Exception)) { /* clear exception, because we are calling jit code again */ - *exceptionptr = NULL; + exceptions_clear_exception(); /* wrap the exception */ - *exceptionptr = - new_exception_throwable(string_java_lang_ExceptionInInitializerError, - (java_lang_Throwable *) xptr); + exceptions_throw_exceptionininitializererror(xptr); } return false; diff --git a/src/vm/initialize.h b/src/vm/initialize.h index bc1f7cc0e..39ecc07a0 100644 --- a/src/vm/initialize.h +++ b/src/vm/initialize.h @@ -1,6 +1,6 @@ /* src/vm/initialize.h - static class initializer functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Mark Probst - Andreas Krall - Christian Thalinger - - $Id: initialize.h 4357 2006-01-22 23:33:38Z twisti $ + $Id: initialize.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -38,8 +30,11 @@ #ifndef _INITIALIZE_H #define _INITIALIZE_H +#include "config.h" + #include "vm/global.h" -#include "vm/references.h" + +#include "vmcore/references.h" /* function prototypes ********************************************************/ diff --git a/src/vm/jit/abi.h b/src/vm/jit/abi.h index 1725e17b3..a28d936f3 100644 --- a/src/vm/jit/abi.h +++ b/src/vm/jit/abi.h @@ -1,6 +1,6 @@ /* src/vm/jit/abi.h - common ABI defines - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: abi.h 5079 2006-07-06 11:36:01Z twisti $ + $Id: abi.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -40,6 +34,7 @@ #include "vm/types.h" #include "vm/jit/abi-asm.h" +#include "vm/jit/jit.h" /* ABI externs ****************************************************************/ diff --git a/src/vm/jit/allocator/simplereg.c b/src/vm/jit/allocator/simplereg.c index a6b148a07..f3557e08a 100644 --- a/src/vm/jit/allocator/simplereg.c +++ b/src/vm/jit/allocator/simplereg.c @@ -22,39 +22,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Contact: cacao@complang.tuwien.ac.at - - Authors: Andreas Krall - Stefan Ring - Christian Thalinger - Christian Ullrich - Michael Starzinger - Edwin Steiner - - $Id: simplereg.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: simplereg.c 7246 2007-01-29 18:49:05Z twisti $ */ #include "config.h" -#include "vm/types.h" #include +#include "vm/types.h" + #include "arch.h" #include "md-abi.h" +#include "mm/memory.h" + #include "vm/builtin.h" #include "vm/exceptions.h" -#include "mm/memory.h" -#include "vm/method.h" -#include "vm/options.h" -#include "vm/resolve.h" #include "vm/stringlocal.h" + #include "vm/jit/reg.h" #include "vm/jit/allocator/simplereg.h" #include "vm/jit/show.h" +#include "vmcore/method.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + #if 0 # define LOG(args) printf args diff --git a/src/vm/jit/asmpart.h b/src/vm/jit/asmpart.h index 1702d5e49..27a50dd0e 100644 --- a/src/vm/jit/asmpart.h +++ b/src/vm/jit/asmpart.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: asmpart.h 7216 2007-01-16 09:54:47Z twisti $ + $Id: asmpart.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -33,18 +33,16 @@ #include "config.h" #include "vm/types.h" - #if defined(ENABLE_THREADS) -# include "threads/native/threads.h" # include "threads/native/critical.h" #endif #include "vm/global.h" -#include "vm/linker.h" -#include "vm/resolve.h" #include "vm/vm.h" + #include "vm/jit/replace.h" -#include "vm/jit/stacktrace.h" + +#include "vmcore/linker.h" /* some macros ****************************************************************/ diff --git a/src/vm/jit/code.c b/src/vm/jit/code.c index d106b8985..abe156557 100644 --- a/src/vm/jit/code.c +++ b/src/vm/jit/code.c @@ -1,6 +1,6 @@ /* src/vm/jit/code.c - codeinfo struct for representing compiled code - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -40,12 +40,11 @@ #include "arch.h" +#include "mm/memory.h" #include "vm/jit/code.h" #include "vm/jit/codegen-common.h" #include "vm/jit/methodheader.h" -#include "mm/memory.h" -#include "vm/options.h" -#include "vm/jit/code.h" +#include "vmcore/options.h" /* code_init ******************************************************************* diff --git a/src/vm/jit/code.h b/src/vm/jit/code.h index 60ad5147e..aab97eaf7 100644 --- a/src/vm/jit/code.h +++ b/src/vm/jit/code.h @@ -1,6 +1,6 @@ /* src/vm/jit/code.h - codeinfo struct for representing compiled code - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - Christian Thalinger - $Id$ */ @@ -43,9 +38,11 @@ typedef struct codeinfo codeinfo; #include "vm/types.h" #include "vm/global.h" -#include "vm/method.h" + #include "vm/jit/replace.h" +#include "vmcore/method.h" + /* constants ******************************************************************/ diff --git a/src/vm/jit/codegen-common.c b/src/vm/jit/codegen-common.c index 5ef123e39..2eb113e71 100644 --- a/src/vm/jit/codegen-common.c +++ b/src/vm/jit/codegen-common.c @@ -39,7 +39,7 @@ memory. All functions writing values into the data area return the offset relative the begin of the code area (start of procedure). - $Id: codegen-common.c 7229 2007-01-22 00:58:36Z twisti $ + $Id: codegen-common.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -62,9 +62,11 @@ #endif #include "mm/memory.h" + #include "toolbox/avl.h" #include "toolbox/list.h" #include "toolbox/logging.h" + #include "native/jni.h" #include "native/native.h" @@ -73,10 +75,8 @@ #endif #include "vm/exceptions.h" -#include "vm/method.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" + #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" @@ -94,6 +94,13 @@ #include "vm/jit/intrp/intrp.h" #endif +#include "vmcore/method.h" +#include "vmcore/options.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + /* in this tree we store all method addresses *********************************/ diff --git a/src/vm/jit/codegen-common.h b/src/vm/jit/codegen-common.h index 649665b95..6776b122e 100644 --- a/src/vm/jit/codegen-common.h +++ b/src/vm/jit/codegen-common.h @@ -1,6 +1,6 @@ /* src/vm/jit/codegen-common.h - architecture independent code generator stuff - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Christian Ullrich - Edwin Steiner - - $Id: codegen-common.h 6265 2007-01-02 20:40:57Z edwin $ + $Id: codegen-common.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -51,14 +45,17 @@ typedef struct linenumberref linenumberref; #include "vm/types.h" #include "vm/global.h" -#include "vm/references.h" -#include "vm/method.h" + #include "vm/jit/dseg.h" #include "vm/jit/jit.h" #include "vm/jit/reg.h" #include "vm/jit/code.h" #include "vm/jit/replace.h" +#include "vmcore/descriptor.h" +#include "vmcore/method.h" +#include "vmcore/references.h" + #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */ #define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */ diff --git a/src/vm/jit/dseg.c b/src/vm/jit/dseg.c index 83e26b57e..abacc3737 100644 --- a/src/vm/jit/dseg.c +++ b/src/vm/jit/dseg.c @@ -1,6 +1,6 @@ /* src/vm/jit/dseg.c - data segment handling stuff - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -30,7 +30,7 @@ Joseph Wenninger Edwin Steiner - $Id: dseg.c 6077 2006-11-28 22:04:29Z twisti $ + $Id: dseg.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -39,12 +39,12 @@ #include -#include "vm/options.h" #include "vm/types.h" #include "mm/memory.h" #include "vm/jit/codegen-common.h" #include "vm/jit/methodheader.h" +#include "vmcore/options.h" /* dseg_finish ***************************************************************** diff --git a/src/vm/jit/dseg.h b/src/vm/jit/dseg.h index 228f742a9..e0f6a9d4f 100644 --- a/src/vm/jit/dseg.h +++ b/src/vm/jit/dseg.h @@ -1,6 +1,6 @@ /* src/vm/jit/dseg.c - data segment handling stuff - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,14 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Andreas Krall - Christian Thalinger - Joseph Wenninger - - $Id: dseg.h 6091 2006-11-29 20:44:10Z twisti $ + $Id: dseg.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -45,13 +38,15 @@ typedef struct dseg_exception_entry dseg_exception_entry; #include "config.h" - #include "vm/types.h" #include "toolbox/list.h" + #include "vm/jit/jit.h" #include "vm/jit/codegen-common.h" +#include "vmcore/references.h" + /* convenience macros *********************************************************/ diff --git a/src/vm/jit/emit-common.c b/src/vm/jit/emit-common.c index a31da52be..d9ca2ea40 100644 --- a/src/vm/jit/emit-common.c +++ b/src/vm/jit/emit-common.c @@ -1,6 +1,6 @@ /* src/vm/jit/emit-common.c - common code emitter functions - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Edwin Steiner - $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $ */ @@ -40,15 +35,14 @@ #include "codegen.h" -#include "vm/options.h" +#include "vm/jit/emit-common.h" +#include "vm/jit/jit.h" +#include "vmcore/options.h" #if defined(ENABLE_STATISTICS) -# include "vm/statistics.h" +# include "vmcore/statistics.h" #endif -#include "vm/jit/emit-common.h" -#include "vm/jit/jit.h" - /* emit_load_s1 **************************************************************** diff --git a/src/vm/jit/jit.c b/src/vm/jit/jit.c index ea2db8de6..edfa2c79d 100644 --- a/src/vm/jit/jit.c +++ b/src/vm/jit/jit.c @@ -22,16 +22,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: jit.c 7229 2007-01-22 00:58:36Z twisti $ + $Id: jit.c 7246 2007-01-29 18:49:05Z twisti $ */ #include "config.h" -#include "vm/types.h" #include +#include "vm/types.h" + #include "mm/memory.h" #include "native/native.h" #include "toolbox/logging.h" @@ -42,13 +43,9 @@ # include "threads/none/lock.h" #endif -#include "vm/class.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/loader.h" -#include "vm/method.h" -#include "vm/options.h" -#include "vm/statistics.h" + #include "vm/jit/asmpart.h" # include "vm/jit/cfg.h" @@ -84,12 +81,21 @@ #include "vm/jit/optimizing/reorder.h" #include "vm/jit/verify/typecheck.h" -#include "vm/rt-timing.h" #if defined(ENABLE_THREADS) # include "threads/native/threads.h" #endif +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/method.h" +#include "vmcore/options.h" +#include "vmcore/rt-timing.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + /* debug macros ***************************************************************/ diff --git a/src/vm/jit/jit.h b/src/vm/jit/jit.h index 1fa0febe0..e95124956 100644 --- a/src/vm/jit/jit.h +++ b/src/vm/jit/jit.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: jit.h 7229 2007-01-22 00:58:36Z twisti $ + $Id: jit.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -46,14 +46,11 @@ typedef struct exception_entry exception_entry; #include "vm/types.h" #include "toolbox/chain.h" + #include "vm/global.h" -#include "vm/method.h" -#include "vm/references.h" -#include "vm/resolve.h" -#include "vm/statistics.h" + #include "vm/jit/codegen-common.h" #include "vm/jit/reg.h" -#include "vm/jit/stacktrace.h" #include "vm/jit/replace.h" #if defined(ENABLE_INLINING) @@ -72,6 +69,15 @@ typedef struct exception_entry exception_entry; #include "vm/jit/verify/typeinfo.h" +#include "vmcore/method.h" +#include "vmcore/references.h" +#include "vmcore/resolve.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + + /* common jit/codegen macros **************************************************/ #if defined(ENABLE_STATISTICS) diff --git a/src/vm/jit/loop/graph.h b/src/vm/jit/loop/graph.h index bdebe6198..e8facd393 100644 --- a/src/vm/jit/loop/graph.h +++ b/src/vm/jit/loop/graph.h @@ -1,6 +1,6 @@ /* src/vm/jit/loop/graph.h - control flow graph header - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: graph.h 4699 2006-03-28 14:52:32Z twisti $ + $Id: graph.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -39,9 +33,10 @@ #include "config.h" #include "vm/types.h" -#include "vm/method.h" #include "vm/jit/loop/loop.h" +#include "vmcore/method.h" + /* function prototypes ********************************************************/ diff --git a/src/vm/jit/loop/loop.h b/src/vm/jit/loop/loop.h index 16b121951..3d791e0e7 100644 --- a/src/vm/jit/loop/loop.h +++ b/src/vm/jit/loop/loop.h @@ -1,6 +1,6 @@ -/* vm/jit/loop/loop.h - array bound removal header +/* src/vm/jit/loop/loop.h - array bound removal header - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christopher Kruegel - - Changes: Christian Thalinger - - $Id: loop.h 5785 2006-10-15 22:25:54Z edwin $ + $Id: loop.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -40,9 +34,11 @@ #include "vm/types.h" #include "vm/global.h" -#include "vm/method.h" + #include "vm/jit/jit.h" +#include "vmcore/method.h" + /* Different types for struct Trace */ #define TRACE_UNKNOWN 0 /* unknown */ diff --git a/src/vm/jit/optimizing/ifconv.c b/src/vm/jit/optimizing/ifconv.c index 2a778ac2e..a80946728 100644 --- a/src/vm/jit/optimizing/ifconv.c +++ b/src/vm/jit/optimizing/ifconv.c @@ -1,6 +1,6 @@ /* src/vm/jit/ifconv/ifconv.c - if-conversion - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: stack.c 4455 2006-02-06 01:02:59Z edwin $ */ @@ -39,12 +33,13 @@ #include "vm/types.h" -#include "vm/method.h" #include "vm/jit/codegen-common.h" #include "vm/jit/jit.h" #include "vm/jit/reg.h" #include "vm/jit/show.h" +#include "vmcore/method.h" + /* patterns for a total number of 3 instructions ******************************/ diff --git a/src/vm/jit/optimizing/ifconv.h b/src/vm/jit/optimizing/ifconv.h index 03865ce20..d1f185d14 100644 --- a/src/vm/jit/optimizing/ifconv.h +++ b/src/vm/jit/optimizing/ifconv.h @@ -1,6 +1,6 @@ -/* src/vm/jit/ifconv/ifconv.h - if-conversion +/* src/vm/jit/optimizing/ifconv.h - if-conversion - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: stack.c 4455 2006-02-06 01:02:59Z edwin $ */ @@ -39,11 +33,12 @@ #include "config.h" #include "vm/types.h" -#include "vm/method.h" #include "vm/jit/codegen-common.h" #include "vm/jit/jit.h" #include "vm/jit/reg.h" +#include "vmcore/method.h" + /* function prototypes ********************************************************/ diff --git a/src/vm/jit/optimizing/profile.c b/src/vm/jit/optimizing/profile.c index cf5771c95..7b6a66ebc 100644 --- a/src/vm/jit/optimizing/profile.c +++ b/src/vm/jit/optimizing/profile.c @@ -1,6 +1,6 @@ /* src/vm/jit/optimizing/profile.c - runtime profiling - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - $Id: cacao.c 4357 2006-01-22 23:33:38Z twisti $ */ @@ -41,6 +35,7 @@ #include "vm/types.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/include/java_lang_Thread.h" #include "native/include/java_lang_VMThread.h" @@ -50,15 +45,17 @@ #endif #include "vm/builtin.h" -#include "vm/class.h" -#include "vm/classcache.h" -#include "vm/method.h" -#include "vm/options.h" #include "vm/stringlocal.h" + #include "vm/jit/jit.h" #include "vm/jit/methodheader.h" #include "vm/jit/optimizing/recompile.h" +#include "vmcore/class.h" +#include "vmcore/classcache.h" +#include "vmcore/method.h" +#include "vmcore/options.h" + /* global variables ***********************************************************/ diff --git a/src/vm/jit/optimizing/recompile.c b/src/vm/jit/optimizing/recompile.c index ad9517743..b92d4655f 100644 --- a/src/vm/jit/optimizing/recompile.c +++ b/src/vm/jit/optimizing/recompile.c @@ -1,6 +1,6 @@ /* src/vm/jit/optimizing/recompile.c - recompilation system - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,10 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - $Id: cacao.c 4357 2006-01-22 23:33:38Z twisti $ */ @@ -39,6 +35,7 @@ #include "vm/types.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/include/java_lang_Thread.h" @@ -52,12 +49,15 @@ #endif #include "toolbox/list.h" + #include "vm/builtin.h" -#include "vm/classcache.h" #include "vm/exceptions.h" #include "vm/stringlocal.h" + #include "vm/jit/optimizing/recompile.h" +#include "vmcore/classcache.h" + /* global variables ***********************************************************/ @@ -196,7 +196,7 @@ static void recompile_thread(void) else { /* XXX what is the right-thing(tm) to do here? */ - exceptions_print_exception(*exceptionptr); + exceptions_print_current_exception(); } /* remove the compiled method */ diff --git a/src/vm/jit/parse.c b/src/vm/jit/parse.c index 1d694427c..655f6c6e4 100644 --- a/src/vm/jit/parse.c +++ b/src/vm/jit/parse.c @@ -1,6 +1,6 @@ /* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Andreas Krall - Carolyn Oates - Edwin Steiner - Joseph Wenninger - Christian Thalinger - - $Id: parse.c 6175 2006-12-11 20:16:10Z twisti $ + $Id: parse.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -50,22 +42,29 @@ #endif #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/resolve.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" -#include "vm/suck.h" + #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" #include "vm/jit/parse.h" #include "vm/jit/patcher.h" #include "vm/jit/loop/loop.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#include "vmcore/suck.h" + #define INSTRUCTIONS_INCREMENT 5 /* number of additional instructions to */ /* allocate if space runs out */ diff --git a/src/vm/jit/powerpc/codegen.c b/src/vm/jit/powerpc/codegen.c index 057f29336..eeba56943 100644 --- a/src/vm/jit/powerpc/codegen.c +++ b/src/vm/jit/powerpc/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/codegen.c - machine code generator for 32-bit PowerPC - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Andreas Krall - Stefan Ring - Christian Thalinger - Christian Ullrich - Edwin Steiner - - $Id: codegen.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: codegen.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -58,26 +50,30 @@ #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/abi-asm.h" #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.h" +#include "vm/jit/md.h" #include "vm/jit/methodheader.h" #include "vm/jit/parse.h" #include "vm/jit/patcher.h" #include "vm/jit/reg.h" #include "vm/jit/replace.h" +#include "vm/jit/stacktrace.h" #if defined(ENABLE_LSRA) # include "vm/jit/allocator/lsra.h" #endif +#include "vmcore/loader.h" +#include "vmcore/options.h" + /* codegen ********************************************************************* diff --git a/src/vm/jit/powerpc/emit.c b/src/vm/jit/powerpc/emit.c index 4b5aa1570..86b57d782 100644 --- a/src/vm/jit/powerpc/emit.c +++ b/src/vm/jit/powerpc/emit.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/emit.c - PowerPC code emitter functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,10 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - $Id: emit.c 4398 2006-01-31 23:43:08Z twisti $ */ @@ -42,15 +38,22 @@ #include "vm/jit/powerpc/codegen.h" #include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + #include "vm/builtin.h" #include "vm/exceptions.h" -#include "vm/options.h" + #include "vm/jit/asmpart.h" #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.h" #include "vm/jit/replace.h" +#include "vmcore/options.h" + /* emit_load ******************************************************************* diff --git a/src/vm/jit/powerpc/linux/md-abi.c b/src/vm/jit/powerpc/linux/md-abi.c index 13b64bf9e..83ec65ab0 100644 --- a/src/vm/jit/powerpc/linux/md-abi.c +++ b/src/vm/jit/powerpc/linux/md-abi.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/linux/md-abi.c - functions for PowerPC Linux ABI - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Christian Ullrich - - $Id: md-abi.c 5634 2006-10-02 14:18:04Z edwin $ + $Id: md-abi.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -38,10 +32,12 @@ #include "vm/jit/powerpc/linux/md-abi.h" -#include "vm/descriptor.h" #include "vm/global.h" + #include "vm/jit/abi.h" +#include "vmcore/descriptor.h" + #define _ALIGN(a) do { if ((a) & 1) (a)++; } while (0) diff --git a/src/vm/jit/powerpc/md.c b/src/vm/jit/powerpc/md.c index 8e6b0e84f..3ec67f021 100644 --- a/src/vm/jit/powerpc/md.c +++ b/src/vm/jit/powerpc/md.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/md.c - machine dependent PowerPC functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Edwin Steiner - - $Id: md.c 6265 2007-01-02 20:40:57Z edwin $ + $Id: md.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -42,11 +37,13 @@ #include "vm/jit/powerpc/codegen.h" #include "vm/global.h" + #include "vm/jit/asmpart.h" +#include "vm/jit/stacktrace.h" #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) -#include "vm/options.h" /* XXX debug */ -#include "vm/jit/disass.h" /* XXX debug */ +# include "vm/jit/disass.h" /* XXX debug */ +# include "vmcore/options.h" /* XXX debug */ #endif diff --git a/src/vm/jit/powerpc/patcher.c b/src/vm/jit/powerpc/patcher.c index 0996932a3..e7a136062 100644 --- a/src/vm/jit/powerpc/patcher.c +++ b/src/vm/jit/powerpc/patcher.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/patcher.c - PowerPC code patching functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: patcher.c 5942 2006-11-09 10:52:34Z twisti $ + $Id: patcher.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,17 +35,22 @@ #include "mm/memory.h" #include "native/native.h" + #include "vm/builtin.h" -#include "vm/class.h" #include "vm/exceptions.h" -#include "vm/field.h" #include "vm/initialize.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/references.h" + #include "vm/jit/asmpart.h" #include "vm/jit/patcher.h" +#include "vm/jit/md.h" #include "vm/jit/methodheader.h" +#include "vm/jit/stacktrace.h" + +#include "vmcore/class.h" +#include "vmcore/field.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" +#include "vmcore/references.h" /* patcher_wrapper ************************************************************* diff --git a/src/vm/jit/show.c b/src/vm/jit/show.c index 4410e3f73..3781ba2ea 100644 --- a/src/vm/jit/show.c +++ b/src/vm/jit/show.c @@ -1,6 +1,6 @@ /* src/vm/jit/show.c - showing the intermediate representation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,23 +22,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Andreas Krall - Edwin Steiner - Christian Thalinger - Christian Ullrich - $Id$ */ #include "config.h" -#include "vm/types.h" #include +#include "vm/types.h" + #include "mm/memory.h" #if defined(ENABLE_THREADS) @@ -48,7 +42,6 @@ #endif #include "vm/global.h" -#include "vm/options.h" #include "vm/builtin.h" #include "vm/stringlocal.h" #include "vm/jit/jit.h" @@ -56,6 +49,7 @@ #include "vm/jit/disass.h" #include "vm/jit/stack.h" #include "vm/jit/parse.h" +#include "vmcore/options.h" /* global variables ***********************************************************/ @@ -694,7 +688,7 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage) if (stage >= SHOW_PARSE) { \ putchar('"'); \ utf_display_printable_ascii( \ - javastring_toutf((java_lang_String *)(val), false)); \ + javastring_toutf((java_objectheader *)(val), false)); \ printf("\" "); \ } \ else { \ diff --git a/src/vm/jit/stack.c b/src/vm/jit/stack.c index 5be8d7501..14b18ac4f 100644 --- a/src/vm/jit/stack.c +++ b/src/vm/jit/stack.c @@ -22,14 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Andreas Krall - Edwin Steiner - Christian Thalinger - Christian Ullrich - - $Id: stack.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: stack.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -52,9 +45,6 @@ #include "vm/global.h" #include "vm/builtin.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" #include "vm/types.h" @@ -78,6 +68,13 @@ # include "vm/jit/allocator/lsra.h" #endif +#include "vmcore/options.h" +#include "vmcore/resolve.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + /*#define STACK_VERBOSE*/ diff --git a/src/vm/jit/stacktrace.c b/src/vm/jit/stacktrace.c index beaae0c77..e79ee038e 100644 --- a/src/vm/jit/stacktrace.c +++ b/src/vm/jit/stacktrace.c @@ -1,6 +1,6 @@ /* src/vm/jit/stacktrace.c - machine independent stacktrace system - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Joseph Wenninger - Christian Thalinger - Edwin Steiner - - $Id: stacktrace.c 6251 2006-12-27 23:15:56Z twisti $ + $Id: stacktrace.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -43,9 +37,9 @@ #include "mm/gc-common.h" #include "mm/memory.h" -#include "native/native.h" #include "vm/global.h" /* required here for native includes */ +#include "native/jni.h" #include "native/include/java_lang_Throwable.h" #if defined(WITH_CLASSPATH_GNU) @@ -59,17 +53,20 @@ #endif #include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/class.h" +#include "vm/cycles-stats.h" #include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" #include "vm/jit/methodheader.h" -#include "vm/cycles-stats.h" + +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" /* global variables ***********************************************************/ @@ -349,7 +346,7 @@ java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp, /* create exception */ - o = new_arithmeticexception(); + o = exceptions_new_arithmeticexception(); /* remove stackframeinfo */ @@ -380,7 +377,7 @@ java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv, /* create exception */ - o = new_arrayindexoutofboundsexception(index); + o = exceptions_new_arrayindexoutofboundsexception(index); /* remove stackframeinfo */ @@ -546,7 +543,7 @@ java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp, /* create exception */ - o = new_arithmeticexception(); + o = exceptions_new_arithmeticexception(); /* remove stackframeinfo */ @@ -1167,15 +1164,15 @@ return_NULL: #if defined(ENABLE_JAVASE) java_objectarray *stacktrace_getStack(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - java_objectarray *oa; - java_objectarray *classes; - java_objectarray *methodnames; - classinfo *c; - java_lang_String *str; - s4 i; - s4 dumpsize; + stacktracebuffer *stb; + stacktrace_entry *ste; + java_objectarray *oa; + java_objectarray *classes; + java_objectarray *methodnames; + classinfo *c; + java_objectheader *string; + s4 i; + s4 dumpsize; CYCLES_STATS_DECLARE_AND_START /* mark start of dump memory area */ @@ -1221,12 +1218,13 @@ java_objectarray *stacktrace_getStack(void) c = ste->method->class; classes->data[i] = (java_objectheader *) c; - str = javastring_new(ste->method->name); - if (str == NULL) + string = javastring_new(ste->method->name); + + if (string == NULL) goto return_NULL; - methodnames->data[i] = (java_objectheader *) str; + methodnames->data[i] = string; } /* return the 2-dimensional array */ @@ -1300,28 +1298,6 @@ void stacktrace_dump_trace(threadobject *thread) stacktracebuffer *stb; s4 dumpsize; -#if 0 - /* get methodinfo pointer from data segment */ - - m = *((methodinfo **) (pv + MethodPointer)); - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; - - /* fill new stackframe info structure */ - - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = NULL; - sfi->sp = sp; - sfi->ra = ra; - - /* store new stackframe info pointer */ - - *psfi = sfi; -#endif - /* mark start of dump memory area */ dumpsize = dump_size(); @@ -1332,7 +1308,7 @@ void stacktrace_dump_trace(threadobject *thread) /* print stacktrace */ - if (stb) + if (stb != NULL) stacktrace_print_trace_from_buffer(stb); else { puts("\t<>"); diff --git a/src/vm/jit/stacktrace.h b/src/vm/jit/stacktrace.h index c8e325796..2372ddd4c 100644 --- a/src/vm/jit/stacktrace.h +++ b/src/vm/jit/stacktrace.h @@ -1,6 +1,6 @@ /* src/vm/jit/stacktrace.h - header file for stacktrace generation - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: stacktrace.h 6248 2006-12-27 22:39:39Z twisti $ + $Id: stacktrace.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -51,7 +45,8 @@ typedef struct stacktrace_entry stacktrace_entry; # include "threads/none/threads.h" #endif -#include "vm/method.h" +#include "vmcore/class.h" +#include "vmcore/method.h" /* stackframeinfo ************************************************************** @@ -70,14 +65,6 @@ struct stackframeinfo { u1 *xpc; /* XPC (for inline stubs) */ }; -#if defined(ENABLE_THREADS) -#define STACKFRAMEINFO (&(THREADOBJECT->_stackframeinfo)) -#else -extern stackframeinfo *_no_threads_stackframeinfo; - -#define STACKFRAMEINFO (&_no_threads_stackframeinfo) -#endif - /* stacktrace_entry ***********************************************************/ diff --git a/src/vm/jit/tools/genoffsets.c b/src/vm/jit/tools/genoffsets.c index 38d077d35..d3e86d2e9 100644 --- a/src/vm/jit/tools/genoffsets.c +++ b/src/vm/jit/tools/genoffsets.c @@ -1,6 +1,6 @@ /* src/vm/jit/tools/genoffsets.c - generate asmpart offsets of structures - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Edwin Steiner - - $Id: genoffsets.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: genoffsets.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -40,15 +34,18 @@ #include "vm/types.h" #include "mm/memory.h" -#include "vm/class.h" + #include "vm/global.h" -#include "vm/linker.h" -#include "vm/method.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/stacktrace.h" #include "vm/jit/replace.h" +#include "vmcore/class.h" +#include "vmcore/linker.h" +#include "vmcore/method.h" + int main(int argc, char **argv) { diff --git a/src/vm/jit/verify/typecheck-stackbased.c b/src/vm/jit/verify/typecheck-stackbased.c index 9abb9a7cf..a2c909ded 100644 --- a/src/vm/jit/verify/typecheck-stackbased.c +++ b/src/vm/jit/verify/typecheck-stackbased.c @@ -1,6 +1,6 @@ /* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,12 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - $Id$ */ @@ -39,8 +33,11 @@ #include "vm/types.h" +#include "vm/builtin.h" #include "mm/memory.h" + #include "vm/global.h" + #include "vm/jit/parse.h" #include "vm/jit/show.h" #include "vm/jit/stack.h" diff --git a/src/vm/jit/verify/typecheck-typeinferer.c b/src/vm/jit/verify/typecheck-typeinferer.c index 6ea736eb2..d300c8571 100644 --- a/src/vm/jit/verify/typecheck-typeinferer.c +++ b/src/vm/jit/verify/typecheck-typeinferer.c @@ -1,6 +1,6 @@ /* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,10 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - $Id$ */ @@ -40,19 +36,23 @@ #include "mm/memory.h" #include "toolbox/logging.h" #include "native/native.h" + +#include "vm/access.h" #include "vm/builtin.h" +#include "vm/exceptions.h" +#include "vm/vm.h" + #include "vm/jit/patcher.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/jit/jit.h" #include "vm/jit/show.h" #include "vm/jit/parse.h" -#include "vm/access.h" -#include "vm/resolve.h" -#include "vm/exceptions.h" -#include "vm/vm.h" + #include "vm/jit/verify/typecheck-typeinferer.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + #define TYPECHECK_NO_STATISTICS #include diff --git a/src/vm/jit/verify/typecheck.c b/src/vm/jit/verify/typecheck.c index da521e1b1..4720feba3 100644 --- a/src/vm/jit/verify/typecheck.c +++ b/src/vm/jit/verify/typecheck.c @@ -1,6 +1,6 @@ /* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification) - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: Christian Thalinger - - $Id: typecheck.c 6275 2007-01-03 22:39:14Z edwin $ + $Id: typecheck.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -141,28 +135,34 @@ error reporting. citeseer.ist.psu.edu/article/coglio03improving.html */ + #include "config.h" -#include "vm/types.h" -#include "vm/global.h" #include #include +#include "vm/types.h" + #ifdef ENABLE_VERIFIER #include "mm/memory.h" -#include "toolbox/logging.h" #include "native/native.h" + +#include "toolbox/logging.h" + #include "vm/builtin.h" -#include "vm/jit/patcher.h" -#include "vm/loader.h" -#include "vm/options.h" +#include "vm/exceptions.h" +#include "vm/global.h" + +#include "vm/access.h" #include "vm/jit/jit.h" -#include "vm/jit/show.h" #include "vm/jit/parse.h" -#include "vm/access.h" -#include "vm/resolve.h" -#include "vm/exceptions.h" +#include "vm/jit/patcher.h" +#include "vm/jit/show.h" + +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" #include diff --git a/src/vm/jit/verify/typeinfo.c b/src/vm/jit/verify/typeinfo.c index 1c3dcb9d8..660a25b12 100644 --- a/src/vm/jit/verify/typeinfo.c +++ b/src/vm/jit/verify/typeinfo.c @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - $Id: typeinfo.c 6286 2007-01-10 10:03:38Z twisti $ + $Id: typeinfo.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -38,13 +34,16 @@ #include "mm/memory.h" #include "toolbox/logging.h" -#include "vm/class.h" -#include "vm/loader.h" + +#include "vm/exceptions.h" + #include "vm/jit/jit.h" #include "vm/jit/verify/typeinfo.h" -#include "vm/descriptor.h" -#include "vm/resolve.h" -#include "vm/exceptions.h" + +#include "vmcore/class.h" +#include "vmcore/descriptor.h" +#include "vmcore/loader.h" +#include "vmcore/resolve.h" /* check if a linked class is an array class. Only use for linked classes! */ diff --git a/src/vm/jit/verify/typeinfo.h b/src/vm/jit/verify/typeinfo.h index 4dffce704..8cfeca6c9 100644 --- a/src/vm/jit/verify/typeinfo.h +++ b/src/vm/jit/verify/typeinfo.h @@ -1,6 +1,6 @@ -/* typeinfo.h - type system used by the type checker +/* src/vm/jit/verify/typeinfo.h - type system used by the type checker - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - $Id: typeinfo.h 6023 2006-11-19 15:22:53Z edwin $ + $Id: typeinfo.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -43,7 +39,8 @@ typedef struct typedescriptor typedescriptor; #include "vm/types.h" #include "vm/global.h" -#include "vm/references.h" + +#include "vmcore/references.h" /* configuration **************************************************************/ diff --git a/src/vm/linker.c b/src/vm/linker.c deleted file mode 100644 index e967b3ba6..000000000 --- a/src/vm/linker.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* src/vm/linker.c - class linker functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Andreas Krall - Roman Obermaiser - Mark Probst - Edwin Steiner - Christian Thalinger - - $Id: linker.c 7228 2007-01-19 01:13:48Z edwin $ - -*/ - - -#include "config.h" - -#include - -#include "vm/types.h" - -#include "mm/memory.h" -#include "native/native.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#else -# include "threads/none/lock.h" -#endif - -#include "vm/class.h" -#include "vm/classcache.h" -#include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" -#include "vm/stringlocal.h" -#include "vm/access.h" -#include "vm/rt-timing.h" -#include "vm/vm.h" -#include "vm/jit/asmpart.h" - - -#if !defined(NDEBUG) && defined(ENABLE_INLINING) -#define INLINELOG(code) do { if (opt_inline_debug_log) { code } } while (0) -#else -#define INLINELOG(code) -#endif - - -/* global variables ***********************************************************/ - -static s4 interfaceindex; /* sequential numbering of interfaces */ -static s4 classvalue; - - -/* primitivetype_table ********************************************************* - - Structure for primitive classes: contains the class for wrapping - the primitive type, the primitive class, the name of the class for - wrapping, the one character type signature and the name of the - primitive class. - - CAUTION: Don't change the order of the types. This table is indexed - by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT). - -*******************************************************************************/ - -primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { - { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL }, - { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL }, - { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL }, - { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL }, - { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, - { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL }, - { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL }, - { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL }, - { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL }, - { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, -#if defined(ENABLE_JAVASE) - { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL } -#else - { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, -#endif -}; - - -/* private functions **********************************************************/ - -static bool link_primitivetype_table(void); -static classinfo *link_class_intern(classinfo *c); -static arraydescriptor *link_array(classinfo *c); -static void linker_compute_class_values(classinfo *c); -static void linker_compute_subclasses(classinfo *c); -static bool linker_addinterface(classinfo *c, classinfo *ic); -static s4 class_highestinterface(classinfo *c); - - -/* linker_init ***************************************************************** - - Initializes the linker subsystem. - -*******************************************************************************/ - -bool linker_init(void) -{ - /* reset interface index */ - - interfaceindex = 0; - - /* link java.lang.Class as first class of the system, because we - need it's vftbl for all other classes so we can use a class as - object */ - - if (!link_class(class_java_lang_Class)) - return false; - - /* now set the header.vftbl of all classes which were created - before java.lang.Class was linked */ - - class_postset_header_vftbl(); - - - /* link important system classes */ - - if (!link_class(class_java_lang_Object)) - return false; - - if (!link_class(class_java_lang_String)) - return false; - -#if defined(ENABLE_JAVASE) - if (!link_class(class_java_lang_Cloneable)) - return false; - - if (!link_class(class_java_io_Serializable)) - return false; -#endif - - - /* link classes for wrapping primitive types */ - -#if defined(ENABLE_JAVASE) - if (!link_class(class_java_lang_Void)) - return false; -#endif - - if (!link_class(class_java_lang_Boolean)) - return false; - - if (!link_class(class_java_lang_Byte)) - return false; - - if (!link_class(class_java_lang_Character)) - return false; - - if (!link_class(class_java_lang_Short)) - return false; - - if (!link_class(class_java_lang_Integer)) - return false; - - if (!link_class(class_java_lang_Long)) - return false; - - if (!link_class(class_java_lang_Float)) - return false; - - if (!link_class(class_java_lang_Double)) - return false; - - - /* load some other important classes */ - -#if defined(ENABLE_JAVASE) - if (!link_class(class_java_lang_ClassLoader)) - return false; - - if (!link_class(class_java_lang_SecurityManager)) - return false; -#endif - - if (!link_class(class_java_lang_System)) - return false; - - if (!link_class(class_java_lang_Thread)) - return false; - -#if defined(ENABLE_JAVASE) - if (!link_class(class_java_lang_ThreadGroup)) - return false; -#endif - -#if defined(WITH_CLASSPATH_GNU) - if (!link_class(class_java_lang_VMSystem)) - return false; - - if (!link_class(class_java_lang_VMThread)) - return false; -#endif - - - /* some classes which may be used more often */ - -#if defined(ENABLE_JAVASE) - if (!link_class(class_java_lang_StackTraceElement)) - return false; - - if (!link_class(class_java_lang_reflect_Constructor)) - return false; - - if (!link_class(class_java_lang_reflect_Field)) - return false; - - if (!link_class(class_java_lang_reflect_Method)) - return false; - - if (!link_class(class_java_security_PrivilegedAction)) - return false; - - if (!link_class(class_java_util_Vector)) - return false; - - if (!link_class(arrayclass_java_lang_Object)) - return false; -#endif - - - /* create pseudo classes used by the typechecker */ - - /* pseudo class for Arraystubs (extends java.lang.Object) */ - - pseudo_class_Arraystub = - class_create_classinfo(utf_new_char("$ARRAYSTUB$")); - pseudo_class_Arraystub->state |= CLASS_LOADED; - pseudo_class_Arraystub->super.cls = class_java_lang_Object; - -#if defined(ENABLE_JAVASE) - pseudo_class_Arraystub->interfacescount = 2; - pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2); - pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable; - pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable; -#elif defined(ENABLE_JAVAME_CLDC1_1) - pseudo_class_Arraystub->interfacescount = 0; - pseudo_class_Arraystub->interfaces = NULL; -#endif - - if (!classcache_store_unique(pseudo_class_Arraystub)) { - log_text("could not cache pseudo_class_Arraystub"); - assert(0); - } - - if (!link_class(pseudo_class_Arraystub)) - return false; - - /* pseudo class representing the null type */ - - pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); - pseudo_class_Null->state |= CLASS_LOADED; - pseudo_class_Null->super.cls = class_java_lang_Object; - - if (!classcache_store_unique(pseudo_class_Null)) { - log_text("could not cache pseudo_class_Null"); - assert(0); - } - - if (!link_class(pseudo_class_Null)) - return false; - - /* pseudo class representing new uninitialized objects */ - - pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); - pseudo_class_New->state |= CLASS_LOADED; - pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */ - pseudo_class_New->super.cls = class_java_lang_Object; - - if (!classcache_store_unique(pseudo_class_New)) { - log_text("could not cache pseudo_class_New"); - assert(0); - } - - /* create classes representing primitive types */ - - if (!link_primitivetype_table()) - return false; - - - /* Correct vftbl-entries (retarded loading and linking of class */ - /* java/lang/String). */ - - stringtable_update(); - - return true; -} - - -/* link_primitivetype_table **************************************************** - - Create classes representing primitive types. - -*******************************************************************************/ - -static bool link_primitivetype_table(void) -{ - classinfo *c; - utf *u; - s4 i; - - for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { - /* skip dummies */ - - if (!primitivetype_table[i].name) - continue; - - /* create primitive class */ - - c = class_create_classinfo(utf_new_char(primitivetype_table[i].name)); - - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; - - /* prevent loader from loading primitive class */ - - c->state |= CLASS_LOADED; - - /* INFO: don't put primitive classes into the classcache */ - - if (!link_class(c)) - return false; - - primitivetype_table[i].class_primitive = c; - - /* create class for wrapping the primitive type */ - - u = utf_new_char(primitivetype_table[i].wrapname); - - if (!(c = load_class_bootstrap(u))) - return false; - - primitivetype_table[i].class_wrap = c; - - /* create the primitive array class */ - - if (primitivetype_table[i].arrayname) { - u = utf_new_char(primitivetype_table[i].arrayname); - c = class_create_classinfo(u); - c = load_newly_created_array(c, NULL); - if (c == NULL) - return false; - - primitivetype_table[i].arrayclass = c; - - assert(c->state & CLASS_LOADED); - - if (!(c->state & CLASS_LINKED)) - if (!link_class(c)) - return false; - - primitivetype_table[i].arrayvftbl = c->vftbl; - } - } - - return true; -} - - -/* link_class ****************************************************************** - - Wrapper function for link_class_intern to ease monitor enter/exit - and exception handling. - -*******************************************************************************/ - -classinfo *link_class(classinfo *c) -{ - classinfo *r; -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_end; -#endif - - RT_TIMING_GET_TIME(time_start); - - if (c == NULL) { - exceptions_throw_nullpointerexception(); - return NULL; - } - - LOCK_MONITOR_ENTER(c); - - /* maybe the class is already linked */ - - if (c->state & CLASS_LINKED) { - LOCK_MONITOR_EXIT(c); - - return c; - } - -#if defined(ENABLE_STATISTICS) - /* measure time */ - - if (opt_getcompilingtime) - compilingtime_stop(); - - if (opt_getloadingtime) - loadingtime_start(); -#endif - - /* call the internal function */ - - r = link_class_intern(c); - - /* if return value is NULL, we had a problem and the class is not linked */ - - if (!r) - c->state &= ~CLASS_LINKING; - -#if defined(ENABLE_STATISTICS) - /* measure time */ - - if (opt_getloadingtime) - loadingtime_stop(); - - if (opt_getcompilingtime) - compilingtime_start(); -#endif - - LOCK_MONITOR_EXIT(c); - - RT_TIMING_GET_TIME(time_end); - - RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL); - - return r; -} - - -/* linker_overwrite_method ***************************************************** - - Overwrite a method with another one, update method flags and check - assumptions. - - IN: - mg................the general method being overwritten - ms................the overwriting (more specialized) method - wl................worklist where to add invalidated methods - - RETURN VALUE: - true..............everything ok - false.............an exception has been thrown - -*******************************************************************************/ - -static bool linker_overwrite_method(methodinfo *mg, - methodinfo *ms, - method_worklist **wl) -{ - classinfo *cg; - classinfo *cs; - - cg = mg->class; - cs = ms->class; - - /* overriding a final method is illegal */ - - if (mg->flags & ACC_FINAL) { - *exceptionptr = - new_exception(string_java_lang_VerifyError); - return false; - } - - /* method ms overwrites method mg */ - -#if defined(ENABLE_VERIFIER) - /* Add loading constraints (for the more general types of method mg). */ - /* Not for , as it is not invoked virtually. */ - - if ((ms->name != utf_init) - && !classcache_add_constraints_for_params( - cs->classloader, cg->classloader, mg)) - { - return false; - } -#endif - - /* inherit the vftbl index, and record the overwriting */ - - ms->vftblindex = mg->vftblindex; - ms->overwrites = mg; - - /* update flags and check assumptions */ - /* methods are a special case, as they are never dispatched dynamically */ - - if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) { - do { - if (mg->flags & ACC_METHOD_IMPLEMENTED) { - /* this adds another implementation */ - - mg->flags &= ~ACC_METHOD_MONOMORPHIC; - - INLINELOG( printf("becomes polymorphic: "); method_println(mg); ); - - method_break_assumption_monomorphic(mg, wl); - } - else { - /* this is the first implementation */ - - mg->flags |= ACC_METHOD_IMPLEMENTED; - - INLINELOG( printf("becomes implemented: "); method_println(mg); ); - } - - ms = mg; - mg = mg->overwrites; - } while (mg != NULL); - } - - return true; -} - - -/* link_class_intern *********************************************************** - - Tries to link a class. The function calculates the length in bytes - that an instance of this class requires as well as the VTBL for - methods and interface methods. - -*******************************************************************************/ - -static classinfo *link_class_intern(classinfo *c) -{ - classinfo *super; /* super class */ - classinfo *tc; /* temporary class variable */ - s4 supervftbllength; /* vftbllegnth of super class */ - s4 vftbllength; /* vftbllength of current class */ - s4 interfacetablelength; /* interface table length */ - vftbl_t *v; /* vftbl of current class */ - s4 i; /* interface/method/field counter */ - arraydescriptor *arraydesc; /* descriptor for array classes */ - method_worklist *worklist; /* worklist for recompilation */ -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_resolving, time_compute_vftbl, - time_abstract, time_compute_iftbl, time_fill_vftbl, - time_offsets, time_fill_iftbl, time_finalizer, - time_subclasses; -#endif - - RT_TIMING_GET_TIME(time_start); - - /* the class is already linked */ - - if (c->state & CLASS_LINKED) - return c; - -#if !defined(NDEBUG) - if (linkverbose) - log_message_class("Linking class: ", c); -#endif - - /* the class must be loaded */ - - /* XXX should this be a specific exception? */ - assert(c->state & CLASS_LOADED); - - /* cache the self-reference of this class */ - /* we do this for cases where the defining loader of the class */ - /* has not yet been recorded as an initiating loader for the class */ - /* this is needed so subsequent code can assume that self-refs */ - /* will always resolve lazily */ - /* No need to do it for the bootloader - it is always registered */ - /* as initiating loader for the classes it loads. */ - if (c->classloader) - classcache_store(c->classloader,c,false); - - /* this class is currently linking */ - - c->state |= CLASS_LINKING; - - arraydesc = NULL; - worklist = NULL; - - /* check interfaces */ - - for (i = 0; i < c->interfacescount; i++) { - /* resolve this super interface */ - - if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager, - true, false, &tc)) - return NULL; - - c->interfaces[i].cls = tc; - - /* detect circularity */ - - if (tc == c) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); - return NULL; - } - - assert(tc->state & CLASS_LOADED); - - if (!(tc->flags & ACC_INTERFACE)) { - *exceptionptr = - new_exception_message(string_java_lang_IncompatibleClassChangeError, - "Implementing class"); - return NULL; - } - - if (!(tc->state & CLASS_LINKED)) - if (!link_class(tc)) - return NULL; - } - - /* check super class */ - - super = NULL; - - if (c->super.any == NULL) { /* class java.lang.Object */ - c->index = 0; - c->instancesize = sizeof(java_objectheader); - - vftbllength = supervftbllength = 0; - - c->finalizer = NULL; - - } else { - /* resolve super class */ - - if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false, - &super)) - return NULL; - c->super.cls = super; - - /* detect circularity */ - - if (super == c) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); - return NULL; - } - - assert(super->state & CLASS_LOADED); - - if (super->flags & ACC_INTERFACE) { - /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */ - log_text("Interface specified as super class"); - assert(0); - } - - /* Don't allow extending final classes */ - - if (super->flags & ACC_FINAL) { - *exceptionptr = - new_exception_message(string_java_lang_VerifyError, - "Cannot inherit from final class"); - return NULL; - } - - /* link the superclass if necessary */ - - if (!(super->state & CLASS_LINKED)) - if (!link_class(super)) - return NULL; - - /* OR the ACC_CLASS_HAS_POINTERS flag */ - - c->flags |= (super->flags & ACC_CLASS_HAS_POINTERS); - - /* handle array classes */ - - if (c->name->text[0] == '[') - if (!(arraydesc = link_array(c))) - return NULL; - - if (c->flags & ACC_INTERFACE) - c->index = interfaceindex++; - else - c->index = super->index + 1; - - c->instancesize = super->instancesize; - - vftbllength = supervftbllength = super->vftbl->vftbllength; - - c->finalizer = super->finalizer; - } - RT_TIMING_GET_TIME(time_resolving); - - - /* compute vftbl length */ - - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - - if (!(m->flags & ACC_STATIC)) { /* is instance method */ - tc = super; - - while (tc) { - s4 j; - - for (j = 0; j < tc->methodscount; j++) { - if (method_canoverwrite(m, &(tc->methods[j]))) { - if (tc->methods[j].flags & ACC_PRIVATE) - goto notfoundvftblindex; - - /* package-private methods in other packages */ - /* must not be overridden */ - /* (see Java Language Specification 8.4.8.1) */ - if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) - && !SAME_PACKAGE(c,tc) ) - { - goto notfoundvftblindex; - } - - if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist)) - return NULL; - - goto foundvftblindex; - } - } - - tc = tc->super.cls; - } - - notfoundvftblindex: - m->vftblindex = (vftbllength++); - foundvftblindex: - ; - } - } - RT_TIMING_GET_TIME(time_compute_vftbl); - - - /* Check all interfaces of an abstract class (maybe be an - interface too) for unimplemented methods. Such methods are - called miranda-methods and are marked with the ACC_MIRANDA - flag. VMClass.getDeclaredMethods does not return such - methods. */ - - if (c->flags & ACC_ABSTRACT) { - classinfo *ic; - methodinfo *im; - s4 abstractmethodscount; - s4 j; - s4 k; - - abstractmethodscount = 0; - - /* check all interfaces of the abstract class */ - - for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i].cls; - - for (j = 0; j < ic->methodscount; j++) { - im = &(ic->methods[j]); - - /* skip `' and `' */ - - if ((im->name == utf_clinit) || (im->name == utf_init)) - continue; - - for (tc = c; tc != NULL; tc = tc->super.cls) { - for (k = 0; k < tc->methodscount; k++) { - if (method_canoverwrite(im, &(tc->methods[k]))) - goto noabstractmethod; - } - } - - abstractmethodscount++; - - noabstractmethod: - ; - } - } - - if (abstractmethodscount > 0) { - methodinfo *am; - - /* reallocate methods memory */ - - c->methods = MREALLOC(c->methods, methodinfo, c->methodscount, - c->methodscount + abstractmethodscount); - - for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i].cls; - - for (j = 0; j < ic->methodscount; j++) { - im = &(ic->methods[j]); - - /* skip `' and `' */ - - if ((im->name == utf_clinit) || (im->name == utf_init)) - continue; - - for (tc = c; tc != NULL; tc = tc->super.cls) { - for (k = 0; k < tc->methodscount; k++) { - if (method_canoverwrite(im, &(tc->methods[k]))) - goto noabstractmethod2; - } - } - - /* Copy the method found into the new c->methods - array and tag it as miranda-method. */ - - am = &(c->methods[c->methodscount]); - c->methodscount++; - - MCOPY(am, im, methodinfo, 1); - - am->vftblindex = (vftbllength++); - am->class = c; - am->flags |= ACC_MIRANDA; - - noabstractmethod2: - ; - } - } - } - } - RT_TIMING_GET_TIME(time_abstract); - - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_vftbl_len += - sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); -#endif - - /* compute interfacetable length */ - - interfacetablelength = 0; - - for (tc = c; tc != NULL; tc = tc->super.cls) { - for (i = 0; i < tc->interfacescount; i++) { - s4 h = class_highestinterface(tc->interfaces[i].cls) + 1; - - if (h > interfacetablelength) - interfacetablelength = h; - } - } - RT_TIMING_GET_TIME(time_compute_iftbl); - - /* allocate virtual function table */ - - v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) + - sizeof(methodptr) * (vftbllength - 1) + - sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); - v = (vftbl_t *) (((methodptr *) v) + - (interfacetablelength - 1) * (interfacetablelength > 1)); - - c->vftbl = v; - v->class = c; - v->vftbllength = vftbllength; - v->interfacetablelength = interfacetablelength; - v->arraydesc = arraydesc; - - /* store interface index in vftbl */ - - if (c->flags & ACC_INTERFACE) - v->baseval = -(c->index); - - /* copy virtual function table of super class */ - - for (i = 0; i < supervftbllength; i++) - v->table[i] = super->vftbl->table[i]; - - /* Fill the remaining vftbl slots with the AbstractMethodError - stub (all after the super class slots, because they are already - initialized). */ - - for (; i < vftbllength; i++) { -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; - else -# endif - v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror; -#else - v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; -#endif - } - - /* add method stubs into virtual function table */ - - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - - assert(m->stubroutine == NULL); - - /* Don't create a compiler stub for abstract methods as they - throw an AbstractMethodError with the default stub in the - vftbl. This entry is simply copied by sub-classes. */ - - if (m->flags & ACC_ABSTRACT) - continue; - -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - m->stubroutine = intrp_createcompilerstub(m); - else -#endif - m->stubroutine = createcompilerstub(m); -#else - m->stubroutine = intrp_createcompilerstub(m); -#endif - - /* static methods are not in the vftbl */ - - if (m->flags & ACC_STATIC) - continue; - - /* insert the stubroutine into the vftbl */ - - v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; - } - RT_TIMING_GET_TIME(time_fill_vftbl); - - /* compute instance size and offset of each field */ - - for (i = 0; i < c->fieldscount; i++) { - s4 dsize; - fieldinfo *f = &(c->fields[i]); - - if (!(f->flags & ACC_STATIC)) { - dsize = descriptor_typesize(f->parseddesc); - - /* On i386 we only align to 4 bytes even for double and s8. */ - /* This matches what gcc does for struct members. We must */ - /* do the same as gcc here because the offsets in native */ - /* header structs like java_lang_Double must match the offsets */ - /* of the Java fields (eg. java.lang.Double.value). */ -#if defined(__I386__) - c->instancesize = MEMORY_ALIGN(c->instancesize, 4); -#else - c->instancesize = MEMORY_ALIGN(c->instancesize, dsize); -#endif - - f->offset = c->instancesize; - c->instancesize += dsize; - } - } - RT_TIMING_GET_TIME(time_offsets); - - /* initialize interfacetable and interfacevftbllength */ - - v->interfacevftbllength = MNEW(s4, interfacetablelength); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; -#endif - - for (i = 0; i < interfacetablelength; i++) { - v->interfacevftbllength[i] = 0; - v->interfacetable[-i] = NULL; - } - - /* add interfaces */ - - for (tc = c; tc != NULL; tc = tc->super.cls) - for (i = 0; i < tc->interfacescount; i++) - if (!linker_addinterface(c, tc->interfaces[i].cls)) - return NULL; - - RT_TIMING_GET_TIME(time_fill_iftbl); - - /* add finalizer method (not for java.lang.Object) */ - - if (super) { - methodinfo *fi; - - fi = class_findmethod(c, utf_finalize, utf_void__void); - - if (fi) - if (!(fi->flags & ACC_STATIC)) - c->finalizer = fi; - } - RT_TIMING_GET_TIME(time_finalizer); - - /* final tasks */ - - linker_compute_subclasses(c); - - RT_TIMING_GET_TIME(time_subclasses); - - /* revert the linking state and class is linked */ - - c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED; - - /* check worklist */ - - /* XXX must this also be done in case of exception? */ - - while (worklist != NULL) { - method_worklist *wi = worklist; - - worklist = worklist->next; - - INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); ); - jit_invalidate_code(wi->m); - - /* XXX put worklist into dump memory? */ - FREE(wi, method_worklist); - } - -#if !defined(NDEBUG) - if (linkverbose) - log_message_class("Linking done class: ", c); -#endif - - RT_TIMING_TIME_DIFF(time_start ,time_resolving ,RT_TIMING_LINK_RESOLVE); - RT_TIMING_TIME_DIFF(time_resolving ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL); - RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract ,RT_TIMING_LINK_ABSTRACT); - RT_TIMING_TIME_DIFF(time_abstract ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL); - RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl ,RT_TIMING_LINK_F_VFTBL); - RT_TIMING_TIME_DIFF(time_fill_vftbl ,time_offsets ,RT_TIMING_LINK_OFFSETS); - RT_TIMING_TIME_DIFF(time_offsets ,time_fill_iftbl ,RT_TIMING_LINK_F_IFTBL); - RT_TIMING_TIME_DIFF(time_fill_iftbl ,time_finalizer ,RT_TIMING_LINK_FINALIZER); - RT_TIMING_TIME_DIFF(time_finalizer ,time_subclasses ,RT_TIMING_LINK_SUBCLASS); - - /* just return c to show that we didn't had a problem */ - - return c; -} - - -/* link_array ****************************************************************** - - This function is called by link_class to create the arraydescriptor - for an array class. - - This function returns NULL if the array cannot be linked because - the component type has not been linked yet. - -*******************************************************************************/ - -static arraydescriptor *link_array(classinfo *c) -{ - classinfo *comp; - s4 namelen; - arraydescriptor *desc; - vftbl_t *compvftbl; - utf *u; - - comp = NULL; - namelen = c->name->blength; - - /* Check the component type */ - - switch (c->name->text[1]) { - case '[': - /* c is an array of arrays. */ - u = utf_new(c->name->text + 1, namelen - 1); - if (!(comp = load_class_from_classloader(u, c->classloader))) - return NULL; - break; - - case 'L': - /* c is an array of objects. */ - u = utf_new(c->name->text + 2, namelen - 3); - if (!(comp = load_class_from_classloader(u, c->classloader))) - return NULL; - break; - } - - /* If the component type has not been linked, link it now */ - - assert(!comp || (comp->state & CLASS_LOADED)); - - if (comp && !(comp->state & CLASS_LINKED)) - if (!link_class(comp)) - return NULL; - - /* Allocate the arraydescriptor */ - - desc = NEW(arraydescriptor); - - if (comp) { - /* c is an array of references */ - desc->arraytype = ARRAYTYPE_OBJECT; - desc->componentsize = sizeof(void*); - desc->dataoffset = OFFSET(java_objectarray, data); - - compvftbl = comp->vftbl; - - if (!compvftbl) { - log_text("Component class has no vftbl"); - assert(0); - } - - desc->componentvftbl = compvftbl; - - if (compvftbl->arraydesc) { - desc->elementvftbl = compvftbl->arraydesc->elementvftbl; - - if (compvftbl->arraydesc->dimension >= 255) { - log_text("Creating array of dimension >255"); - assert(0); - } - - desc->dimension = compvftbl->arraydesc->dimension + 1; - desc->elementtype = compvftbl->arraydesc->elementtype; - - } else { - desc->elementvftbl = compvftbl; - desc->dimension = 1; - desc->elementtype = ARRAYTYPE_OBJECT; - } - - } else { - /* c is an array of a primitive type */ - switch (c->name->text[1]) { - case 'Z': - desc->arraytype = ARRAYTYPE_BOOLEAN; - desc->dataoffset = OFFSET(java_booleanarray,data); - desc->componentsize = sizeof(u1); - break; - - case 'B': - desc->arraytype = ARRAYTYPE_BYTE; - desc->dataoffset = OFFSET(java_bytearray,data); - desc->componentsize = sizeof(u1); - break; - - case 'C': - desc->arraytype = ARRAYTYPE_CHAR; - desc->dataoffset = OFFSET(java_chararray,data); - desc->componentsize = sizeof(u2); - break; - - case 'D': - desc->arraytype = ARRAYTYPE_DOUBLE; - desc->dataoffset = OFFSET(java_doublearray,data); - desc->componentsize = sizeof(double); - break; - - case 'F': - desc->arraytype = ARRAYTYPE_FLOAT; - desc->dataoffset = OFFSET(java_floatarray,data); - desc->componentsize = sizeof(float); - break; - - case 'I': - desc->arraytype = ARRAYTYPE_INT; - desc->dataoffset = OFFSET(java_intarray,data); - desc->componentsize = sizeof(s4); - break; - - case 'J': - desc->arraytype = ARRAYTYPE_LONG; - desc->dataoffset = OFFSET(java_longarray,data); - desc->componentsize = sizeof(s8); - break; - - case 'S': - desc->arraytype = ARRAYTYPE_SHORT; - desc->dataoffset = OFFSET(java_shortarray,data); - desc->componentsize = sizeof(s2); - break; - - default: - *exceptionptr = new_noclassdeffounderror(c->name); - return NULL; - } - - desc->componentvftbl = NULL; - desc->elementvftbl = NULL; - desc->dimension = 1; - desc->elementtype = desc->arraytype; - } - - return desc; -} - - -/* linker_compute_subclasses *************************************************** - - XXX - -*******************************************************************************/ - -static void linker_compute_subclasses(classinfo *c) -{ -#if defined(ENABLE_THREADS) - compiler_lock(); -#endif - - if (!(c->flags & ACC_INTERFACE)) { - c->nextsub = 0; - c->sub = 0; - } - - if (!(c->flags & ACC_INTERFACE) && (c->super.any != NULL)) { - c->nextsub = c->super.cls->sub; - c->super.cls->sub = c; - } - - classvalue = 0; - - /* compute class values */ - - linker_compute_class_values(class_java_lang_Object); - -#if defined(ENABLE_THREADS) - compiler_unlock(); -#endif -} - - -/* linker_compute_class_values ************************************************* - - XXX - -*******************************************************************************/ - -static void linker_compute_class_values(classinfo *c) -{ - classinfo *subs; - - c->vftbl->baseval = ++classvalue; - - subs = c->sub; - - while (subs) { - linker_compute_class_values(subs); - - subs = subs->nextsub; - } - - c->vftbl->diffval = classvalue - c->vftbl->baseval; -} - - -/* linker_addinterface ********************************************************* - - Is needed by link_class for adding a VTBL to a class. All - interfaces implemented by ic are added as well. - - RETURN VALUE: - true.........everything ok - false........an exception has been thrown - -*******************************************************************************/ - -static bool linker_addinterface(classinfo *c, classinfo *ic) -{ - s4 j, k; - vftbl_t *v; - s4 i; - classinfo *sc; - methodinfo *m; - - v = c->vftbl; - i = ic->index; - - if (i >= v->interfacetablelength) - vm_abort("Internal error: interfacetable overflow"); - - /* if this interface has already been added, return immediately */ - - if (v->interfacetable[-i] != NULL) - return true; - - if (ic->methodscount == 0) { /* fake entry needed for subtype test */ - v->interfacevftbllength[i] = 1; - v->interfacetable[-i] = MNEW(methodptr, 1); - v->interfacetable[-i][0] = NULL; - } - else { - v->interfacevftbllength[i] = ic->methodscount; - v->interfacetable[-i] = MNEW(methodptr, ic->methodscount); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_vftbl_len += sizeof(methodptr) * - (ic->methodscount + (ic->methodscount == 0)); -#endif - - for (j = 0; j < ic->methodscount; j++) { - for (sc = c; sc != NULL; sc = sc->super.cls) { - for (k = 0; k < sc->methodscount; k++) { - m = &(sc->methods[k]); - - if (method_canoverwrite(m, &(ic->methods[j]))) { - /* method m overwrites the (abstract) method */ -#if defined(ENABLE_VERIFIER) - /* Add loading constraints (for the more - general types of the method - ic->methods[j]). */ - if (!classcache_add_constraints_for_params( - c->classloader, ic->classloader, - &(ic->methods[j]))) - { - return false; - } -#endif - - /* XXX taken from gcj */ - /* check for ACC_STATIC: IncompatibleClassChangeError */ - - /* check for !ACC_PUBLIC: IllegalAccessError */ - - /* check for ACC_ABSTRACT: AbstracMethodError, - not sure about that one */ - - v->interfacetable[-i][j] = v->table[m->vftblindex]; - goto foundmethod; - } - } - } - - /* If no method was found, insert the AbstractMethodError - stub. */ - -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - v->interfacetable[-i][j] = - (methodptr) (ptrint) &intrp_asm_abstractmethoderror; - else -# endif - v->interfacetable[-i][j] = - (methodptr) (ptrint) &asm_abstractmethoderror; -#else - v->interfacetable[-i][j] = - (methodptr) (ptrint) &intrp_asm_abstractmethoderror; -#endif - - foundmethod: - ; - } - } - - /* add superinterfaces of this interface */ - - for (j = 0; j < ic->interfacescount; j++) - if (!linker_addinterface(c, ic->interfaces[j].cls)) - return false; - - /* everything ok */ - - return true; -} - - -/* class_highestinterface ****************************************************** - - Used by the function link_class to determine the amount of memory - needed for the interface table. - -*******************************************************************************/ - -static s4 class_highestinterface(classinfo *c) -{ - s4 h; - s4 h2; - s4 i; - - /* check for ACC_INTERFACE bit already done in link_class_intern */ - - h = c->index; - - for (i = 0; i < c->interfacescount; i++) { - h2 = class_highestinterface(c->interfaces[i].cls); - - if (h2 > h) - h = h2; - } - - return 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: - */ diff --git a/src/vm/linker.h b/src/vm/linker.h deleted file mode 100644 index e8c6b11af..000000000 --- a/src/vm/linker.h +++ /dev/null @@ -1,184 +0,0 @@ -/* src/vm/linker.h - class linker header - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: linker.h 4357 2006-01-22 23:33:38Z twisti $ -*/ - - -#ifndef _LINKER_H -#define _LINKER_H - -/* forward typedefs ***********************************************************/ - -typedef struct _vftbl vftbl_t; -typedef struct arraydescriptor arraydescriptor; -typedef struct primitivetypeinfo primitivetypeinfo; - - -#include "vm/class.h" -#include "vm/references.h" - - -/* virtual function table ****************************************************** - - The vtbl has a bidirectional layout with open ends at both sides. - interfacetablelength gives the number of entries of the interface - table at the start of the vftbl. The vftbl pointer points to - &interfacetable[0]. vftbllength gives the number of entries of - table at the end of the vftbl. - - runtime type check (checkcast): - - Different methods are used for runtime type check depending on the - argument of checkcast/instanceof. - - A check against a class is implemented via relative numbering on - the class hierachy tree. The tree is numbered in a depth first - traversal setting the base field and the diff field. The diff field - gets the result of (high - base) so that a range check can be - implemented by an unsigned compare. A sub type test is done by - checking the inclusion of base of the sub class in the range of the - superclass. - - A check against an interface is implemented via the - interfacevftbl. If the interfacevftbl contains a nonnull value a - class is a subclass of this interface. - - interfacetable: - - Like standard virtual methods interface methods are called using - virtual function tables. All interfaces are numbered sequentially - (starting with zero). For each class there exist an interface table - of virtual function tables for each implemented interface. The - length of the interface table is determined by the highest number - of an implemented interface. - - The following example assumes a class which implements interface 0 and 3: - - interfacetablelength = 4 - - | ... | +----------+ - +-----------+ | method 2 |---> method z - | class | | method 1 |---> method y - +-----------+ | method 0 |---> method x - | ivftbl 0 |----------> +----------+ - vftblptr ---> +-----------+ - | ivftbl -1 |--> NULL +----------+ - | ivftbl -2 |--> NULL | method 1 |---> method x - | ivftbl -3 |-----+ | method 0 |---> method a - +-----------+ +----> +----------+ - - +---------------+ - | length 3 = 2 | - | length 2 = 0 | - | length 1 = 0 | - | length 0 = 3 | - interfacevftbllength ---> +---------------+ - -*******************************************************************************/ - -struct _vftbl { - methodptr *interfacetable[1]; /* interface table (access via macro) */ - classinfo *class; /* class, the vtbl belongs to */ - arraydescriptor *arraydesc; /* for array classes, otherwise NULL */ - s4 vftbllength; /* virtual function table length */ - s4 interfacetablelength; /* interface table length */ - s4 baseval; /* base for runtime type check */ - /* (-index for interfaces) */ - s4 diffval; /* high - base for runtime type check */ - s4 *interfacevftbllength; /* length of interface vftbls */ - methodptr table[1]; /* class vftbl */ -}; - - -/* arraydescriptor ************************************************************* - - For every array class an arraydescriptor is allocated which - describes the array class. The arraydescriptor is referenced from - the vftbl of the array class. - -*******************************************************************************/ - -struct arraydescriptor { - vftbl_t *componentvftbl; /* vftbl of the component type, NULL for primit. */ - vftbl_t *elementvftbl; /* vftbl of the element type, NULL for primitive */ - s2 arraytype; /* ARRAYTYPE_* constant */ - s2 dimension; /* dimension of the array (always >= 1) */ - s4 dataoffset; /* offset of the array data from object pointer */ - s4 componentsize; /* size of a component in bytes */ - s2 elementtype; /* ARRAYTYPE_* constant */ -}; - - -/* primitivetypeinfo **********************************************************/ - -struct primitivetypeinfo { - classinfo *class_wrap; /* class for wrapping primitive type */ - classinfo *class_primitive; /* primitive class */ - char *wrapname; /* name of class for wrapping */ - char typesig; /* one character type signature */ - char *name; /* name of primitive class */ - char *arrayname; /* name of primitive array class */ - classinfo *arrayclass; /* primitive array class */ - vftbl_t *arrayvftbl; /* vftbl of primitive array class */ -}; - - -/* global variables ***********************************************************/ - -/* This array can be indexed by the PRIMITIVETYPE_ and ARRAYTYPE_ constants */ -/* (except ARRAYTYPE_OBJECT). */ - -extern primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT]; - - -/* function prototypes ********************************************************/ - -/* initialize the linker subsystem */ -bool linker_init(void); - -/* link a class */ -classinfo *link_class(classinfo *c); - -#endif /* _LINKER_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: - */ diff --git a/src/vm/loader.c b/src/vm/loader.c deleted file mode 100644 index 75b452130..000000000 --- a/src/vm/loader.c +++ /dev/null @@ -1,2623 +0,0 @@ -/* src/vm/loader.c - class loader functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Andreas Krall - Roman Obermaiser - Mark Probst - Edwin Steiner - Christian Thalinger - - $Id: loader.c 7240 2007-01-27 13:01:35Z twisti $ - -*/ - - -#include "config.h" - -#include -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" -#include "native/native.h" -#include "native/include/java_lang_Throwable.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif - -#include "toolbox/logging.h" - -#if defined(ENABLE_JAVASE) -# include "vm/annotation.h" -# include "vm/stackmap.h" -#endif - -#include "vm/builtin.h" -#include "vm/classcache.h" -#include "vm/exceptions.h" -#include "vm/global.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/statistics.h" -#include "vm/stringlocal.h" -#include "vm/suck.h" -#include "vm/vm.h" - -#if defined(ENABLE_ZLIB) -# include "vm/zip.h" -#endif - -#include "vm/jit/asmpart.h" -#include "vm/jit/codegen-common.h" -#include "vm/rt-timing.h" - -#if defined(ENABLE_JVMTI) -#include "native/jvmti/cacaodbg.h" -#endif - - -/* loader_init ***************************************************************** - - Initializes all lists and loads all classes required for the system - or the compiler. - -*******************************************************************************/ - -bool loader_init(void) -{ -#if defined(ENABLE_THREADS) - list_classpath_entry *lce; - - /* Initialize the monitor pointer for zip/jar file locking. */ - - for (lce = list_first(list_classpath_entries); lce != NULL; - lce = list_next(list_classpath_entries, lce)) - if (lce->type == CLASSPATH_ARCHIVE) - lock_init_object_lock((java_objectheader *) lce); -#endif - - /* load some important classes */ - - if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object))) - return false; - - if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String))) - return false; - -#if defined(ENABLE_JAVASE) - if (!(class_java_lang_Cloneable = - load_class_bootstrap(utf_java_lang_Cloneable))) - return false; - - if (!(class_java_io_Serializable = - load_class_bootstrap(utf_java_io_Serializable))) - return false; -#endif - - /* load classes for wrapping primitive types */ - -#if defined(ENABLE_JAVASE) - if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void))) - return false; -#endif - - if (!(class_java_lang_Boolean = - load_class_bootstrap(utf_java_lang_Boolean))) - return false; - - if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte))) - return false; - - if (!(class_java_lang_Character = - load_class_bootstrap(utf_java_lang_Character))) - return false; - - if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short))) - return false; - - if (!(class_java_lang_Integer = - load_class_bootstrap(utf_java_lang_Integer))) - return false; - - if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long))) - return false; - - if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float))) - return false; - - if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double))) - return false; - - - /* load some other important classes */ - - if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class))) - return false; - -#if defined(ENABLE_JAVASE) - if (!(class_java_lang_ClassLoader = - load_class_bootstrap(utf_java_lang_ClassLoader))) - return false; - - if (!(class_java_lang_SecurityManager = - load_class_bootstrap(utf_java_lang_SecurityManager))) - return false; -#endif - - if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System))) - return false; - - if (!(class_java_lang_Thread = - load_class_bootstrap(utf_new_char("java/lang/Thread")))) - return false; - -#if defined(ENABLE_JAVASE) - if (!(class_java_lang_ThreadGroup = - load_class_bootstrap(utf_java_lang_ThreadGroup))) - return false; -#endif - -#if defined(WITH_CLASSPATH_GNU) - if (!(class_java_lang_VMSystem = - load_class_bootstrap(utf_new_char("java/lang/VMSystem")))) - - return false; - - if (!(class_java_lang_VMThread = - load_class_bootstrap(utf_new_char("java/lang/VMThread")))) - return false; -#endif - - - /* some classes which may be used more often */ - -#if defined(ENABLE_JAVASE) - if (!(class_java_lang_StackTraceElement = - load_class_bootstrap(utf_java_lang_StackTraceElement))) - return false; - - if (!(class_java_lang_reflect_Constructor = - load_class_bootstrap(utf_java_lang_reflect_Constructor))) - return false; - - if (!(class_java_lang_reflect_Field = - load_class_bootstrap(utf_java_lang_reflect_Field))) - return false; - - if (!(class_java_lang_reflect_Method = - load_class_bootstrap(utf_java_lang_reflect_Method))) - return false; - - if (!(class_java_security_PrivilegedAction = - load_class_bootstrap(utf_new_char("java/security/PrivilegedAction")))) - return false; - - if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector))) - return false; - - if (!(arrayclass_java_lang_Object = - load_class_bootstrap(utf_new_char("[Ljava/lang/Object;")))) - return false; -#endif - - return true; -} - - -/* loader_load_all_classes ***************************************************** - - Loads all classes specified in the BOOTCLASSPATH. - -*******************************************************************************/ - -void loader_load_all_classes(void) -{ - list_classpath_entry *lce; -#if defined(ENABLE_ZLIB) - hashtable *ht; - s4 slot; - hashtable_zipfile_entry *htzfe; - utf *u; -#endif - - for (lce = list_first(list_classpath_entries); lce != NULL; - lce = list_next(list_classpath_entries, lce)) { -#if defined(ENABLE_ZLIB) - if (lce->type == CLASSPATH_ARCHIVE) { - /* get the classes hashtable */ - - ht = lce->htclasses; - - for (slot = 0; slot < ht->size; slot++) { - htzfe = (hashtable_zipfile_entry *) ht->ptr[slot]; - - for (; htzfe; htzfe = htzfe->hashlink) { - u = htzfe->filename; - - /* skip all entries in META-INF and .properties, - .png files */ - - if (!strncmp(u->text, "META-INF", strlen("META-INF")) || - strstr(u->text, ".properties") || - strstr(u->text, ".png")) - continue; - - /* load class from bootstrap classloader */ - - if (!load_class_bootstrap(u)) { - fprintf(stderr, "Error loading: "); - utf_fprint_printable_ascii_classname(stderr, u); - fprintf(stderr, "\n"); - -#if !defined(NDEBUG) - /* print out exception and cause */ - - exceptions_print_exception(*exceptionptr); -#endif - } - } - } - - } else { -#endif -#if defined(ENABLE_ZLIB) - } -#endif - } -} - - -/* loader_skip_attribute_body ************************************************** - - Skips an attribute the attribute_name_index has already been read. - - attribute_info { - u2 attribute_name_index; - u4 attribute_length; - u1 info[attribute_length]; - } - -*******************************************************************************/ - -bool loader_skip_attribute_body(classbuffer *cb) -{ - u4 attribute_length; - - if (!suck_check_classbuffer_size(cb, 4)) - return false; - - attribute_length = suck_u4(cb); - - if (!suck_check_classbuffer_size(cb, attribute_length)) - return false; - - suck_skip_nbytes(cb, attribute_length); - - return true; -} - - -/* load_constantpool *********************************************************** - - Loads the constantpool of a class, the entries are transformed into - a simpler format by resolving references (a detailed overview of - the compact structures can be found in global.h). - -*******************************************************************************/ - -static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool) -{ - - /* The following structures are used to save information which cannot be - processed during the first pass. After the complete constantpool has - been traversed the references can be resolved. - (only in specific order) */ - - /* CONSTANT_Class entries */ - typedef struct forward_class { - struct forward_class *next; - u2 thisindex; - u2 name_index; - } forward_class; - - /* CONSTANT_String */ - typedef struct forward_string { - struct forward_string *next; - u2 thisindex; - u2 string_index; - } forward_string; - - /* CONSTANT_NameAndType */ - typedef struct forward_nameandtype { - struct forward_nameandtype *next; - u2 thisindex; - u2 name_index; - u2 sig_index; - } forward_nameandtype; - - /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */ - typedef struct forward_fieldmethint { - struct forward_fieldmethint *next; - u2 thisindex; - u1 tag; - u2 class_index; - u2 nameandtype_index; - } forward_fieldmethint; - - - classinfo *c; - u4 idx; - - forward_class *forward_classes = NULL; - forward_string *forward_strings = NULL; - forward_nameandtype *forward_nameandtypes = NULL; - forward_fieldmethint *forward_fieldmethints = NULL; - - forward_class *nfc; - forward_string *nfs; - forward_nameandtype *nfn; - forward_fieldmethint *nff; - - u4 cpcount; - u1 *cptags; - voidptr *cpinfos; - - c = cb->class; - - /* number of entries in the constant_pool table plus one */ - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - cpcount = c->cpcount = suck_u2(cb); - - /* allocate memory */ - cptags = c->cptags = MNEW(u1, cpcount); - cpinfos = c->cpinfos = MNEW(voidptr, cpcount); - - if (cpcount < 1) { - exceptions_throw_classformaterror(c, "Illegal constant pool size"); - return false; - } - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; -#endif - - /* initialize constantpool */ - for (idx = 0; idx < cpcount; idx++) { - cptags[idx] = CONSTANT_UNUSED; - cpinfos[idx] = NULL; - } - - - /******* first pass *******/ - /* entries which cannot be resolved now are written into - temporary structures and traversed again later */ - - idx = 1; - while (idx < cpcount) { - u4 t; - - /* get constant type */ - if (!suck_check_classbuffer_size(cb, 1)) - return false; - - t = suck_u1(cb); - - switch (t) { - case CONSTANT_Class: - nfc = DNEW(forward_class); - - nfc->next = forward_classes; - forward_classes = nfc; - - nfc->thisindex = idx; - /* reference to CONSTANT_NameAndType */ - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - nfc->name_index = suck_u2(cb); - - idx++; - break; - - case CONSTANT_String: - nfs = DNEW(forward_string); - - nfs->next = forward_strings; - forward_strings = nfs; - - nfs->thisindex = idx; - - /* reference to CONSTANT_Utf8_info with string characters */ - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - nfs->string_index = suck_u2(cb); - - idx++; - break; - - case CONSTANT_NameAndType: - nfn = DNEW(forward_nameandtype); - - nfn->next = forward_nameandtypes; - forward_nameandtypes = nfn; - - nfn->thisindex = idx; - - if (!suck_check_classbuffer_size(cb, 2 + 2)) - return false; - - /* reference to CONSTANT_Utf8_info containing simple name */ - nfn->name_index = suck_u2(cb); - - /* reference to CONSTANT_Utf8_info containing field or method - descriptor */ - nfn->sig_index = suck_u2(cb); - - idx++; - break; - - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - nff = DNEW(forward_fieldmethint); - - nff->next = forward_fieldmethints; - forward_fieldmethints = nff; - - nff->thisindex = idx; - /* constant type */ - nff->tag = t; - - if (!suck_check_classbuffer_size(cb, 2 + 2)) - return false; - - /* class or interface type that contains the declaration of the - field or method */ - nff->class_index = suck_u2(cb); - - /* name and descriptor of the field or method */ - nff->nameandtype_index = suck_u2(cb); - - idx++; - break; - - case CONSTANT_Integer: { - constant_integer *ci = NEW(constant_integer); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_integer); -#endif - - if (!suck_check_classbuffer_size(cb, 4)) - return false; - - ci->value = suck_s4(cb); - cptags[idx] = CONSTANT_Integer; - cpinfos[idx] = ci; - - idx++; - break; - } - - case CONSTANT_Float: { - constant_float *cf = NEW(constant_float); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_float); -#endif - - if (!suck_check_classbuffer_size(cb, 4)) - return false; - - cf->value = suck_float(cb); - cptags[idx] = CONSTANT_Float; - cpinfos[idx] = cf; - - idx++; - break; - } - - case CONSTANT_Long: { - constant_long *cl = NEW(constant_long); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_long); -#endif - - if (!suck_check_classbuffer_size(cb, 8)) - return false; - - cl->value = suck_s8(cb); - cptags[idx] = CONSTANT_Long; - cpinfos[idx] = cl; - idx += 2; - if (idx > cpcount) { - exceptions_throw_classformaterror(c, "Invalid constant pool entry"); - return false; - } - break; - } - - case CONSTANT_Double: { - constant_double *cd = NEW(constant_double); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_double); -#endif - - if (!suck_check_classbuffer_size(cb, 8)) - return false; - - cd->value = suck_double(cb); - cptags[idx] = CONSTANT_Double; - cpinfos[idx] = cd; - idx += 2; - if (idx > cpcount) { - exceptions_throw_classformaterror(c, "Invalid constant pool entry"); - return false; - } - break; - } - - case CONSTANT_Utf8: { - u4 length; - - /* number of bytes in the bytes array (not string-length) */ - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - length = suck_u2(cb); - cptags[idx] = CONSTANT_Utf8; - - /* validate the string */ - if (!suck_check_classbuffer_size(cb, length)) - return false; - -#ifdef ENABLE_VERIFIER - if (opt_verify && - !is_valid_utf((char *) cb->pos, (char *) (cb->pos + length))) - { - exceptions_throw_classformaterror(c, "Invalid UTF-8 string"); - return false; - } -#endif /* ENABLE_VERIFIER */ - /* insert utf-string into the utf-symboltable */ - cpinfos[idx] = utf_new((char *) cb->pos, length); - - /* skip bytes of the string (buffer size check above) */ - suck_skip_nbytes(cb, length); - idx++; - break; - } - - default: - exceptions_throw_classformaterror(c, "Illegal constant pool type"); - return false; - } /* end switch */ - } /* end while */ - - - /* resolve entries in temporary structures */ - - while (forward_classes) { - utf *name = - class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); - if (!name) - return false; - -#ifdef ENABLE_VERIFIER - if (opt_verify && !is_valid_name_utf(name)) { - exceptions_throw_classformaterror(c, "Class reference with invalid name"); - return false; - } -#endif /* ENABLE_VERIFIER */ - - /* add all class references to the descriptor_pool */ - - if (!descriptor_pool_add_class(descpool, name)) - return false; - - cptags[forward_classes->thisindex] = CONSTANT_Class; - - if (opt_eager) { - classinfo *tc; - - if (!(tc = load_class_bootstrap(name))) - return false; - - /* link the class later, because we cannot link the class currently - loading */ - list_add_first(&unlinkedclasses, tc); - } - - /* the classref is created later */ - cpinfos[forward_classes->thisindex] = name; - - nfc = forward_classes; - forward_classes = forward_classes->next; - } - - while (forward_strings) { - utf *text = - class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); - if (!text) - return false; - - /* resolve utf-string */ - cptags[forward_strings->thisindex] = CONSTANT_String; - cpinfos[forward_strings->thisindex] = text; - - nfs = forward_strings; - forward_strings = forward_strings->next; - } - - while (forward_nameandtypes) { - constant_nameandtype *cn = NEW(constant_nameandtype); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_nameandtype); -#endif - - /* resolve simple name and descriptor */ - cn->name = class_getconstant(c, - forward_nameandtypes->name_index, - CONSTANT_Utf8); - if (!cn->name) - return false; - - cn->descriptor = class_getconstant(c, - forward_nameandtypes->sig_index, - CONSTANT_Utf8); - if (!cn->descriptor) - return false; - -#ifdef ENABLE_VERIFIER - if (opt_verify) { - /* check name */ - if (!is_valid_name_utf(cn->name)) { - exceptions_throw_classformaterror(c, - "Illegal Field name \"%s\"", - cn->name->text); - - return false; - } - - /* disallow referencing among others */ - if (cn->name->text[0] == '<' && cn->name != utf_init) { - exceptions_throw_classformaterror(c, "Illegal reference to special method"); - return false; - } - } -#endif /* ENABLE_VERIFIER */ - - cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; - cpinfos[forward_nameandtypes->thisindex] = cn; - - nfn = forward_nameandtypes; - forward_nameandtypes = forward_nameandtypes->next; - } - - while (forward_fieldmethints) { - constant_nameandtype *nat; - constant_FMIref *fmi = NEW(constant_FMIref); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_FMIref); -#endif - /* resolve simple name and descriptor */ - - nat = class_getconstant(c, - forward_fieldmethints->nameandtype_index, - CONSTANT_NameAndType); - if (!nat) - return false; - - /* add all descriptors in {Field,Method}ref to the descriptor_pool */ - - if (!descriptor_pool_add(descpool, nat->descriptor, NULL)) - return false; - - /* the classref is created later */ - - fmi->p.index = forward_fieldmethints->class_index; - fmi->name = nat->name; - fmi->descriptor = nat->descriptor; - - cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag; - cpinfos[forward_fieldmethints->thisindex] = fmi; - - nff = forward_fieldmethints; - forward_fieldmethints = forward_fieldmethints->next; - } - - /* everything was ok */ - - return true; -} - - -/* loader_load_attribute_signature ********************************************* - - Signature_attribute { - u2 attribute_name_index; - u4 atrribute_length; - u2 signature_index; - } - -*******************************************************************************/ - -#if defined(ENABLE_JAVASE) -bool loader_load_attribute_signature(classbuffer *cb, utf **signature) -{ - classinfo *c; - u4 attribute_length; - u2 signature_index; - - /* get classinfo */ - - c = cb->class; - - /* check remaining bytecode */ - - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* check attribute length */ - - attribute_length = suck_u4(cb); - - if (attribute_length != 2) { - exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); - return false; - } - - if (*signature != NULL) { - exceptions_throw_classformaterror(c, "Multiple Signature attributes"); - return false; - } - - /* get signature */ - - signature_index = suck_u2(cb); - - if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8))) - return false; - - return true; -} -#endif /* defined(ENABLE_JAVASE) */ - - -/* load_field ****************************************************************** - - Load everything about a class field from the class file and fill a - 'fieldinfo' structure. For static fields, space in the data segment - is allocated. - -*******************************************************************************/ - -#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ - -static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool) -{ - classinfo *c; - u4 attrnum, i; - u4 jtype; - u4 pindex = field_load_NOVALUE; /* constantvalue_index */ - utf *u; - - c = cb->class; - - if (!suck_check_classbuffer_size(cb, 2 + 2 + 2)) - return false; - - f->flags = suck_u2(cb); - - if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) - return false; - - f->name = u; - - if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) - return false; - - f->descriptor = u; - f->parseddesc = NULL; - - if (!descriptor_pool_add(descpool, u, NULL)) - return false; - - /* descriptor_pool_add accepts method descriptors, so we have to check */ - /* against them here before the call of descriptor_to_basic_type below. */ - if (u->text[0] == '(') { - exceptions_throw_classformaterror(c, "Method descriptor used for field"); - return false; - } - -#ifdef ENABLE_VERIFIER - if (opt_verify) { - /* check name */ - if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') { - exceptions_throw_classformaterror(c, - "Illegal Field name \"%s\"", - f->name->text); - return false; - } - - /* check flag consistency */ - i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED); - - if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) || - ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) { - exceptions_throw_classformaterror(c, - "Illegal field modifiers: 0x%X", - f->flags); - return false; - } - - if (c->flags & ACC_INTERFACE) { - if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) - != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) || - f->flags & ACC_TRANSIENT) { - exceptions_throw_classformaterror(c, - "Illegal field modifiers: 0x%X", - f->flags); - return false; - } - } - } -#endif /* ENABLE_VERIFIER */ - - f->type = jtype = descriptor_to_basic_type(f->descriptor); /* data type */ - f->offset = 0; /* offset from start of object */ - f->class = c; - - switch (f->type) { - case TYPE_INT: - f->value.i = 0; - break; - - case TYPE_FLT: - f->value.f = 0.0; - break; - - case TYPE_DBL: - f->value.d = 0.0; - break; - - case TYPE_ADR: - f->value.a = NULL; - if (!(f->flags & ACC_STATIC)) - c->flags |= ACC_CLASS_HAS_POINTERS; - break; - - case TYPE_LNG: -#if U8_AVAILABLE - f->value.l = 0; -#else - f->value.l.low = 0; - f->value.l.high = 0; -#endif - break; - } - - /* read attributes */ - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - attrnum = suck_u2(cb); - for (i = 0; i < attrnum; i++) { - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) - return false; - - if (u == utf_ConstantValue) { - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* check attribute length */ - - if (suck_u4(cb) != 2) { - exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); - return false; - } - - /* constant value attribute */ - - if (pindex != field_load_NOVALUE) { - exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes"); - return false; - } - - /* index of value in constantpool */ - - pindex = suck_u2(cb); - - /* initialize field with value from constantpool */ - switch (jtype) { - case TYPE_INT: { - constant_integer *ci; - - if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer))) - return false; - - f->value.i = ci->value; - } - break; - - case TYPE_LNG: { - constant_long *cl; - - if (!(cl = class_getconstant(c, pindex, CONSTANT_Long))) - return false; - - f->value.l = cl->value; - } - break; - - case TYPE_FLT: { - constant_float *cf; - - if (!(cf = class_getconstant(c, pindex, CONSTANT_Float))) - return false; - - f->value.f = cf->value; - } - break; - - case TYPE_DBL: { - constant_double *cd; - - if (!(cd = class_getconstant(c, pindex, CONSTANT_Double))) - return false; - - f->value.d = cd->value; - } - break; - - case TYPE_ADR: - if (!(u = class_getconstant(c, pindex, CONSTANT_String))) - return false; - - /* create javastring from compressed utf8-string */ - f->value.a = literalstring_new(u); - break; - - default: - log_text("Invalid Constant - Type"); - } - } -#if defined(ENABLE_JAVASE) - else if (u == utf_Signature) { - /* Signature */ - - if (!loader_load_attribute_signature(cb, &(f->signature))) - return false; - } -#endif - else { - /* unknown attribute */ - - if (!loader_skip_attribute_body(cb)) - return false; - } - } - - /* everything was ok */ - - return true; -} - - -/* loader_load_method ********************************************************** - - Loads a method from the class file and fills an existing - 'methodinfo' structure. For native methods, the function pointer - field is set to the real function pointer, for JavaVM methods a - pointer to the compiler is used preliminarily. - - 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]; - } - -*******************************************************************************/ - -static bool loader_load_method(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->class; - -#if defined(ENABLE_THREADS) - lock_init_object_lock(&m->header); -#endif - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_all_methods++; -#endif - - /* all fields of m have been zeroed in load_class_from_classbuffer */ - - m->class = 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); - - if (!(attribute_name = class_getconstant(c, attribute_name_index, CONSTANT_Utf8))) - 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); - - if (!(code_attribute_name = class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8))) - 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); - - 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; - } -#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; - } - - /* everything was ok */ - - return true; -} - - -/* load_class_from_sysloader *************************************************** - - Load the class with the given name using the system class loader - - IN: - name.............the classname - - RETURN VALUE: - the loaded class, or - NULL if an exception has been thrown - -*******************************************************************************/ - -classinfo *load_class_from_sysloader(utf *name) -{ - methodinfo *m; - java_objectheader *cl; - classinfo *c; - - assert(class_java_lang_Object); - assert(class_java_lang_ClassLoader); - assert(class_java_lang_ClassLoader->state & CLASS_LINKED); - - m = class_resolveclassmethod(class_java_lang_ClassLoader, - utf_getSystemClassLoader, - utf_void__java_lang_ClassLoader, - class_java_lang_Object, - false); - - if (!m) - return false; - - cl = vm_call_method(m, NULL); - - if (!cl) - return false; - - c = load_class_from_classloader(name, cl); - - return c; -} - - -/* load_class_from_classloader ************************************************* - - Load the class with the given name using the given user-defined class loader. - - IN: - name.............the classname - cl...............user-defined class loader - - RETURN VALUE: - the loaded class, or - NULL if an exception has been thrown - -*******************************************************************************/ - -classinfo *load_class_from_classloader(utf *name, java_objectheader *cl) -{ - java_objectheader *o; - classinfo *c; - classinfo *tmpc; - java_lang_String *s; -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_lookup, time_prepare, time_java, - time_cache; -#endif - - RT_TIMING_GET_TIME(time_start); - - assert(name); - - /* lookup if this class has already been loaded */ - - c = classcache_lookup(cl, name); - - RT_TIMING_GET_TIME(time_lookup); - RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_CL_LOOKUP); - - if (c) - return c; - - /* if other class loader than bootstrap, call it */ - - if (cl) { - methodinfo *lc; - char *text; - s4 namelen; - - text = name->text; - namelen = name->blength; - - /* handle array classes */ - if (text[0] == '[') { - classinfo *comp; - utf *u; - - switch (text[1]) { - case 'L': - /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ - if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') { - *exceptionptr = new_noclassdeffounderror(name); - return false; - } - - u = utf_new(text + 2, namelen - 3); - - if (!(comp = load_class_from_classloader(u, cl))) - return false; - - /* create the array class */ - - c = class_array_of(comp, false); - - tmpc = classcache_store(cl, c, true); - - if (tmpc == NULL) { - /* exception, free the loaded class */ - c->state &= ~CLASS_LOADING; - class_free(c); - } - - return tmpc; - - case '[': - /* load the component class */ - - u = utf_new(text + 1, namelen - 1); - - if (!(comp = load_class_from_classloader(u, cl))) - return false; - - /* create the array class */ - - c = class_array_of(comp, false); - - tmpc = classcache_store(cl, c, true); - - if (tmpc == NULL) { - /* exception, free the loaded class */ - c->state &= ~CLASS_LOADING; - class_free(c); - } - - return tmpc; - - default: - /* primitive array classes are loaded by the bootstrap loader */ - - c = load_class_bootstrap(name); - - return c; - } - } - - assert(class_java_lang_Object); - - lc = class_resolveclassmethod(cl->vftbl->class, - utf_loadClass, - utf_java_lang_String__java_lang_Class, - class_java_lang_Object, - true); - - if (!lc) - return false; /* exception */ - - /* move return value into `o' and cast it afterwards to a classinfo* */ - - s = javastring_new_slash_to_dot(name); - - RT_TIMING_GET_TIME(time_prepare); - - o = vm_call_method(lc, cl, s); - - RT_TIMING_GET_TIME(time_java); - - c = (classinfo *) o; - - if (c) { - /* Store this class in the loaded class cache. If another - class with the same (initloader,name) pair has been - stored earlier it will be returned by classcache_store - In this case classcache_store may not free the class - because it has already been exposed to Java code which - may have kept references to that class. */ - - tmpc = classcache_store(cl, c, false); - - if (tmpc == NULL) { - /* exception, free the loaded class */ - c->state &= ~CLASS_LOADING; - class_free(c); - } - - c = tmpc; - - } else { - /* loadClass has thrown an exception. We must convert - ClassNotFoundException into - NoClassDefFoundException. */ - - /* XXX Maybe we should have a flag that avoids this - conversion for calling load_class_from_classloader from - Class.forName. Currently we do a double conversion in - these cases. */ - - classnotfoundexception_to_noclassdeffounderror(); - } - - RT_TIMING_GET_TIME(time_cache); - - RT_TIMING_TIME_DIFF(time_lookup , time_prepare, RT_TIMING_LOAD_CL_PREPARE); - RT_TIMING_TIME_DIFF(time_prepare, time_java , RT_TIMING_LOAD_CL_JAVA); - RT_TIMING_TIME_DIFF(time_java , time_cache , RT_TIMING_LOAD_CL_CACHE); - - /* SUN compatible -verbose:class output */ - - if (opt_verboseclass && (c != NULL) && (c->classloader == cl)) { - printf("[Loaded "); - utf_display_printable_ascii_classname(name); - printf("]\n"); - } - -#if defined(ENABLE_JVMTI) - /* fire Class Load JVMTI event */ - if (jvmti) jvmti_ClassLoadPrepare(false, c); -#endif - - - return c; - } - - c = load_class_bootstrap(name); - - return c; -} - - -/* load_class_bootstrap ******************************************************** - - Load the class with the given name using the bootstrap class loader. - - IN: - name.............the classname - - RETURN VALUE: - loaded classinfo, or - NULL if an exception has been thrown - - SYNCHRONIZATION: - load_class_bootstrap is synchronized. It can be treated as an - atomic operation. - -*******************************************************************************/ - -classinfo *load_class_bootstrap(utf *name) -{ - classbuffer *cb; - classinfo *c; - classinfo *r; -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_lookup, time_array, time_suck, - time_load, time_cache; -#endif - - RT_TIMING_GET_TIME(time_start); - - /* for debugging */ - - assert(name); - - /* lookup if this class has already been loaded */ - - if ((r = classcache_lookup(NULL, name))) { - - RT_TIMING_GET_TIME(time_lookup); - RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP); - - return r; - } - - RT_TIMING_GET_TIME(time_lookup); - RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP); - - /* create the classinfo */ - - c = class_create_classinfo(name); - - /* handle array classes */ - - if (name->text[0] == '[') { - c = load_newly_created_array(c, NULL); - if (c == NULL) - return NULL; - assert(c->state & CLASS_LOADED); - - RT_TIMING_GET_TIME(time_array); - RT_TIMING_TIME_DIFF(time_start,time_array,RT_TIMING_LOAD_BOOT_ARRAY); - - return c; - } - -#if defined(ENABLE_STATISTICS) - /* measure time */ - - if (opt_getcompilingtime) - compilingtime_stop(); - - if (opt_getloadingtime) - loadingtime_start(); -#endif - - /* load classdata, throw exception on error */ - - if ((cb = suck_start(c)) == NULL) { - /* this normally means, the classpath was not set properly */ - - if (name == utf_java_lang_Object) - vm_abort("%s: java/lang/Object", string_java_lang_NoClassDefFoundError); - - *exceptionptr = new_noclassdeffounderror(name); - - return NULL; - } - - RT_TIMING_GET_TIME(time_suck); - - /* load the class from the buffer */ - - r = load_class_from_classbuffer(cb); - - RT_TIMING_GET_TIME(time_load); - - if (!r) { - /* the class could not be loaded, free the classinfo struct */ - - class_free(c); - - } else { - /* Store this class in the loaded class cache this step also - checks the loading constraints. If the class has been loaded - before, the earlier loaded class is returned. */ - - classinfo *res = classcache_store(NULL, c, true); - - if (!res) { - /* exception */ - class_free(c); - } - - r = res; - } - - RT_TIMING_GET_TIME(time_cache); - - /* SUN compatible -verbose:class output */ - - if (opt_verboseclass && r) { - printf("[Loaded "); - utf_display_printable_ascii_classname(name); - printf(" from %s]\n", cb->path); - } - - /* free memory */ - - suck_stop(cb); - -#if defined(ENABLE_STATISTICS) - /* measure time */ - - if (opt_getloadingtime) - loadingtime_stop(); - - if (opt_getcompilingtime) - compilingtime_start(); -#endif - - RT_TIMING_TIME_DIFF(time_lookup, time_suck , RT_TIMING_LOAD_BOOT_SUCK); - RT_TIMING_TIME_DIFF(time_suck , time_load , RT_TIMING_LOAD_BOOT_LOAD); - RT_TIMING_TIME_DIFF(time_load , time_cache, RT_TIMING_LOAD_BOOT_CACHE); - RT_TIMING_TIME_DIFF(time_lookup, time_cache, RT_TIMING_LOAD_BOOT_TOTAL); - - return r; -} - - -/* load_class_from_classbuffer ************************************************* - - Loads everything interesting about a class from the class file. The - 'classinfo' structure must have been allocated previously. - - The super class and the interfaces implemented by this class need - not be loaded. The link is set later by the function 'class_link'. - - The loaded class is removed from the list 'unloadedclasses' and - added to the list 'unlinkedclasses'. - - SYNCHRONIZATION: - This function is NOT synchronized! - -*******************************************************************************/ - -classinfo *load_class_from_classbuffer(classbuffer *cb) -{ - classinfo *c; - utf *name; - utf *supername; - u4 i,j; - u4 ma, mi; - s4 dumpsize; - descriptor_pool *descpool; -#if defined(ENABLE_STATISTICS) - u4 classrefsize; - u4 descsize; -#endif -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_checks, time_ndpool, time_cpool, - time_setup, time_fields, time_methods, time_classrefs, - time_descs, time_setrefs, time_parsefds, time_parsemds, - time_parsecpool, time_verify, time_attrs; -#endif - - RT_TIMING_GET_TIME(time_start); - - /* get the classbuffer's class */ - - c = cb->class; - - /* the class is already loaded */ - - if (c->state & CLASS_LOADED) - return c; - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_class_loads++; -#endif - -#if !defined(NDEBUG) - /* output for debugging purposes */ - - if (loadverbose) - log_message_class("Loading class: ", c); -#endif - - /* mark start of dump memory area */ - - dumpsize = dump_size(); - - /* class is currently loading */ - - c->state |= CLASS_LOADING; - - if (!suck_check_classbuffer_size(cb, 4 + 2 + 2)) - goto return_exception; - - /* check signature */ - - if (suck_u4(cb) != MAGIC) { - exceptions_throw_classformaterror(c, "Bad magic number"); - - goto return_exception; - } - - /* check version */ - - mi = suck_u2(cb); - ma = suck_u2(cb); - - if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { - *exceptionptr = - new_unsupportedclassversionerror(c, - "Unsupported major.minor version %d.%d", - ma, mi); - - goto return_exception; - } - RT_TIMING_GET_TIME(time_checks); - - /* create a new descriptor pool */ - - descpool = descriptor_pool_new(c); - - RT_TIMING_GET_TIME(time_ndpool); - - /* load the constant pool */ - - if (!load_constantpool(cb, descpool)) - goto return_exception; - - RT_TIMING_GET_TIME(time_cpool); - - /* ACC flags */ - - if (!suck_check_classbuffer_size(cb, 2)) - goto return_exception; - - c->flags = suck_u2(cb); - - /* check ACC flags consistency */ - - if (c->flags & ACC_INTERFACE) { - if (!(c->flags & ACC_ABSTRACT)) { - /* We work around this because interfaces in JDK 1.1 are - * not declared abstract. */ - - c->flags |= ACC_ABSTRACT; - } - - if (c->flags & ACC_FINAL) { - exceptions_throw_classformaterror(c, - "Illegal class modifiers: 0x%X", - c->flags); - goto return_exception; - } - - if (c->flags & ACC_SUPER) { - c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */ - } - } - - if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { - exceptions_throw_classformaterror(c, - "Illegal class modifiers: 0x%X", - c->flags); - goto return_exception; - } - - if (!suck_check_classbuffer_size(cb, 2 + 2)) - goto return_exception; - - /* this class */ - - i = suck_u2(cb); - if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class))) - goto return_exception; - - if (c->name == utf_not_named_yet) { - /* we finally have a name for this class */ - c->name = name; - class_set_packagename(c); - - } else if (name != c->name) { - char *msg; - s4 msglen; - - msglen = utf_bytes(c->name) + strlen(" (wrong name: ") + - utf_bytes(name) + strlen(")") + strlen("0"); - - msg = MNEW(char, msglen); - - utf_copy_classname(msg, c->name); - strcat(msg, " (wrong name: "); - utf_cat_classname(msg, name); - strcat(msg, ")"); - - *exceptionptr = - new_exception_message(string_java_lang_NoClassDefFoundError, msg); - - MFREE(msg, char, msglen); - - goto return_exception; - } - - /* retrieve superclass */ - - c->super.any = NULL; - if ((i = suck_u2(cb))) { - if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class))) - goto return_exception; - - /* java.lang.Object may not have a super class. */ - - if (c->name == utf_java_lang_Object) { - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - "java.lang.Object with superclass"); - - goto return_exception; - } - - /* Interfaces must have java.lang.Object as super class. */ - - if ((c->flags & ACC_INTERFACE) && - supername != utf_java_lang_Object) { - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - "Interfaces must have java.lang.Object as superclass"); - - goto return_exception; - } - - } else { - supername = NULL; - - /* This is only allowed for java.lang.Object. */ - - if (c->name != utf_java_lang_Object) { - exceptions_throw_classformaterror(c, "Bad superclass index"); - goto return_exception; - } - } - - /* retrieve interfaces */ - - if (!suck_check_classbuffer_size(cb, 2)) - goto return_exception; - - c->interfacescount = suck_u2(cb); - - if (!suck_check_classbuffer_size(cb, 2 * c->interfacescount)) - goto return_exception; - - c->interfaces = MNEW(classref_or_classinfo, c->interfacescount); - for (i = 0; i < c->interfacescount; i++) { - /* the classrefs are created later */ - if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) - goto return_exception; - } - - RT_TIMING_GET_TIME(time_setup); - - /* load fields */ - if (!suck_check_classbuffer_size(cb, 2)) - goto return_exception; - - c->fieldscount = suck_u2(cb); -#if defined(ENABLE_GC_CACAO) - c->fields = MNEW(fieldinfo, c->fieldscount); - MZERO(c->fields, fieldinfo, c->fieldscount); -#else - c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount); -#endif - - for (i = 0; i < c->fieldscount; i++) { - if (!load_field(cb, &(c->fields[i]),descpool)) - goto return_exception; - } - - RT_TIMING_GET_TIME(time_fields); - - /* load methods */ - if (!suck_check_classbuffer_size(cb, 2)) - goto return_exception; - - c->methodscount = suck_u2(cb); - c->methods = MNEW(methodinfo, c->methodscount); - - MZERO(c->methods, methodinfo, c->methodscount); - - for (i = 0; i < c->methodscount; i++) { - if (!loader_load_method(cb, &(c->methods[i]), descpool)) - goto return_exception; - } - - RT_TIMING_GET_TIME(time_methods); - - /* create the class reference table */ - - c->classrefs = - descriptor_pool_create_classrefs(descpool, &(c->classrefcount)); - - RT_TIMING_GET_TIME(time_classrefs); - - /* allocate space for the parsed descriptors */ - - descriptor_pool_alloc_parsed_descriptors(descpool); - c->parseddescs = - descriptor_pool_get_parsed_descriptors(descpool, &(c->parseddescsize)); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - descriptor_pool_get_sizes(descpool, &classrefsize, &descsize); - count_classref_len += classrefsize; - count_parsed_desc_len += descsize; - } -#endif - - RT_TIMING_GET_TIME(time_descs); - - /* put the classrefs in the constant pool */ - for (i = 0; i < c->cpcount; i++) { - if (c->cptags[i] == CONSTANT_Class) { - utf *name = (utf *) c->cpinfos[i]; - c->cpinfos[i] = descriptor_pool_lookup_classref(descpool, name); - } - } - - /* set the super class reference */ - - if (supername) { - c->super.ref = descriptor_pool_lookup_classref(descpool, supername); - if (!c->super.ref) - goto return_exception; - } - - /* set the super interfaces references */ - - for (i = 0; i < c->interfacescount; i++) { - c->interfaces[i].ref = - descriptor_pool_lookup_classref(descpool, - (utf *) c->interfaces[i].any); - if (!c->interfaces[i].ref) - goto return_exception; - } - - RT_TIMING_GET_TIME(time_setrefs); - - /* parse field descriptors */ - - for (i = 0; i < c->fieldscount; i++) { - c->fields[i].parseddesc = - descriptor_pool_parse_field_descriptor(descpool, - c->fields[i].descriptor); - if (!c->fields[i].parseddesc) - goto return_exception; - } - - RT_TIMING_GET_TIME(time_parsefds); - - /* parse method descriptors */ - - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &c->methods[i]; - m->parseddesc = - descriptor_pool_parse_method_descriptor(descpool, m->descriptor, - m->flags, class_get_self_classref(m->class)); - if (!m->parseddesc) - goto return_exception; - - for (j = 0; j < m->rawexceptiontablelength; j++) { - if (!m->rawexceptiontable[j].catchtype.any) - continue; - if ((m->rawexceptiontable[j].catchtype.ref = - descriptor_pool_lookup_classref(descpool, - (utf *) m->rawexceptiontable[j].catchtype.any)) == NULL) - goto return_exception; - } - - for (j = 0; j < m->thrownexceptionscount; j++) { - if (!m->thrownexceptions[j].any) - continue; - if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool, - (utf *) m->thrownexceptions[j].any)) == NULL) - goto return_exception; - } - } - - RT_TIMING_GET_TIME(time_parsemds); - - /* parse the loaded descriptors */ - - for (i = 0; i < c->cpcount; i++) { - constant_FMIref *fmi; - s4 index; - - switch (c->cptags[i]) { - case CONSTANT_Fieldref: - fmi = (constant_FMIref *) c->cpinfos[i]; - fmi->parseddesc.fd = - descriptor_pool_parse_field_descriptor(descpool, - fmi->descriptor); - if (!fmi->parseddesc.fd) - goto return_exception; - index = fmi->p.index; - fmi->p.classref = - (constant_classref *) class_getconstant(c, index, - CONSTANT_Class); - if (!fmi->p.classref) - goto return_exception; - break; - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - fmi = (constant_FMIref *) c->cpinfos[i]; - index = fmi->p.index; - fmi->p.classref = - (constant_classref *) class_getconstant(c, index, - CONSTANT_Class); - if (!fmi->p.classref) - goto return_exception; - fmi->parseddesc.md = - descriptor_pool_parse_method_descriptor(descpool, - fmi->descriptor, - ACC_UNDEF, - fmi->p.classref); - if (!fmi->parseddesc.md) - goto return_exception; - break; - } - } - - RT_TIMING_GET_TIME(time_parsecpool); - -#ifdef ENABLE_VERIFIER - /* Check if all fields and methods can be uniquely - * identified by (name,descriptor). */ - - if (opt_verify) { - /* We use a hash table here to avoid making the - * average case quadratic in # of methods, fields. - */ - static int shift = 0; - u2 *hashtab; - u2 *next; /* for chaining colliding hash entries */ - size_t len; - size_t hashlen; - u2 index; - u2 old; - - /* Allocate hashtable */ - len = c->methodscount; - if (len < c->fieldscount) len = c->fieldscount; - hashlen = 5 * len; - hashtab = MNEW(u2,(hashlen + len)); - next = hashtab + hashlen; - - /* Determine bitshift (to get good hash values) */ - if (!shift) { - len = sizeof(utf); - while (len) { - len >>= 1; - shift++; - } - } - - /* Check fields */ - memset(hashtab, 0, sizeof(u2) * (hashlen + len)); - - for (i = 0; i < c->fieldscount; ++i) { - fieldinfo *fi = c->fields + i; - - /* It's ok if we lose bits here */ - index = ((((size_t) fi->name) + - ((size_t) fi->descriptor)) >> shift) % hashlen; - - if ((old = hashtab[index])) { - old--; - next[i] = old; - do { - if (c->fields[old].name == fi->name && - c->fields[old].descriptor == fi->descriptor) { - exceptions_throw_classformaterror(c, "Repetitive field name/signature"); - goto return_exception; - } - } while ((old = next[old])); - } - hashtab[index] = i + 1; - } - - /* Check methods */ - memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5)); - - for (i = 0; i < c->methodscount; ++i) { - methodinfo *mi = c->methods + i; - - /* It's ok if we lose bits here */ - index = ((((size_t) mi->name) + - ((size_t) mi->descriptor)) >> shift) % hashlen; - - /*{ JOWENN - int dbg; - for (dbg=0;dbgmethods[old].name == mi->name && - c->methods[old].descriptor == mi->descriptor) { - exceptions_throw_classformaterror(c, "Repetitive method name/signature"); - goto return_exception; - } - } while ((old = next[old])); - } - hashtab[index] = i + 1; - } - - MFREE(hashtab, u2, (hashlen + len)); - } -#endif /* ENABLE_VERIFIER */ - - RT_TIMING_GET_TIME(time_verify); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - size_classinfo += sizeof(classinfo*) * c->interfacescount; - size_fieldinfo += sizeof(fieldinfo) * c->fieldscount; - size_methodinfo += sizeof(methodinfo) * c->methodscount; - } -#endif - - /* load attribute structures */ - - if (!class_load_attributes(cb)) - goto return_exception; - - /* Pre Java 1.5 version don't check this. This implementation is like - Java 1.5 do it: for class file version 45.3 we don't check it, older - versions are checked. - */ - - if (((ma == 45) && (mi > 3)) || (ma > 45)) { - /* check if all data has been read */ - s4 classdata_left = ((cb->data + cb->size) - cb->pos); - - if (classdata_left > 0) { - exceptions_throw_classformaterror(c, "Extra bytes at the end of class file"); - goto return_exception; - } - } - - RT_TIMING_GET_TIME(time_attrs); - - /* release dump area */ - - dump_release(dumpsize); - - /* revert loading state and class is loaded */ - - c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED; - -#if defined(ENABLE_JVMTI) - /* fire Class Prepare JVMTI event */ - - if (jvmti) - jvmti_ClassLoadPrepare(true, c); -#endif - -#if !defined(NDEBUG) - if (loadverbose) - log_message_class("Loading done class: ", c); -#endif - - RT_TIMING_TIME_DIFF(time_start , time_checks , RT_TIMING_LOAD_CHECKS); - RT_TIMING_TIME_DIFF(time_checks , time_ndpool , RT_TIMING_LOAD_NDPOOL); - RT_TIMING_TIME_DIFF(time_ndpool , time_cpool , RT_TIMING_LOAD_CPOOL); - RT_TIMING_TIME_DIFF(time_cpool , time_setup , RT_TIMING_LOAD_SETUP); - RT_TIMING_TIME_DIFF(time_setup , time_fields , RT_TIMING_LOAD_FIELDS); - RT_TIMING_TIME_DIFF(time_fields , time_methods , RT_TIMING_LOAD_METHODS); - RT_TIMING_TIME_DIFF(time_methods , time_classrefs , RT_TIMING_LOAD_CLASSREFS); - RT_TIMING_TIME_DIFF(time_classrefs , time_descs , RT_TIMING_LOAD_DESCS); - RT_TIMING_TIME_DIFF(time_descs , time_setrefs , RT_TIMING_LOAD_SETREFS); - RT_TIMING_TIME_DIFF(time_setrefs , time_parsefds , RT_TIMING_LOAD_PARSEFDS); - RT_TIMING_TIME_DIFF(time_parsefds , time_parsemds , RT_TIMING_LOAD_PARSEMDS); - RT_TIMING_TIME_DIFF(time_parsemds , time_parsecpool, RT_TIMING_LOAD_PARSECP); - RT_TIMING_TIME_DIFF(time_parsecpool, time_verify , RT_TIMING_LOAD_VERIFY); - RT_TIMING_TIME_DIFF(time_verify , time_attrs , RT_TIMING_LOAD_ATTRS); - RT_TIMING_TIME_DIFF(time_start , time_attrs , RT_TIMING_LOAD_TOTAL); - - return c; - -return_exception: - /* release dump area */ - - dump_release(dumpsize); - - /* an exception has been thrown */ - - return NULL; -} - - -/* load_newly_created_array **************************************************** - - Load a newly created array class. - - RETURN VALUE: - c....................the array class C has been loaded - other classinfo......the array class was found in the class cache, - C has been freed - NULL.................an exception has been thrown - - Note: - This is an internal function. Do not use it unless you know exactly - what you are doing! - - Use one of the load_class_... functions for general array class loading. - -*******************************************************************************/ - -classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader) -{ - classinfo *comp = NULL; - methodinfo *clone; - methoddesc *clonedesc; - constant_classref *classrefs; - char *text; - s4 namelen; - utf *u; - - text = c->name->text; - namelen = c->name->blength; - - /* Check array class name */ - - if (namelen < 2 || text[0] != '[') { - *exceptionptr = new_noclassdeffounderror(c->name); - return NULL; - } - - /* Check the element type */ - - switch (text[1]) { - case '[': - /* c is an array of arrays. We have to create the component class. */ - - u = utf_new(text + 1, namelen - 1); - if (!(comp = load_class_from_classloader(u, loader))) - return NULL; - - assert(comp->state & CLASS_LOADED); - - if (opt_eager) - if (!link_class(c)) - return NULL; - - /* the array's flags are that of the component class */ - c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; - c->classloader = comp->classloader; - break; - - case 'L': - /* c is an array of objects. */ - - /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ - if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') { - *exceptionptr = new_noclassdeffounderror(c->name); - return NULL; - } - - u = utf_new(text + 2, namelen - 3); - - if (!(comp = load_class_from_classloader(u, loader))) - return NULL; - - assert(comp->state & CLASS_LOADED); - - if (opt_eager) - if (!link_class(c)) - return NULL; - - /* the array's flags are that of the component class */ - c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; - c->classloader = comp->classloader; - break; - - default: - /* c is an array of a primitive type */ - - /* check for cases like `[II' */ - if (namelen > 2) { - *exceptionptr = new_noclassdeffounderror(c->name); - return NULL; - } - - /* the accessibility of the array class is public (VM Spec 5.3.3) */ - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; - c->classloader = NULL; - } - - assert(class_java_lang_Object); -#if defined(ENABLE_JAVASE) - assert(class_java_lang_Cloneable); - assert(class_java_io_Serializable); -#endif - - /* setup the array class */ - - c->super.cls = class_java_lang_Object; - -#if defined(ENABLE_JAVASE) - c->interfacescount = 2; - c->interfaces = MNEW(classref_or_classinfo, 2); - - if (opt_eager) { - classinfo *tc; - - tc = class_java_lang_Cloneable; - assert(tc->state & CLASS_LOADED); - list_add_first(&unlinkedclasses, tc); - c->interfaces[0].cls = tc; - - tc = class_java_io_Serializable; - assert(tc->state & CLASS_LOADED); - list_add_first(&unlinkedclasses, tc); - c->interfaces[1].cls = tc; - } - else { - c->interfaces[0].cls = class_java_lang_Cloneable; - c->interfaces[1].cls = class_java_io_Serializable; - } -#elif defined(ENABLE_JAVAME_CLDC1_1) - c->interfacescount = 0; - c->interfaces = NULL; -#else -#error unknow java configuration -#endif - - c->methodscount = 1; - c->methods = MNEW(methodinfo, c->methodscount); - MZERO(c->methods, methodinfo, c->methodscount); - - classrefs = MNEW(constant_classref, 2); - CLASSREF_INIT(classrefs[0], c, c->name); - CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object); - - /* create descriptor for clone method */ - /* we need one paramslot which is reserved for the 'this' parameter */ - clonedesc = NEW(methoddesc); - clonedesc->returntype.type = TYPE_ADR; - clonedesc->returntype.classref = classrefs + 1; - clonedesc->returntype.arraydim = 0; - /* initialize params to "empty", add real params below in - descriptor_params_from_paramtypes */ - clonedesc->paramcount = 0; - clonedesc->paramslots = 0; - clonedesc->paramtypes[0].classref = classrefs + 0; - clonedesc->params = NULL; - - /* create methodinfo */ - - clone = c->methods; - MSET(clone, 0, methodinfo, 1); - -#if defined(ENABLE_THREADS) - lock_init_object_lock(&clone->header); -#endif - - /* ATTENTION: if you delete the ACC_NATIVE below, set - clone->maxlocals=1 (interpreter related) */ - - clone->flags = ACC_PUBLIC | ACC_NATIVE; - clone->name = utf_clone; - clone->descriptor = utf_void__java_lang_Object; - clone->parseddesc = clonedesc; - clone->class = c; - - /* parse the descriptor to get the register allocation */ - - if (!descriptor_params_from_paramtypes(clonedesc, clone->flags)) - return false; - - clone->code = codegen_createnativestub(BUILTIN_clone, clone); - - /* XXX: field: length? */ - - /* array classes are not loaded from class files */ - - c->state |= CLASS_LOADED; - c->parseddescs = (u1 *) clonedesc; - c->parseddescsize = sizeof(methodinfo); - c->classrefs = classrefs; - c->classrefcount = 1; - - /* insert class into the loaded class cache */ - /* XXX free classinfo if NULL returned? */ - - return classcache_store(loader, c, true); -} - - -/* loader_close **************************************************************** - - Frees all resources. - -*******************************************************************************/ - -void loader_close(void) -{ - /* empty */ -} - - -/* - * 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: - */ diff --git a/src/vm/loader.h b/src/vm/loader.h deleted file mode 100644 index ee2db94ca..000000000 --- a/src/vm/loader.h +++ /dev/null @@ -1,157 +0,0 @@ -/* src/vm/loader.h - class loader header - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Christian Thalinger - - $Id: loader.h 6216 2006-12-18 18:21:37Z twisti $ -*/ - - -#ifndef _LOADER_H -#define _LOADER_H - -#include "config.h" - -#include - -#include "vm/types.h" - - -/* forward typedefs ***********************************************************/ - -typedef struct classbuffer classbuffer; - - -#include "vm/class.h" -#include "vm/descriptor.h" -#include "vm/global.h" -#include "vm/references.h" -#include "vm/method.h" -#include "vm/utf8.h" - - -/* constant pool entries ******************************************************* - - All constant pool entries need a data structure which contain the entrys - value. In some cases this structure exist already, in the remaining cases - this structure must be generated: - - kind structure generated? - ---------------------------------------------------------------------- - CONSTANT_Class constant_classref yes - CONSTANT_Fieldref constant_FMIref yes - CONSTANT_Methodref constant_FMIref yes - CONSTANT_InterfaceMethodref constant_FMIref yes - CONSTANT_String unicode no - CONSTANT_Integer constant_integer yes - CONSTANT_Float constant_float yes - CONSTANT_Long constant_long yes - CONSTANT_Double constant_double yes - CONSTANT_NameAndType constant_nameandtype yes - CONSTANT_Utf8 unicode no - CONSTANT_UNUSED - - -*******************************************************************************/ - -typedef struct { /* Integer */ - s4 value; -} constant_integer; - - -typedef struct { /* Float */ - float value; -} constant_float; - - -typedef struct { /* Long */ - s8 value; -} constant_long; - - -typedef struct { /* Double */ - double value; -} constant_double; - - -typedef struct { /* NameAndType (Field or Method) */ - utf *name; /* field/method name */ - utf *descriptor; /* field/method type descriptor string */ -} constant_nameandtype; - - -/* classbuffer ****************************************************************/ - -struct classbuffer { - classinfo *class; /* pointer to classinfo structure */ - u1 *data; /* pointer to byte code */ - s4 size; /* size of the byte code */ - u1 *pos; /* current read position */ - char *path; /* path to file (for debugging) */ -}; - - -/* function prototypes ********************************************************/ - -/* initialize loader, load important systemclasses */ -bool loader_init(void); - -void loader_load_all_classes(void); - -bool loader_skip_attribute_body(classbuffer *cb); - -#if defined(ENABLE_JAVASE) -bool loader_load_attribute_signature(classbuffer *cb, utf **signature); -#endif - -/* free resources */ -void loader_close(void); - -/* class loading functions */ -classinfo *load_class_from_sysloader(utf *name); -classinfo *load_class_from_classloader(utf *name, java_objectheader *cl); -classinfo *load_class_bootstrap(utf *name); - -/* (don't use the following directly) */ -classinfo *load_class_from_classbuffer(classbuffer *cb); -classinfo *load_newly_created_array(classinfo *c,java_objectheader *loader); - -#endif /* _LOADER_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: - */ diff --git a/src/vm/method.c b/src/vm/method.c deleted file mode 100644 index 58e0da3b8..000000000 --- a/src/vm/method.c +++ /dev/null @@ -1,424 +0,0 @@ -/* src/vm/method.c - method functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Andreas Krall - Roman Obermaiser - Mark Probst - Edwin Steiner - Christian Thalinger - - $Id: method.c 7228 2007-01-19 01:13:48Z edwin $ - -*/ - - -#include "config.h" - -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" -#include "vm/class.h" -#include "vm/global.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/method.h" -#include "vm/options.h" -#include "vm/jit/methodheader.h" - - -#if !defined(NDEBUG) && defined(ENABLE_INLINING) -#define INLINELOG(code) do { if (opt_inline_debug_log) { code } } while (0) -#else -#define INLINELOG(code) -#endif - - -/* method_free ***************************************************************** - - Frees all memory that was allocated for this method. - -*******************************************************************************/ - -void method_free(methodinfo *m) -{ - 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) { - removenativestub(m->stubroutine); - - } else { - removecompilerstub(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_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 */ - codeinfo *code; - - /* 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->class->flags & ACC_INTERFACE) { - pmptr = vftbl->interfacetable[-(m->class->index)]; - mptr = pmptr[(m - m->class->methods)]; - } - else { - mptr = vftbl->table[m->vftblindex]; - } - - /* and now get the codeinfo pointer from the first data segment slot */ - - code = *((codeinfo **) (mptr + CodeinfoPointer)); - - resm = code->m; - - return resm; -} - - -/* 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_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); - } -} - - -/* 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_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.()V - -*******************************************************************************/ - -#if !defined(NDEBUG) -void method_print(methodinfo *m) -{ - if (m == NULL) { - printf("NULL"); - return; - } - - utf_display_printable_ascii_classname(m->class->name); - 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.()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_print(mr->p.method); - } - else { - printf(" "); - 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: - */ diff --git a/src/vm/method.h b/src/vm/method.h deleted file mode 100644 index 4dd819bb7..000000000 --- a/src/vm/method.h +++ /dev/null @@ -1,185 +0,0 @@ -/* src/vm/method.h - method functions header - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Christian Thalinger - Edwin Steiner - - $Id: method.h 6273 2007-01-03 22:20:25Z edwin $ -*/ - - -#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; - -#include "config.h" -#include "vm/types.h" - -#include "vm/descriptor.h" -#include "vm/global.h" -#include "vm/linker.h" -#include "vm/references.h" - -#if defined(ENABLE_JAVASE) -# include "vm/stackmap.h" -#endif - -#include "vm/utf8.h" -#include "vm/jit/code.h" -#include "vm/jit/jit.h" - - -/* methodinfo *****************************************************************/ - -struct methodinfo { /* method structure */ - java_objectheader header; /* we need this in jit's monitorenter */ - 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 *class; /* 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 */ -}; - - -/* 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; -}; - - -/* function prototypes ********************************************************/ - -void method_free(methodinfo *m); -bool method_canoverwrite(methodinfo *m, methodinfo *old); - -methodinfo *method_vftbl_lookup(vftbl_t *vftbl, 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); - -#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 - -#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: - */ diff --git a/src/vm/options.c b/src/vm/options.c deleted file mode 100644 index 17d063c04..000000000 --- a/src/vm/options.c +++ /dev/null @@ -1,250 +0,0 @@ -/* src/vm/options.c - contains global options - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: options.c 7228 2007-01-19 01:13:48Z edwin $ - -*/ - - -#include "config.h" - -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" -#include "native/jni.h" -#include "vm/options.h" - - -/* command line option ********************************************************/ - -s4 opt_index = 0; /* index of processed arguments */ -char *opt_arg; /* this one exports the option argument */ - -bool opt_foo = false; /* option for development */ - -bool opt_jar = false; - -#if defined(ENABLE_JIT) -bool opt_jit = true; /* JIT mode execution (default) */ -bool opt_intrp = false; /* interpreter mode execution */ -#else -bool opt_jit = false; /* JIT mode execution */ -bool opt_intrp = true; /* interpreter mode execution (default) */ -#endif - -bool opt_run = true; - -s4 opt_heapmaxsize = 0; /* maximum heap size */ -s4 opt_heapstartsize = 0; /* initial heap size */ -s4 opt_stacksize = 0; /* thread stack size */ - -bool opt_verbose = false; -bool opt_debugcolor = false; /* use ANSI terminal sequences */ -bool compileall = false; - -bool loadverbose = false; -bool linkverbose = false; -bool initverbose = false; - -bool opt_verboseclass = false; -bool opt_verbosegc = false; -bool opt_verbosejni = false; -bool opt_verbosecall = false; /* trace all method invocation */ -bool opt_verboseexception = false; - -bool showmethods = false; -bool showconstantpool = false; -bool showutf = false; - -char *opt_method = NULL; -char *opt_signature = NULL; - -bool compileverbose = false; /* trace compiler actions */ -bool showstack = false; - -bool opt_showdisassemble = false; /* generate disassembler listing */ -bool opt_shownops = false; -bool opt_showddatasegment = false; /* generate data segment listing */ -bool opt_showintermediate = false; /* generate intermediate code listing */ -bool opt_showexceptionstubs = false; -bool opt_shownativestub = false; - -bool checkbounds = true; /* check array bounds */ -bool checknull = true; /* check null pointers */ -bool opt_noieee = false; /* don't implement ieee compliant floats */ -bool checksync = true; /* do synchronization */ -#if defined(ENABLE_LOOP) -bool opt_loops = false; /* optimize array accesses in loops */ -#endif - -bool makeinitializations = true; - -#if defined(ENABLE_STATISTICS) -bool opt_stat = false; -bool opt_getloadingtime = false; /* to measure the runtime */ -bool opt_getcompilingtime = false; /* compute compile time */ -#endif -#if defined(ENABLE_VERIFIER) -bool opt_verify = true; /* true if classfiles should be verified */ -#endif -bool opt_eager = false; - -#if defined(ENABLE_PROFILING) -bool opt_prof = false; -bool opt_prof_bb = false; -#endif - - -/* inlining options ***********************************************************/ - -#if defined(ENABLE_INLINING) -bool opt_inlining = false; -#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) -s4 opt_replace_verbose = 0; -s4 opt_inline_debug_min_size = 0; -s4 opt_inline_debug_max_size = INT_MAX; -s4 opt_inline_debug_end_counter = INT_MAX; -bool opt_inline_debug_all = false; -#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */ -#if !defined(NDEBUG) -bool opt_inline_debug_log = false; -#endif /* !defined(NDEBUG) */ -#endif /* defined(ENABLE_INLINING) */ - - -/* optimization options *******************************************************/ - -#if defined(ENABLE_IFCONV) -bool opt_ifconv = false; -#endif - -#if defined(ENABLE_LSRA) || defined(ENABLE_SSA) -bool opt_lsra = false; -#endif - - -/* interpreter options ********************************************************/ - -#if defined(ENABLE_INTRP) -bool opt_no_dynamic = false; /* suppress dynamic superinstructions */ -bool opt_no_replication = false; /* don't use replication in intrp */ -bool opt_no_quicksuper = false; /* instructions for quickening cannot be - part of dynamic superinstructions */ - -s4 opt_static_supers = 0x7fffffff; -bool vm_debug = false; /* XXX this should be called `opt_trace' */ -#endif - - -/* options_get ***************************************************************** - - DOCUMENT ME!!! - -*******************************************************************************/ - -s4 options_get(opt_struct *opts, JavaVMInitArgs *vm_args) -{ - char *option; - s4 i; - - if (opt_index >= vm_args->nOptions) - return OPT_DONE; - - /* get the current option */ - - option = vm_args->options[opt_index].optionString; - - if ((option == NULL) || (option[0] != '-')) - return OPT_DONE; - - for (i = 0; opts[i].name; i++) { - if (!opts[i].arg) { - /* boolean option found */ - - if (strcmp(option + 1, opts[i].name) == 0) { - opt_index++; - return opts[i].value; - } - - } else { - /* parameter option found */ - - /* with a space between */ - - if (strcmp(option + 1, opts[i].name) == 0) { - opt_index++; - - if (opt_index < vm_args->nOptions) { - opt_arg = strdup(vm_args->options[opt_index].optionString); - opt_index++; - return opts[i].value; - } - - return OPT_ERROR; - - } else { - /* parameter and option have no space between */ - - /* FIXME: this assumption is plain wrong, hits you if there is a - * parameter with no argument starting with same letter as param with argument - * but named after that one, ouch! */ - - size_t l = strlen(opts[i].name); - - if (strlen(option + 1) > l) { - if (memcmp(option + 1, opts[i].name, l) == 0) { - opt_index++; - opt_arg = strdup(option + 1 + l); - return opts[i].value; - } - } - } - } - } - - return OPT_ERROR; -} - - -/* - * 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: - */ diff --git a/src/vm/options.h b/src/vm/options.h deleted file mode 100644 index 983083c89..000000000 --- a/src/vm/options.h +++ /dev/null @@ -1,196 +0,0 @@ -/* src/vm/options.h - define global options extern - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: options.h 7228 2007-01-19 01:13:48Z edwin $ - -*/ - - -#ifndef _OPTIONS_H -#define _OPTIONS_H - - -#include "config.h" -#include "vm/types.h" - -#include "native/jni.h" -#include "vm/global.h" - - -/* reserved option numbers ****************************************************/ - -/* define these negative since the other options are an enum */ - -#define OPT_DONE -1 -#define OPT_ERROR -2 -#define OPT_IGNORE -3 - - -typedef struct opt_struct opt_struct; - -struct opt_struct { - char *name; - bool arg; - int value; -}; - - -/* global variables ***********************************************************/ - -extern s4 opt_index; -extern char *opt_arg; - -extern bool opt_foo; - -extern bool opt_jit; -extern bool opt_intrp; - -extern bool opt_jar; -extern bool opt_run; - -extern s4 opt_heapmaxsize; -extern s4 opt_heapstartsize; -extern s4 opt_stacksize; - -extern bool opt_verbose; -extern bool opt_debugcolor; -extern bool compileall; - -extern bool loadverbose; /* Print debug messages during loading */ -extern bool linkverbose; -extern bool initverbose; /* Log class initialization */ - -extern bool opt_verboseclass; -extern bool opt_verbosegc; -extern bool opt_verbosejni; -extern bool opt_verbosecall; -extern bool opt_verboseexception; - -extern bool showmethods; -extern bool showconstantpool; -extern bool showutf; - -extern char *opt_method; -extern char *opt_signature; - -extern bool compileverbose; -extern bool showstack; - -extern bool opt_showdisassemble; -extern bool opt_shownops; -extern bool opt_showddatasegment; -extern bool opt_showintermediate; -extern bool opt_showexceptionstubs; -extern bool opt_shownativestub; - -extern bool checkbounds; -extern bool checknull; -extern bool opt_noieee; -extern bool checksync; -#if defined(ENABLE_LOOP) -extern bool opt_loops; -#endif - -extern bool makeinitializations; - -#if defined(ENABLE_STATISTICS) -extern bool opt_stat; -extern bool opt_getloadingtime; -extern bool opt_getcompilingtime; -#endif -#if defined(ENABLE_VERIFIER) -extern bool opt_verify; -#endif -extern bool opt_eager; - -#if defined(ENABLE_PROFILING) -extern bool opt_prof; -extern bool opt_prof_bb; -#endif - -/* inlining options ***********************************************************/ - -#if defined(ENABLE_INLINING) -extern bool opt_inlining; -#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) -extern s4 opt_replace_verbose; -extern s4 opt_inline_debug_min_size; -extern s4 opt_inline_debug_max_size; -extern s4 opt_inline_debug_end_counter; -extern bool opt_inline_debug_all; -#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */ -#if !defined(NDEBUG) -extern bool opt_inline_debug_log; -#endif /* !defined(NDEBUG) */ -#endif /* defined(ENABLE_INLINING) */ - - -/* optimization options *******************************************************/ - -#if defined(ENABLE_IFCONV) -extern bool opt_ifconv; -#endif - -#if defined(ENABLE_LSRA) || defined(ENABLE_SSA) -extern bool opt_lsra; -#endif - - -/* interpreter options ********************************************************/ - -#if defined(ENABLE_INTRP) -extern bool opt_no_dynamic; -extern bool opt_no_replication; -extern bool opt_no_quicksuper; - -extern s4 opt_static_supers; -extern bool vm_debug; -#endif - - -/* function prototypes ********************************************************/ - -s4 options_get(opt_struct *opts, JavaVMInitArgs *vm_args); - -#endif /* _OPTIONS_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: - */ diff --git a/src/vm/properties.c b/src/vm/properties.c index ba2935e52..6e85df5b3 100644 --- a/src/vm/properties.c +++ b/src/vm/properties.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: properties.c 7234 2007-01-22 17:03:04Z twisti $ + $Id: properties.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -41,19 +41,18 @@ #include "vm/global.h" #include "native/include/java_lang_String.h" -#if defined(ENABLE_JAVASE) -# include "native/include/java_util_Properties.h" -#endif - #include "toolbox/list.h" #include "toolbox/util.h" -#include "vm/method.h" -#include "vm/options.h" + #include "vm/properties.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" +#include "vmcore/method.h" +#include "vmcore/options.h" + /* internal property structure ************************************************/ @@ -376,9 +375,9 @@ char *properties_get(char *key) void properties_system_add(java_objectheader *p, char *key, char *value) { - methodinfo *m; - java_lang_String *k; - java_lang_String *v; + methodinfo *m; + java_objectheader *k; + java_objectheader *v; /* search for method to add properties */ @@ -405,19 +404,22 @@ void properties_system_add(java_objectheader *p, char *key, char *value) Adds all properties from the properties list to the Java system properties. + ARGUMENTS: + p.... is actually a java_util_Properties structure + *******************************************************************************/ #if defined(ENABLE_JAVASE) -void properties_system_add_all(java_util_Properties *p) +void properties_system_add_all(java_objectheader *p) { list_properties_entry *pe; methodinfo *m; - java_lang_String *key; - java_lang_String *value; + java_objectheader *key; + java_objectheader *value; /* search for method to add properties */ - m = class_resolveclassmethod(p->header.vftbl->class, + m = class_resolveclassmethod(p->vftbl->class, utf_put, utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), NULL, diff --git a/src/vm/properties.h b/src/vm/properties.h index 42769336e..0c2defa19 100644 --- a/src/vm/properties.h +++ b/src/vm/properties.h @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: properties.h 7234 2007-01-22 17:03:04Z twisti $ + $Id: properties.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -37,11 +33,6 @@ #include "config.h" #include "vm/types.h" -#if defined(ENABLE_JAVASE) -# include "native/jni.h" -# include "native/include/java_util_Properties.h" -#endif - #include "vm/global.h" @@ -56,7 +47,7 @@ char *properties_get(char *key); void properties_system_add(java_objectheader *p, char *key, char *value); #if defined(ENABLE_JAVASE) -void properties_system_add_all(java_util_Properties *p); +void properties_system_add_all(java_objectheader *p); #endif #endif /* _PROPERTIES_H */ diff --git a/src/vm/references.h b/src/vm/references.h deleted file mode 100644 index 25569b894..000000000 --- a/src/vm/references.h +++ /dev/null @@ -1,176 +0,0 @@ -/* src/vm/references.h - references to classes/fields/methods - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - Christian Thalinger - - $Id: references.h 6012 2006-11-16 19:45:15Z twisti $ - -*/ - -#ifndef _REFERENCES_H_ -#define _REFERENCES_H_ - -/* forward typedefs ***********************************************************/ - -typedef struct constant_classref constant_classref; -typedef struct constant_FMIref constant_FMIref; - - -/* constant_classref **********************************************************/ - -struct constant_classref { - void *pseudo_vftbl; /* for distinguishing it from classinfo */ - struct classinfo *referer; /* class containing the reference */ - struct utf *name; /* name of the class refered to */ -}; - - -/* classref_or_classinfo ******************************************************/ - -typedef union classref_or_classinfo { - constant_classref *ref; /* a symbolic class reference */ - struct classinfo *cls; /* an already loaded class */ - void *any; /* used for general access (x != NULL,...) */ -} classref_or_classinfo; - - -/* parseddesc *****************************************************************/ - -typedef union parseddesc { - struct typedesc *fd; /* parsed field descriptor */ - struct methoddesc *md; /* parsed method descriptor */ - void *any; /* used for simple test against NULL */ -} parseddesc; - - -#include "config.h" -#include "vm/types.h" - -#include "vm/class.h" -#include "vm/descriptor.h" -#include "vm/field.h" -#include "vm/global.h" -#include "vm/method.h" -#include "vm/utf8.h" - - -/*----------------------------------------------------------------------------*/ -/* References */ -/* */ -/* This header files defines the following types used for references to */ -/* classes/methods/fields and descriptors: */ -/* */ -/* classinfo * a loaded class */ -/* constant_classref a symbolic reference */ -/* classref_or_classinfo a loaded class or a symbolic reference */ -/* */ -/* constant_FMIref a symb. ref. to a field/method/intf.method */ -/* */ -/* typedesc * describes a field type */ -/* methoddesc * descrives a method type */ -/* parseddesc describes a field type or a method type */ -/*----------------------------------------------------------------------------*/ - -/* structs ********************************************************************/ - -/* constant_FMIref ************************************************************/ - -struct constant_FMIref{ /* Fieldref, Methodref and InterfaceMethodref */ - union { - s4 index; /* used only within the loader */ - constant_classref *classref; /* class having this field/meth./intfm. */ - fieldinfo *field; /* resolved field */ - methodinfo *method; /* resolved method */ - } p; - utf *name; /* field/method/interfacemethod name */ - utf *descriptor; /* field/method/intfmeth. type descriptor string */ - parseddesc parseddesc; /* parsed descriptor */ -}; - - -/* macros *********************************************************************/ - -/* a value that never occurrs in classinfo.header.vftbl */ -#define CLASSREF_PSEUDO_VFTBL ((void *) 1) - -/* macro for testing if a classref_or_classinfo is a classref */ -/* `reforinfo` is only evaluated once */ -#define IS_CLASSREF(reforinfo) \ - ((reforinfo).ref->pseudo_vftbl == CLASSREF_PSEUDO_VFTBL) - -/* macro for testing if a constant_FMIref has been resolved */ -/* `fmiref` is only evaluated once */ -#define IS_FMIREF_RESOLVED(fmiref) \ - ((fmiref)->p.classref->pseudo_vftbl != CLASSREF_PSEUDO_VFTBL) - -/* the same as IS_CLASSREF, but also check against NULL */ -#define IS_XCLASSREF(reforinfo) \ - ((reforinfo).any && IS_CLASSREF(reforinfo)) - -/* macro for casting a classref/classinfo * to a classref_or_classinfo */ -#define CLASSREF_OR_CLASSINFO(value) \ - (*((classref_or_classinfo *)(&(value)))) - -/* macro for accessing the name of a classref/classinfo */ -#define CLASSREF_OR_CLASSINFO_NAME(value) \ - (IS_CLASSREF(value) ? (value).ref->name : (value).cls->name) - -/* macro for accessing the class name of a method reference */ -#define METHODREF_CLASSNAME(fmiref) \ - (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.method->class->name \ - : (fmiref)->p.classref->name) - -/* macro for accessing the class name of a method reference */ -#define FIELDREF_CLASSNAME(fmiref) \ - (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.field->class->name \ - : (fmiref)->p.classref->name) - -/* initialize a constant_classref with referer `ref` and name `classname` */ - -#define CLASSREF_INIT(c,ref,classname) \ - do { \ - (c).pseudo_vftbl = CLASSREF_PSEUDO_VFTBL; \ - (c).referer = (ref); \ - (c).name = (classname); \ - } while (0) - -#endif /* _REFERENCES_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: - */ - diff --git a/src/vm/resolve.c b/src/vm/resolve.c deleted file mode 100644 index 31544d877..000000000 --- a/src/vm/resolve.c +++ /dev/null @@ -1,2995 +0,0 @@ -/* src/vm/resolve.c - resolving classes/interfaces/fields/methods - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: Christan Thalinger - - $Id: resolve.c 6244 2006-12-27 15:15:31Z twisti $ - -*/ - - -#include "config.h" - -#include - -#include "mm/memory.h" -#include "vm/resolve.h" -#include "vm/access.h" -#include "vm/classcache.h" -#include "vm/descriptor.h" -#include "vm/exceptions.h" -#include "vm/global.h" -#include "vm/linker.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/stringlocal.h" -#include "vm/jit/jit.h" -#include "vm/jit/verify/typeinfo.h" - - -/******************************************************************************/ -/* DEBUG HELPERS */ -/******************************************************************************/ - -/*#define RESOLVE_VERBOSE*/ - -/******************************************************************************/ -/* CLASS RESOLUTION */ -/******************************************************************************/ - -/* resolve_class_from_name ***************************************************** - - Resolve a symbolic class reference - - IN: - referer..........the class containing the reference - refmethod........the method from which resolution was triggered - (may be NULL if not applicable) - classname........class name to resolve - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - checkaccess......if true, access rights to the class are checked - link.............if true, guarantee that the returned class, if any, - has been linked - - OUT: - *result..........set to result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - - NOTE: - The returned class is *not* guaranteed to be linked! - (It is guaranteed to be loaded, though.) - -*******************************************************************************/ - -bool resolve_class_from_name(classinfo *referer, - methodinfo *refmethod, - utf *classname, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result) -{ - classinfo *cls = NULL; - char *utf_ptr; - int len; - - assert(result); - assert(referer); - assert(classname); - assert(mode == resolveLazy || mode == resolveEager); - - *result = NULL; - -#ifdef RESOLVE_VERBOSE - printf("resolve_class_from_name("); - utf_fprint_printable_ascii(stdout,referer->name); - printf(",%p,",(void*)referer->classloader); - utf_fprint_printable_ascii(stdout,classname); - printf(",%d,%d)\n",(int)checkaccess,(int)link); -#endif - - /* lookup if this class has already been loaded */ - - cls = classcache_lookup(referer->classloader, classname); - -#ifdef RESOLVE_VERBOSE - printf(" lookup result: %p\n",(void*)cls); -#endif - - if (!cls) { - /* resolve array types */ - - if (classname->text[0] == '[') { - utf_ptr = classname->text + 1; - len = classname->blength - 1; - - /* classname is an array type name */ - - switch (*utf_ptr) { - case 'L': - utf_ptr++; - len -= 2; - /* FALLTHROUGH */ - case '[': - /* the component type is a reference type */ - /* resolve the component type */ - if (!resolve_class_from_name(referer,refmethod, - utf_new(utf_ptr,len), - mode,checkaccess,link,&cls)) - return false; /* exception */ - if (!cls) { - assert(mode == resolveLazy); - return true; /* be lazy */ - } - /* create the array class */ - cls = class_array_of(cls,false); - if (!cls) - return false; /* exception */ - } - } - else { - /* the class has not been loaded, yet */ - if (mode == resolveLazy) - return true; /* be lazy */ - } - -#ifdef RESOLVE_VERBOSE - printf(" loading...\n"); -#endif - - /* load the class */ - if (!cls) { - if (!(cls = load_class_from_classloader(classname, - referer->classloader))) - return false; /* exception */ - } - } - - /* the class is now loaded */ - assert(cls); - assert(cls->state & CLASS_LOADED); - -#ifdef RESOLVE_VERBOSE - printf(" checking access rights...\n"); -#endif - - /* check access rights of referer to refered class */ - if (checkaccess && !access_is_accessible_class(referer,cls)) { - int msglen; - char *message; - - msglen = utf_bytes(cls->name) + utf_bytes(referer->name) + 100; - message = MNEW(char, msglen); - strcpy(message, "class is not accessible ("); - utf_cat_classname(message, cls->name); - strcat(message, " from "); - utf_cat_classname(message, referer->name); - strcat(message, ")"); - *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message); - MFREE(message,char,msglen); - return false; /* exception */ - } - - /* link the class if necessary */ - if (link) { - if (!(cls->state & CLASS_LINKED)) - if (!link_class(cls)) - return false; /* exception */ - - assert(cls->state & CLASS_LINKED); - } - - /* resolution succeeds */ -#ifdef RESOLVE_VERBOSE - printf(" success.\n"); -#endif - *result = cls; - return true; -} - -/* resolve_classref ************************************************************ - - Resolve a symbolic class reference - - IN: - refmethod........the method from which resolution was triggered - (may be NULL if not applicable) - ref..............class reference - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - checkaccess......if true, access rights to the class are checked - link.............if true, guarantee that the returned class, if any, - has been linked - - OUT: - *result..........set to result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - -*******************************************************************************/ - -bool resolve_classref(methodinfo *refmethod, - constant_classref *ref, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result) -{ - return resolve_classref_or_classinfo(refmethod,CLASSREF_OR_CLASSINFO(ref),mode,checkaccess,link,result); -} - -/* resolve_classref_or_classinfo *********************************************** - - Resolve a symbolic class reference if necessary - - IN: - refmethod........the method from which resolution was triggered - (may be NULL if not applicable) - cls..............class reference or classinfo - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - checkaccess......if true, access rights to the class are checked - link.............if true, guarantee that the returned class, if any, - has been linked - - OUT: - *result..........set to result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - -*******************************************************************************/ - -bool resolve_classref_or_classinfo(methodinfo *refmethod, - classref_or_classinfo cls, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result) -{ - classinfo *c; - - assert(cls.any); - assert(mode == resolveEager || mode == resolveLazy); - assert(result); - -#ifdef RESOLVE_VERBOSE - printf("resolve_classref_or_classinfo("); - utf_fprint_printable_ascii(stdout,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name); - printf(",%i,%i,%i)\n",mode,(int)checkaccess,(int)link); -#endif - - *result = NULL; - - if (IS_CLASSREF(cls)) { - /* we must resolve this reference */ - - if (!resolve_class_from_name(cls.ref->referer, refmethod, cls.ref->name, - mode, checkaccess, link, &c)) - goto return_exception; - - } else { - /* cls has already been resolved */ - c = cls.cls; - assert(c->state & CLASS_LOADED); - } - assert(c || (mode == resolveLazy)); - - if (!c) - return true; /* be lazy */ - - assert(c); - assert(c->state & CLASS_LOADED); - - if (link) { - if (!(c->state & CLASS_LINKED)) - if (!link_class(c)) - goto return_exception; - - assert(c->state & CLASS_LINKED); - } - - /* succeeded */ - *result = c; - return true; - - return_exception: - *result = NULL; - return false; -} - - -/* resolve_class_from_typedesc ************************************************* - - Return a classinfo * for the given type descriptor - - IN: - d................type descriptor - checkaccess......if true, access rights to the class are checked - link.............if true, guarantee that the returned class, if any, - has been linked - OUT: - *result..........set to result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - - NOTE: - This function always resolves eagerly. - -*******************************************************************************/ - -bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, classinfo **result) -{ - classinfo *cls; - - assert(d); - assert(result); - - *result = NULL; - -#ifdef RESOLVE_VERBOSE - printf("resolve_class_from_typedesc("); - descriptor_debug_print_typedesc(stdout,d); - printf(",%i,%i)\n",(int)checkaccess,(int)link); -#endif - - if (d->type == TYPE_ADR) { - /* a reference type */ - assert(d->classref); - if (!resolve_classref_or_classinfo(NULL,CLASSREF_OR_CLASSINFO(d->classref), - resolveEager,checkaccess,link,&cls)) - return false; /* exception */ - } - else { - /* a primitive type */ - cls = primitivetype_table[d->decltype].class_primitive; - assert(cls->state & CLASS_LOADED); - if (!(cls->state & CLASS_LINKED)) - if (!link_class(cls)) - return false; /* exception */ - } - assert(cls); - assert(cls->state & CLASS_LOADED); - assert(!link || (cls->state & CLASS_LINKED)); - -#ifdef RESOLVE_VERBOSE - printf(" result = ");utf_fprint_printable_ascii(stdout,cls->name);printf("\n"); -#endif - - *result = cls; - return true; -} - -/******************************************************************************/ -/* SUBTYPE SET CHECKS */ -/******************************************************************************/ - -/* resolve_subtype_check ******************************************************* - - Resolve the given types lazily and perform a subtype check - - IN: - refmethod........the method triggering the resolution - subtype..........checked to be a subtype of supertype - supertype........the super type to check agaings - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - error............which type of exception to throw if - the test fails. May be: - resolveLinkageError, or - resolveIllegalAccessError - IMPORTANT: If error==resolveIllegalAccessError, - then array types are not checked. - - RETURN VALUE: - resolveSucceeded.....the check succeeded - resolveDeferred......the check could not be performed due to - unresolved types. (This can only happen for - mode == resolveLazy.) - resolveFailed........the check failed, an exception has been thrown. - - NOTE: - The types are resolved first, so any - exception which may occurr during resolution may - be thrown by this function. - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -static resolve_result_t resolve_subtype_check(methodinfo *refmethod, - classref_or_classinfo subtype, - classref_or_classinfo supertype, - resolve_mode_t mode, - resolve_err_t error) -{ - classinfo *subclass; - typeinfo subti; - typecheck_result r; - - assert(refmethod); - assert(subtype.any); - assert(supertype.any); - assert(mode == resolveLazy || mode == resolveEager); - assert(error == resolveLinkageError || error == resolveIllegalAccessError); - - /* resolve the subtype */ - - if (!resolve_classref_or_classinfo(refmethod,subtype,mode,false,true,&subclass)) { - /* the subclass could not be resolved. therefore we are sure that */ - /* no instances of this subclass will ever exist -> skip this test */ - /* XXX this assumes that class loading has invariant results (as in JVM spec) */ - *exceptionptr = NULL; - return resolveSucceeded; - } - if (!subclass) - return resolveDeferred; /* be lazy */ - - assert(subclass->state & CLASS_LINKED); - - /* do not check access to protected members of arrays */ - - if (error == resolveIllegalAccessError && subclass->name->text[0] == '[') { - return resolveSucceeded; - } - - /* perform the subtype check */ - - typeinfo_init_classinfo(&subti,subclass); -check_again: - r = typeinfo_is_assignable_to_class(&subti,supertype); - if (r == typecheck_FAIL) - return resolveFailed; /* failed, exception is already set */ - - if (r == typecheck_MAYBE) { - assert(IS_CLASSREF(supertype)); - if (mode == resolveEager) { - if (!resolve_classref_or_classinfo(refmethod,supertype, - resolveEager,false,true, - &supertype.cls)) - { - return resolveFailed; - } - assert(supertype.cls); - goto check_again; - } - - return resolveDeferred; /* be lazy */ - } - - if (!r) { - /* sub class relationship is false */ - - char *message; - int msglen; - -#if defined(RESOLVE_VERBOSE) - printf("SUBTYPE CHECK FAILED!\n"); -#endif - - msglen = utf_bytes(subclass->name) + utf_bytes(CLASSREF_OR_CLASSINFO_NAME(supertype)) + 200; - message = MNEW(char, msglen); - strcpy(message, (error == resolveIllegalAccessError) ? - "illegal access to protected member (" - : "subtype constraint violated ("); - utf_cat_classname(message, subclass->name); - strcat(message, " is not a subclass of "); - utf_cat_classname(message, CLASSREF_OR_CLASSINFO_NAME(supertype)); - strcat(message, ")"); - if (error == resolveIllegalAccessError) - *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message); - else - *exceptionptr = exceptions_new_linkageerror(message, NULL); - MFREE(message, char, msglen); - return resolveFailed; /* exception */ - } - - /* everything ok */ - - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - -/* resolve_lazy_subtype_checks ************************************************* - - Resolve the types to check lazily and perform subtype checks - - IN: - refmethod........the method triggering the resolution - subtinfo.........the typeinfo containing the subtypes - supertype........the supertype to test againgst - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - error............which type of exception to throw if - the test fails. May be: - resolveLinkageError, or - resolveIllegalAccessError - IMPORTANT: If error==resolveIllegalAccessError, - then array types in the set are skipped. - - RETURN VALUE: - resolveSucceeded.....the check succeeded - resolveDeferred......the check could not be performed due to - unresolved types - resolveFailed........the check failed, an exception has been thrown. - - NOTE: - The references in the set are resolved first, so any - exception which may occurr during resolution may - be thrown by this function. - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -static resolve_result_t resolve_lazy_subtype_checks(methodinfo *refmethod, - typeinfo *subtinfo, - classref_or_classinfo supertype, - resolve_err_t error) -{ - int count; - int i; - resolve_result_t result; - - assert(refmethod); - assert(subtinfo); - assert(supertype.any); - assert(error == resolveLinkageError || error == resolveIllegalAccessError); - - /* returnAddresses are illegal here */ - - if (TYPEINFO_IS_PRIMITIVE(*subtinfo)) { - exceptions_throw_verifyerror(refmethod, - "Invalid use of returnAddress"); - return resolveFailed; - } - - /* uninitialized objects are illegal here */ - - if (TYPEINFO_IS_NEWOBJECT(*subtinfo)) { - exceptions_throw_verifyerror(refmethod, - "Invalid use of uninitialized object"); - return resolveFailed; - } - - /* the nulltype is always assignable */ - - if (TYPEINFO_IS_NULLTYPE(*subtinfo)) - return resolveSucceeded; - - /* every type is assignable to (BOOTSTRAP)java.lang.Object */ - - if (supertype.cls == class_java_lang_Object - || (CLASSREF_OR_CLASSINFO_NAME(supertype) == utf_java_lang_Object - && refmethod->class->classloader == NULL)) - { - return resolveSucceeded; - } - - if (subtinfo->merged) { - - /* for a merged type we have to do a series of checks */ - - count = subtinfo->merged->count; - for (i=0; imerged->list[i]; - if (subtinfo->dimension > 0) { - /* a merge of array types */ - /* the merged list contains the possible _element_ types, */ - /* so we have to create array types with these elements. */ - if (IS_CLASSREF(c)) { - c.ref = class_get_classref_multiarray_of(subtinfo->dimension,c.ref); - } - else { - c.cls = class_multiarray_of(subtinfo->dimension,c.cls,false); - } - } - - /* do the subtype check against the type c */ - - result = resolve_subtype_check(refmethod,c,supertype,resolveLazy,error); - if (result != resolveSucceeded) - return result; - } - } - else { - - /* a single type, this is the common case, hopefully */ - - if (CLASSREF_OR_CLASSINFO_NAME(subtinfo->typeclass) - == CLASSREF_OR_CLASSINFO_NAME(supertype)) - { - /* the class names are the same */ - /* equality is guaranteed by the loading constraints */ - return resolveSucceeded; - } - else { - - /* some other type name, try to perform the check lazily */ - - return resolve_subtype_check(refmethod, - subtinfo->typeclass,supertype, - resolveLazy, - error); - } - } - - /* everything ok */ - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - -/* resolve_and_check_subtype_set *********************************************** - - Resolve the references in the given set and test subtype relationships - - IN: - refmethod........the method triggering the resolution - ref..............a set of class/interface references - (may be empty) - typeref..........the type to test against the set - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - error............which type of exception to throw if - the test fails. May be: - resolveLinkageError, or - resolveIllegalAccessError - IMPORTANT: If error==resolveIllegalAccessError, - then array types in the set are skipped. - - RETURN VALUE: - resolveSucceeded.....the check succeeded - resolveDeferred......the check could not be performed due to - unresolved types. (This can only happen if - mode == resolveLazy.) - resolveFailed........the check failed, an exception has been thrown. - - NOTE: - The references in the set are resolved first, so any - exception which may occurr during resolution may - be thrown by this function. - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -static resolve_result_t resolve_and_check_subtype_set(methodinfo *refmethod, - unresolved_subtype_set *ref, - classref_or_classinfo typeref, - resolve_mode_t mode, - resolve_err_t error) -{ - classref_or_classinfo *setp; - typecheck_result checkresult; - - assert(refmethod); - assert(ref); - assert(typeref.any); - assert(mode == resolveLazy || mode == resolveEager); - assert(error == resolveLinkageError || error == resolveIllegalAccessError); - -#if defined(RESOLVE_VERBOSE) - printf("resolve_and_check_subtype_set:\n"); - unresolved_subtype_set_debug_dump(ref, stdout); - if (IS_CLASSREF(typeref)) - class_classref_println(typeref.ref); - else - class_println(typeref.cls); -#endif - - setp = ref->subtyperefs; - - /* an empty set of tests always succeeds */ - if (!setp || !setp->any) { - return resolveSucceeded; - } - - /* first resolve the type if necessary */ - if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&(typeref.cls))) - return resolveFailed; /* exception */ - if (!typeref.cls) - return resolveDeferred; /* be lazy */ - - assert(typeref.cls->state & CLASS_LINKED); - - /* iterate over the set members */ - - for (; setp->any; ++setp) { - checkresult = resolve_subtype_check(refmethod,*setp,typeref,mode,error); -#if defined(RESOLVE_VERBOSE) - if (checkresult != resolveSucceeded) - printf("SUBTYPE CHECK FAILED!\n"); -#endif - if (checkresult != resolveSucceeded) - return checkresult; - } - - /* check succeeds */ - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - -/******************************************************************************/ -/* CLASS RESOLUTION */ -/******************************************************************************/ - -/* resolve_class *************************************************************** - - Resolve an unresolved class reference. The class is also linked. - - IN: - ref..............struct containing the reference - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - checkaccess......if true, access rights to the class are checked - - OUT: - *result..........set to the result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - -*******************************************************************************/ - -#ifdef ENABLE_VERIFIER -bool resolve_class(unresolved_class *ref, - resolve_mode_t mode, - bool checkaccess, - classinfo **result) -{ - classinfo *cls; - resolve_result_t checkresult; - - assert(ref); - assert(result); - assert(mode == resolveLazy || mode == resolveEager); - - *result = NULL; - -#ifdef RESOLVE_VERBOSE - unresolved_class_debug_dump(ref,stdout); -#endif - - /* first we must resolve the class */ - if (!resolve_classref(ref->referermethod, - ref->classref,mode,checkaccess,true,&cls)) - { - /* the class reference could not be resolved */ - return false; /* exception */ - } - if (!cls) - return true; /* be lazy */ - - assert(cls); - assert((cls->state & CLASS_LOADED) && (cls->state & CLASS_LINKED)); - - /* now we check the subtype constraints */ - - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->subtypeconstraints), - CLASSREF_OR_CLASSINFO(cls), - mode, - resolveLinkageError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - - /* succeed */ - *result = cls; - return true; -} -#endif /* ENABLE_VERIFIER */ - -/* resolve_classref_eager ****************************************************** - - Resolve an unresolved class reference eagerly. The class is also linked and - access rights to the class are checked. - - IN: - ref..............constant_classref to the class - - RETURN VALUE: - classinfo * to the class, or - NULL if an exception has been thrown - -*******************************************************************************/ - -classinfo * resolve_classref_eager(constant_classref *ref) -{ - classinfo *c; - - if (!resolve_classref(NULL,ref,resolveEager,true,true,&c)) - return NULL; - - return c; -} - -/* resolve_classref_eager_nonabstract ****************************************** - - Resolve an unresolved class reference eagerly. The class is also linked and - access rights to the class are checked. A check is performed that the class - is not abstract. - - IN: - ref..............constant_classref to the class - - RETURN VALUE: - classinfo * to the class, or - NULL if an exception has been thrown - -*******************************************************************************/ - -classinfo * resolve_classref_eager_nonabstract(constant_classref *ref) -{ - classinfo *c; - - if (!resolve_classref(NULL,ref,resolveEager,true,true,&c)) - return NULL; - - /* ensure that the class is not abstract */ - - if (c->flags & ACC_ABSTRACT) { - exceptions_throw_verifyerror(NULL,"creating instance of abstract class"); - return NULL; - } - - return c; -} - -/* resolve_class_eager ********************************************************* - - Resolve an unresolved class reference eagerly. The class is also linked and - access rights to the class are checked. - - IN: - ref..............struct containing the reference - - RETURN VALUE: - classinfo * to the class, or - NULL if an exception has been thrown - -*******************************************************************************/ - -#ifdef ENABLE_VERIFIER -classinfo * resolve_class_eager(unresolved_class *ref) -{ - classinfo *c; - - if (!resolve_class(ref,resolveEager,true,&c)) - return NULL; - - return c; -} -#endif /* ENABLE_VERIFIER */ - -/******************************************************************************/ -/* FIELD RESOLUTION */ -/******************************************************************************/ - -/* resolve_field_verifier_checks ******************************************* - - Do the verifier checks necessary after field has been resolved. - - IN: - refmethod........the method containing the reference - fieldref.........the field reference - container........the class where the field was found - fi...............the fieldinfo of the resolved field - instanceti.......instance typeinfo, if available - valueti..........value typeinfo, if available - isstatic.........true if this is a *STATIC* instruction - isput............true if this is a PUT* instruction - - RETURN VALUE: - resolveSucceeded....everything ok - resolveDeferred.....tests could not be done, have been deferred - resolveFailed.......exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_field_verifier_checks(methodinfo *refmethod, - constant_FMIref *fieldref, - classinfo *container, - fieldinfo *fi, - typeinfo *instanceti, - typeinfo *valueti, - bool isstatic, - bool isput) -{ - classinfo *declarer; - classinfo *referer; - resolve_result_t result; - constant_classref *fieldtyperef; - - assert(refmethod); - assert(fieldref); - assert(container); - assert(fi); - - /* get the classinfos and the field type */ - - referer = refmethod->class; - assert(referer); - - declarer = fi->class; - assert(declarer); - assert(referer->state & CLASS_LINKED); - - fieldtyperef = fieldref->parseddesc.fd->classref; - - /* check static */ - -#if true != 1 -#error This code assumes that `true` is `1`. Otherwise, use the ternary operator below. -#endif - - if (((fi->flags & ACC_STATIC) != 0) != isstatic) { - /* a static field is accessed via an instance, or vice versa */ - *exceptionptr = - new_exception_message(string_java_lang_IncompatibleClassChangeError, - (fi->flags & ACC_STATIC) ? "static field accessed via instance" - : "instance field accessed without instance"); - return resolveFailed; - } - - /* check access rights */ - - if (!access_is_accessible_member(referer,declarer,fi->flags)) { - int msglen; - char *message; - - msglen = utf_bytes(declarer->name) + utf_bytes(fi->name) + utf_bytes(referer->name) + 100; - message = MNEW(char, msglen); - strcpy(message, "field is not accessible ("); - utf_cat_classname(message, declarer->name); - strcat(message, "."); - utf_cat(message, fi->name); - strcat(message, " from "); - utf_cat_classname(message, referer->name); - strcat(message, ")"); - *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message); - MFREE(message,char,msglen); - return resolveFailed; /* exception */ - } - - /* for non-static methods we have to check the constraints on the */ - /* instance type */ - - if (instanceti) { - typeinfo *insttip; - typeinfo tinfo; - - /* The instanceslot must contain a reference to a non-array type */ - - if (!TYPEINFO_IS_REFERENCE(*instanceti)) { - exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on non-reference"); - return resolveFailed; - } - if (TYPEINFO_IS_ARRAY(*instanceti)) { - exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on array"); - return resolveFailed; - } - - if (isput && TYPEINFO_IS_NEWOBJECT(*instanceti)) - { - /* The instruction writes a field in an uninitialized object. */ - /* This is only allowed when a field of an uninitialized 'this' object is */ - /* written inside an initialization method */ - - classinfo *initclass; - instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); - - if (ins != NULL) { - exceptions_throw_verifyerror(refmethod, "accessing field of uninitialized object"); - return resolveFailed; - } - - /* XXX check that class of field == refmethod->class */ - initclass = referer; /* XXX classrefs */ - assert(initclass->state & CLASS_LINKED); - - typeinfo_init_classinfo(&tinfo, initclass); - insttip = &tinfo; - } - else { - insttip = instanceti; - } - - result = resolve_lazy_subtype_checks(refmethod, - insttip, - CLASSREF_OR_CLASSINFO(container), - resolveLinkageError); - if (result != resolveSucceeded) - return result; - - /* check protected access */ - - if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) - { - result = resolve_lazy_subtype_checks(refmethod, - instanceti, - CLASSREF_OR_CLASSINFO(referer), - resolveIllegalAccessError); - if (result != resolveSucceeded) - return result; - } - - } - - /* for PUT* instructions we have to check the constraints on the value type */ - - if (valueti) { - assert(fieldtyperef); - - /* check subtype constraints */ - result = resolve_lazy_subtype_checks(refmethod, - valueti, - CLASSREF_OR_CLASSINFO(fieldtyperef), - resolveLinkageError); - - if (result != resolveSucceeded) - return result; - } - - /* impose loading constraint on field type */ - - if (fi->type == TYPE_ADR) { - assert(fieldtyperef); - if (!classcache_add_constraint(declarer->classloader, - referer->classloader, - fieldtyperef->name)) - return resolveFailed; - } - - /* XXX impose loading constraint on instance? */ - - /* everything ok */ - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - -/* resolve_field_lazy ********************************************************** - - Resolve an unresolved field reference lazily - - NOTE: This function does NOT do any verification checks. In case of a - successful resolution, you must call resolve_field_verifier_checks - in order to perform the necessary checks! - - IN: - refmethod........the referer method - fieldref.........the field reference - - RETURN VALUE: - resolveSucceeded.....the reference has been resolved - resolveDeferred......the resolving could not be performed lazily - resolveFailed........resolving failed, an exception has been thrown. - -*******************************************************************************/ - -resolve_result_t resolve_field_lazy(methodinfo *refmethod, - constant_FMIref *fieldref) -{ - classinfo *referer; - classinfo *container; - fieldinfo *fi; - - assert(refmethod); - - /* the class containing the reference */ - - referer = refmethod->class; - assert(referer); - - /* check if the field itself is already resolved */ - - if (IS_FMIREF_RESOLVED(fieldref)) - return resolveSucceeded; - - /* first we must resolve the class containg the field */ - - /* XXX can/may lazyResolving trigger linking? */ - - if (!resolve_class_from_name(referer, refmethod, - fieldref->p.classref->name, resolveLazy, true, true, &container)) - { - /* the class reference could not be resolved */ - return resolveFailed; /* exception */ - } - if (!container) - return resolveDeferred; /* be lazy */ - - assert(container->state & CLASS_LINKED); - - /* now we must find the declaration of the field in `container` - * or one of its superclasses */ - - fi = class_resolvefield(container, - fieldref->name, fieldref->descriptor, - referer, true); - if (!fi) { - /* The field does not exist. But since we were called lazily, */ - /* this error must not be reported now. (It will be reported */ - /* if eager resolving of this field is ever tried.) */ - - *exceptionptr = NULL; - return resolveDeferred; /* be lazy */ - } - - /* cache the result of the resolution */ - - fieldref->p.field = fi; - - /* everything ok */ - return resolveSucceeded; -} - -/* resolve_field *************************************************************** - - Resolve an unresolved field reference - - IN: - ref..............struct containing the reference - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - - OUT: - *result..........set to the result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - -*******************************************************************************/ - -bool resolve_field(unresolved_field *ref, - resolve_mode_t mode, - fieldinfo **result) -{ - classinfo *referer; - classinfo *container; - classinfo *declarer; - constant_classref *fieldtyperef; - fieldinfo *fi; - resolve_result_t checkresult; - - assert(ref); - assert(result); - assert(mode == resolveLazy || mode == resolveEager); - - *result = NULL; - -#ifdef RESOLVE_VERBOSE - unresolved_field_debug_dump(ref,stdout); -#endif - - /* the class containing the reference */ - - referer = ref->referermethod->class; - assert(referer); - - /* check if the field itself is already resolved */ - if (IS_FMIREF_RESOLVED(ref->fieldref)) { - fi = ref->fieldref->p.field; - container = fi->class; - goto resolved_the_field; - } - - /* first we must resolve the class containg the field */ - if (!resolve_class_from_name(referer,ref->referermethod, - ref->fieldref->p.classref->name,mode,true,true,&container)) - { - /* the class reference could not be resolved */ - return false; /* exception */ - } - if (!container) - return true; /* be lazy */ - - assert(container); - assert(container->state & CLASS_LOADED); - assert(container->state & CLASS_LINKED); - - /* now we must find the declaration of the field in `container` - * or one of its superclasses */ - -#ifdef RESOLVE_VERBOSE - printf(" resolving field in class...\n"); -#endif - - fi = class_resolvefield(container, - ref->fieldref->name,ref->fieldref->descriptor, - referer,true); - if (!fi) { - if (mode == resolveLazy) { - /* The field does not exist. But since we were called lazily, */ - /* this error must not be reported now. (It will be reported */ - /* if eager resolving of this field is ever tried.) */ - - *exceptionptr = NULL; - return true; /* be lazy */ - } - - return false; /* exception */ - } - - /* cache the result of the resolution */ - ref->fieldref->p.field = fi; - -resolved_the_field: - -#ifdef ENABLE_VERIFIER - /* Checking opt_verify is ok here, because the NULL iptr guarantees */ - /* that no missing parts of an instruction will be accessed. */ - if (opt_verify) { - checkresult = resolve_field_verifier_checks( - ref->referermethod, - ref->fieldref, - container, - fi, - NULL, /* instanceti, handled by constraints below */ - NULL, /* valueti, handled by constraints below */ - (ref->flags & RESOLVE_STATIC) != 0, /* isstatic */ - (ref->flags & RESOLVE_PUTFIELD) != 0 /* isput */); - - if (checkresult != resolveSucceeded) - return (bool) checkresult; - - declarer = fi->class; - assert(declarer); - assert(declarer->state & CLASS_LOADED); - assert(declarer->state & CLASS_LINKED); - - /* for non-static accesses we have to check the constraints on the */ - /* instance type */ - - if (!(ref->flags & RESOLVE_STATIC)) { - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(container), - mode, resolveLinkageError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - } - - fieldtyperef = ref->fieldref->parseddesc.fd->classref; - - /* for PUT* instructions we have to check the constraints on the value type */ - if (((ref->flags & RESOLVE_PUTFIELD) != 0) && fi->type == TYPE_ADR) { - assert(fieldtyperef); - if (!SUBTYPESET_IS_EMPTY(ref->valueconstraints)) { - /* check subtype constraints */ - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->valueconstraints), - CLASSREF_OR_CLASSINFO(fieldtyperef), - mode, resolveLinkageError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - } - } - - /* check protected access */ - if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) { - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(referer), - mode, - resolveIllegalAccessError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - } - - } -#endif /* ENABLE_VERIFIER */ - - /* succeed */ - *result = fi; - - return true; -} - -/* resolve_field_eager ********************************************************* - - Resolve an unresolved field reference eagerly. - - IN: - ref..............struct containing the reference - - RETURN VALUE: - fieldinfo * to the field, or - NULL if an exception has been thrown - -*******************************************************************************/ - -fieldinfo * resolve_field_eager(unresolved_field *ref) -{ - fieldinfo *fi; - - if (!resolve_field(ref,resolveEager,&fi)) - return NULL; - - return fi; -} - -/******************************************************************************/ -/* METHOD RESOLUTION */ -/******************************************************************************/ - -/* resolve_method_invokespecial_lookup ***************************************** - - Do the special lookup for methods invoked by INVOKESPECIAL - - IN: - refmethod........the method containing the reference - mi...............the methodinfo of the resolved method - - RETURN VALUE: - a methodinfo *...the result of the lookup, - NULL.............an exception has been thrown - -*******************************************************************************/ - -methodinfo * resolve_method_invokespecial_lookup(methodinfo *refmethod, - methodinfo *mi) -{ - classinfo *declarer; - classinfo *referer; - - assert(refmethod); - assert(mi); - - /* get referer and declarer classes */ - - referer = refmethod->class; - assert(referer); - - declarer = mi->class; - assert(declarer); - assert(referer->state & CLASS_LINKED); - - /* checks for INVOKESPECIAL: */ - /* for and methods of the current class we don't need any */ - /* special checks. Otherwise we must verify that the called method */ - /* belongs to a super class of the current class */ - - if ((referer != declarer) && (mi->name != utf_init)) { - /* check that declarer is a super class of the current class */ - - if (!class_issubclass(referer,declarer)) { - exceptions_throw_verifyerror(refmethod, - "INVOKESPECIAL calling non-super class method"); - return NULL; - } - - /* if the referer has ACC_SUPER set, we must do the special */ - /* lookup starting with the direct super class of referer */ - - if ((referer->flags & ACC_SUPER) != 0) { - mi = class_resolvemethod(referer->super.cls, - mi->name, - mi->descriptor); - - if (mi == NULL) { -#if defined(ENABLE_JAVASE) - /* the spec calls for an AbstractMethodError in this case */ - exceptions_throw_abstractmethoderror(); -#else - exceptions_throw_virtualmachineerror(); -#endif - return NULL; - } - } - } - - /* everything ok */ - return mi; -} - -/* resolve_method_verifier_checks ****************************************** - - Do the verifier checks necessary after a method has been resolved. - - IN: - refmethod........the method containing the reference - methodref........the method reference - mi...............the methodinfo of the resolved method - invokestatic.....true if the method is invoked by INVOKESTATIC - - RETURN VALUE: - resolveSucceeded....everything ok - resolveDeferred.....tests could not be done, have been deferred - resolveFailed.......exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, - constant_FMIref *methodref, - methodinfo *mi, - bool invokestatic) -{ - classinfo *declarer; - classinfo *referer; - - assert(refmethod); - assert(methodref); - assert(mi); - -#ifdef RESOLVE_VERBOSE - printf("resolve_method_verifier_checks\n"); - printf(" flags: %02x\n",mi->flags); -#endif - - /* get the classinfos and the method descriptor */ - - referer = refmethod->class; - assert(referer); - - declarer = mi->class; - assert(declarer); - - /* check static */ - - if (((mi->flags & ACC_STATIC) != 0) != (invokestatic != false)) { - /* a static method is accessed via an instance, or vice versa */ - *exceptionptr = - new_exception_message(string_java_lang_IncompatibleClassChangeError, - (mi->flags & ACC_STATIC) ? "static method called via instance" - : "instance method called without instance"); - return resolveFailed; - } - - /* check access rights */ - - if (!access_is_accessible_member(referer,declarer,mi->flags)) { - int msglen; - char *message; - - /* XXX clean this up. this should be in exceptions.c */ - msglen = utf_bytes(declarer->name) + utf_bytes(mi->name) + - utf_bytes(mi->descriptor) + utf_bytes(referer->name) + 100; - message = MNEW(char, msglen); - strcpy(message, "method is not accessible ("); - utf_cat_classname(message, declarer->name); - strcat(message, "."); - utf_cat(message, mi->name); - utf_cat(message, mi->descriptor); - strcat(message," from "); - utf_cat_classname(message, referer->name); - strcat(message,")"); - *exceptionptr = new_exception_message(string_java_lang_IllegalAccessException, message); - MFREE(message, char, msglen); - return resolveFailed; /* exception */ - } - - /* everything ok */ - - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_method_instance_type_checks ***************************************** - - Check the instance type of a method invocation. - - IN: - refmethod........the method containing the reference - mi...............the methodinfo of the resolved method - instanceti.......typeinfo of the instance slot - invokespecial....true if the method is invoked by INVOKESPECIAL - - RETURN VALUE: - resolveSucceeded....everything ok - resolveDeferred.....tests could not be done, have been deferred - resolveFailed.......exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_method_instance_type_checks(methodinfo *refmethod, - methodinfo *mi, - typeinfo *instanceti, - bool invokespecial) -{ - typeinfo tinfo; - typeinfo *tip; - resolve_result_t result; - - if (invokespecial && TYPEINFO_IS_NEWOBJECT(*instanceti)) - { /* XXX clean up */ - instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); - classref_or_classinfo initclass = (ins) ? ins[-1].sx.val.c - : CLASSREF_OR_CLASSINFO(refmethod->class); - tip = &tinfo; - if (!typeinfo_init_class(tip, initclass)) - return false; - } - else { - tip = instanceti; - } - - result = resolve_lazy_subtype_checks(refmethod, - tip, - CLASSREF_OR_CLASSINFO(mi->class), - resolveLinkageError); - if (result != resolveSucceeded) - return result; - - /* check protected access */ - - /* XXX use other `declarer` than mi->class? */ - if (((mi->flags & ACC_PROTECTED) != 0) - && !SAME_PACKAGE(mi->class, refmethod->class)) - { - result = resolve_lazy_subtype_checks(refmethod, - tip, - CLASSREF_OR_CLASSINFO(refmethod->class), - resolveIllegalAccessError); - if (result != resolveSucceeded) - return result; - } - - /* everything ok */ - - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_method_param_type_checks ******************************************** - - Check non-instance parameter types of a method invocation. - - IN: - jd...............jitdata of the method doing the call - refmethod........the method containing the reference - iptr.............the invoke instruction - mi...............the methodinfo of the resolved method - invokestatic.....true if the method is invoked by INVOKESTATIC - - RETURN VALUE: - resolveSucceeded....everything ok - resolveDeferred.....tests could not be done, have been deferred - resolveFailed.......exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_method_param_type_checks(jitdata *jd, - methodinfo *refmethod, - instruction *iptr, - methodinfo *mi, - bool invokestatic) -{ - varinfo *param; - resolve_result_t result; - methoddesc *md; - typedesc *paramtypes; - s4 type; - s4 instancecount; - s4 i; - - assert(jd); - - instancecount = (invokestatic) ? 0 : 1; - - /* check subtype constraints for TYPE_ADR parameters */ - - md = mi->parseddesc; - paramtypes = md->paramtypes; - - for (i = md->paramcount-1-instancecount; i>=0; --i) { - param = VAR(iptr->sx.s23.s2.args[i+instancecount]); - type = md->paramtypes[i+instancecount].type; - - assert(param); - assert(type == param->type); - - if (type == TYPE_ADR) { - result = resolve_lazy_subtype_checks(refmethod, - &(param->typeinfo), - CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), - resolveLinkageError); - if (result != resolveSucceeded) - return result; - } - } - - /* everything ok */ - - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_method_param_type_checks_stackbased ********************************* - - Check non-instance parameter types of a method invocation. - - IN: - refmethod........the method containing the reference - mi...............the methodinfo of the resolved method - invokestatic.....true if the method is invoked by INVOKESTATIC - stack............TOS before the INVOKE instruction - - RETURN VALUE: - resolveSucceeded....everything ok - resolveDeferred.....tests could not be done, have been deferred - resolveFailed.......exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_method_param_type_checks_stackbased( - methodinfo *refmethod, - methodinfo *mi, - bool invokestatic, - typedescriptor *stack) -{ - typedescriptor *param; - resolve_result_t result; - methoddesc *md; - typedesc *paramtypes; - s4 type; - s4 instancecount; - s4 i; - - instancecount = (invokestatic) ? 0 : 1; - - /* check subtype constraints for TYPE_ADR parameters */ - - md = mi->parseddesc; - paramtypes = md->paramtypes; - - param = stack - (md->paramslots - 1 - instancecount); - - for (i = instancecount; i < md->paramcount; ++i) { - type = md->paramtypes[i].type; - - assert(type == param->type); - - if (type == TYPE_ADR) { - result = resolve_lazy_subtype_checks(refmethod, - &(param->typeinfo), - CLASSREF_OR_CLASSINFO(paramtypes[i].classref), - resolveLinkageError); - if (result != resolveSucceeded) - return result; - } - - param += (IS_2_WORD_TYPE(type)) ? 2 : 1; - } - - /* everything ok */ - - return resolveSucceeded; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_method_loading_constraints ****************************************** - - Impose loading constraints on the parameters and return type of the - given method. - - IN: - referer..........the class refering to the method - mi...............the method - - RETURN VALUE: - true................everything ok - false...............an exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -bool resolve_method_loading_constraints(classinfo *referer, - methodinfo *mi) -{ - methoddesc *md; - typedesc *paramtypes; - utf *name; - s4 i; - s4 instancecount; - - /* impose loading constraints on parameters (including instance) */ - - md = mi->parseddesc; - paramtypes = md->paramtypes; - instancecount = (mi->flags & ACC_STATIC) / ACC_STATIC; - - for (i = 0; i < md->paramcount; i++) { - if (i < instancecount || paramtypes[i].type == TYPE_ADR) { - if (i < instancecount) { - /* The type of the 'this' pointer is the class containing */ - /* the method definition. Since container is the same as, */ - /* or a subclass of declarer, we also constrain declarer */ - /* by transitivity of loading constraints. */ - name = mi->class->name; - } - else { - name = paramtypes[i].classref->name; - } - - /* The caller (referer) and the callee (container) must agree */ - /* on the types of the parameters. */ - if (!classcache_add_constraint(referer->classloader, - mi->class->classloader, name)) - return false; /* exception */ - } - } - - /* impose loading constraint onto return type */ - - if (md->returntype.type == TYPE_ADR) { - /* The caller (referer) and the callee (container) must agree */ - /* on the return type. */ - if (!classcache_add_constraint(referer->classloader, - mi->class->classloader, - md->returntype.classref->name)) - return false; /* exception */ - } - - /* everything ok */ - - return true; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_method_lazy ********************************************************* - - Resolve an unresolved method reference lazily - - NOTE: This function does NOT do any verification checks. In case of a - successful resolution, you must call resolve_method_verifier_checks - in order to perform the necessary checks! - - IN: - refmethod........the referer method - methodref........the method reference - invokespecial....true if this is an INVOKESPECIAL instruction - - RETURN VALUE: - resolveSucceeded.....the reference has been resolved - resolveDeferred......the resolving could not be performed lazily - resolveFailed........resolving failed, an exception has been thrown. - -*******************************************************************************/ - -resolve_result_t resolve_method_lazy(methodinfo *refmethod, - constant_FMIref *methodref, - bool invokespecial) -{ - classinfo *referer; - classinfo *container; - methodinfo *mi; - - assert(refmethod); - -#ifdef RESOLVE_VERBOSE - printf("resolve_method_lazy\n"); -#endif - - /* the class containing the reference */ - - referer = refmethod->class; - assert(referer); - - /* check if the method itself is already resolved */ - - if (IS_FMIREF_RESOLVED(methodref)) - return resolveSucceeded; - - /* first we must resolve the class containg the method */ - - if (!resolve_class_from_name(referer, refmethod, - methodref->p.classref->name, resolveLazy, true, true, &container)) - { - /* the class reference could not be resolved */ - return resolveFailed; /* exception */ - } - if (!container) - return resolveDeferred; /* be lazy */ - - assert(container->state & CLASS_LINKED); - - /* now we must find the declaration of the method in `container` - * or one of its superclasses */ - - if (container->flags & ACC_INTERFACE) { - mi = class_resolveinterfacemethod(container, - methodref->name, - methodref->descriptor, - referer, true); - - } else { - mi = class_resolveclassmethod(container, - methodref->name, - methodref->descriptor, - referer, true); - } - - if (!mi) { - /* The method does not exist. But since we were called lazily, */ - /* this error must not be reported now. (It will be reported */ - /* if eager resolving of this method is ever tried.) */ - - *exceptionptr = NULL; - return resolveDeferred; /* be lazy */ - } - - if (invokespecial) { - mi = resolve_method_invokespecial_lookup(refmethod, mi); - if (!mi) - return resolveFailed; /* exception */ - } - - /* have the method params already been parsed? no, do it. */ - - if (!mi->parseddesc->params) - if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) - return resolveFailed; - - /* cache the result of the resolution */ - - methodref->p.method = mi; - - /* succeed */ - - return resolveSucceeded; -} - -/* resolve_method ************************************************************** - - Resolve an unresolved method reference - - IN: - ref..............struct containing the reference - mode.............mode of resolution: - resolveLazy...only resolve if it does not - require loading classes - resolveEager..load classes if necessary - - OUT: - *result..........set to the result of resolution, or to NULL if - the reference has not been resolved - In the case of an exception, *result is - guaranteed to be set to NULL. - - RETURN VALUE: - true.............everything ok - (*result may still be NULL for resolveLazy) - false............an exception has been thrown - -*******************************************************************************/ - -bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **result) -{ - classinfo *referer; - classinfo *container; - classinfo *declarer; - methodinfo *mi; - typedesc *paramtypes; - int instancecount; - int i; - resolve_result_t checkresult; - - assert(ref); - assert(result); - assert(mode == resolveLazy || mode == resolveEager); - -#ifdef RESOLVE_VERBOSE - unresolved_method_debug_dump(ref,stdout); -#endif - - *result = NULL; - - /* the class containing the reference */ - - referer = ref->referermethod->class; - assert(referer); - - /* check if the method itself is already resolved */ - - if (IS_FMIREF_RESOLVED(ref->methodref)) { - mi = ref->methodref->p.method; - container = mi->class; - goto resolved_the_method; - } - - /* first we must resolve the class containing the method */ - - if (!resolve_class_from_name(referer,ref->referermethod, - ref->methodref->p.classref->name,mode,true,true,&container)) - { - /* the class reference could not be resolved */ - return false; /* exception */ - } - if (!container) - return true; /* be lazy */ - - assert(container); - assert(container->state & CLASS_LINKED); - - /* now we must find the declaration of the method in `container` - * or one of its superclasses */ - - if (container->flags & ACC_INTERFACE) { - mi = class_resolveinterfacemethod(container, - ref->methodref->name, - ref->methodref->descriptor, - referer, true); - - } else { - mi = class_resolveclassmethod(container, - ref->methodref->name, - ref->methodref->descriptor, - referer, true); - } - - if (!mi) { - if (mode == resolveLazy) { - /* The method does not exist. But since we were called lazily, */ - /* this error must not be reported now. (It will be reported */ - /* if eager resolving of this method is ever tried.) */ - - *exceptionptr = NULL; - return true; /* be lazy */ - } - - return false; /* exception */ /* XXX set exceptionptr? */ - } - - /* { the method reference has been resolved } */ - - if (ref->flags & RESOLVE_SPECIAL) { - mi = resolve_method_invokespecial_lookup(ref->referermethod,mi); - if (!mi) - return false; /* exception */ - } - - /* have the method params already been parsed? no, do it. */ - - if (!mi->parseddesc->params) - if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) - return false; - - /* cache the resolution */ - - ref->methodref->p.method = mi; - -resolved_the_method: - -#ifdef ENABLE_VERIFIER - if (opt_verify) { - - checkresult = resolve_method_verifier_checks( - ref->referermethod, - ref->methodref, - mi, - (ref->flags & RESOLVE_STATIC)); - - if (checkresult != resolveSucceeded) - return (bool) checkresult; - - /* impose loading constraints on params and return type */ - - if (!resolve_method_loading_constraints(referer, mi)) - return false; - - declarer = mi->class; - assert(declarer); - assert(referer->state & CLASS_LINKED); - - /* for non-static methods we have to check the constraints on the */ - /* instance type */ - - if (!(ref->flags & RESOLVE_STATIC)) { - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(container), - mode, - resolveLinkageError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - instancecount = 1; - } - else { - instancecount = 0; - } - - /* check subtype constraints for TYPE_ADR parameters */ - - assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); - paramtypes = mi->parseddesc->paramtypes; - - for (i = 0; i < mi->parseddesc->paramcount-instancecount; i++) { - if (paramtypes[i+instancecount].type == TYPE_ADR) { - if (ref->paramconstraints) { - checkresult = resolve_and_check_subtype_set(ref->referermethod, - ref->paramconstraints + i, - CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), - mode, - resolveLinkageError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - } - } - } - - /* check protected access */ - - if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) - { - checkresult = resolve_and_check_subtype_set(ref->referermethod, - &(ref->instancetypes), - CLASSREF_OR_CLASSINFO(referer), - mode, - resolveIllegalAccessError); - if (checkresult != resolveSucceeded) - return (bool) checkresult; - } - } -#endif /* ENABLE_VERIFIER */ - - /* succeed */ - *result = mi; - return true; -} - -/* resolve_method_eager ******************************************************** - - Resolve an unresolved method reference eagerly. - - IN: - ref..............struct containing the reference - - RETURN VALUE: - methodinfo * to the method, or - NULL if an exception has been thrown - -*******************************************************************************/ - -methodinfo * resolve_method_eager(unresolved_method *ref) -{ - methodinfo *mi; - - if (!resolve_method(ref,resolveEager,&mi)) - return NULL; - - return mi; -} - -/******************************************************************************/ -/* CREATING THE DATA STRUCTURES */ -/******************************************************************************/ - -#ifdef ENABLE_VERIFIER -static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, - methodinfo *refmethod, - unresolved_subtype_set *stset, - typeinfo *tinfo, - utf *declaredclassname) -{ - int count; - int i; - - assert(stset); - assert(tinfo); - -#ifdef RESOLVE_VERBOSE - printf("unresolved_subtype_set_from_typeinfo\n"); -#ifdef TYPEINFO_DEBUG - typeinfo_print(stdout,tinfo,4); -#endif - printf(" declared classname:");utf_fprint_printable_ascii(stdout,declaredclassname); - printf("\n"); -#endif - - if (TYPEINFO_IS_PRIMITIVE(*tinfo)) { - exceptions_throw_verifyerror(refmethod, - "Invalid use of returnAddress"); - return false; - } - - if (TYPEINFO_IS_NEWOBJECT(*tinfo)) { - exceptions_throw_verifyerror(refmethod, - "Invalid use of uninitialized object"); - return false; - } - - /* the nulltype is always assignable */ - if (TYPEINFO_IS_NULLTYPE(*tinfo)) - goto empty_set; - - /* every type is assignable to (BOOTSTRAP)java.lang.Object */ - if (declaredclassname == utf_java_lang_Object - && referer->classloader == NULL) /* XXX do loading constraints make the second check obsolete? */ - { - goto empty_set; - } - - if (tinfo->merged) { - count = tinfo->merged->count; - stset->subtyperefs = MNEW(classref_or_classinfo,count + 1); - for (i=0; imerged->list[i]; - if (tinfo->dimension > 0) { - /* a merge of array types */ - /* the merged list contains the possible _element_ types, */ - /* so we have to create array types with these elements. */ - if (IS_CLASSREF(c)) { - c.ref = class_get_classref_multiarray_of(tinfo->dimension,c.ref); - } - else { - c.cls = class_multiarray_of(tinfo->dimension,c.cls,false); - } - } - stset->subtyperefs[i] = c; - } - stset->subtyperefs[count].any = NULL; /* terminate */ - } - else { - if ((IS_CLASSREF(tinfo->typeclass) - ? tinfo->typeclass.ref->name - : tinfo->typeclass.cls->name) == declaredclassname) - { - /* the class names are the same */ - /* equality is guaranteed by the loading constraints */ - goto empty_set; - } - else { - stset->subtyperefs = MNEW(classref_or_classinfo,1 + 1); - stset->subtyperefs[0] = tinfo->typeclass; - stset->subtyperefs[1].any = NULL; /* terminate */ - } - } - - return true; - -empty_set: - UNRESOLVED_SUBTYPE_SET_EMTPY(*stset); - return true; -} -#endif /* ENABLE_VERIFIER */ - -/* create_unresolved_class ***************************************************** - - Create an unresolved_class struct for the given class reference - - IN: - refmethod........the method triggering the resolution (if any) - classref.........the class reference - valuetype........value type to check against the resolved class - may be NULL, if no typeinfo is available - - RETURN VALUE: - a pointer to a new unresolved_class struct, or - NULL if an exception has been thrown - -*******************************************************************************/ - -#ifdef ENABLE_VERIFIER -unresolved_class * create_unresolved_class(methodinfo *refmethod, - constant_classref *classref, - typeinfo *valuetype) -{ - unresolved_class *ref; - -#ifdef RESOLVE_VERBOSE - printf("create_unresolved_class\n"); - printf(" referer: ");utf_fprint_printable_ascii(stdout,classref->referer->name);fputc('\n',stdout); - if (refmethod) { - printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); - printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); - } - printf(" name : ");utf_fprint_printable_ascii(stdout,classref->name);fputc('\n',stdout); -#endif - - ref = NEW(unresolved_class); - ref->classref = classref; - ref->referermethod = refmethod; - - if (valuetype) { - if (!unresolved_subtype_set_from_typeinfo(classref->referer,refmethod, - &(ref->subtypeconstraints),valuetype,classref->name)) - return NULL; - } - else { - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->subtypeconstraints); - } - - return ref; -} -#endif /* ENABLE_VERIFIER */ - -/* resolve_create_unresolved_field ********************************************* - - Create an unresolved_field struct for the given field access instruction - - IN: - referer..........the class containing the reference - refmethod........the method triggering the resolution (if any) - iptr.............the {GET,PUT}{FIELD,STATIC}{,CONST} instruction - - RETURN VALUE: - a pointer to a new unresolved_field struct, or - NULL if an exception has been thrown - -*******************************************************************************/ - -unresolved_field * resolve_create_unresolved_field(classinfo *referer, - methodinfo *refmethod, - instruction *iptr) -{ - unresolved_field *ref; - constant_FMIref *fieldref = NULL; - -#ifdef RESOLVE_VERBOSE - printf("create_unresolved_field\n"); - printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); - printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); - printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); -#endif - - ref = NEW(unresolved_field); - ref->flags = 0; - ref->referermethod = refmethod; - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); - - switch (iptr->opc) { - case ICMD_PUTFIELD: - ref->flags |= RESOLVE_PUTFIELD; - break; - - case ICMD_PUTFIELDCONST: - ref->flags |= RESOLVE_PUTFIELD; - break; - - case ICMD_PUTSTATIC: - ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; - break; - - case ICMD_PUTSTATICCONST: - ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; - break; - - case ICMD_GETFIELD: - break; - - case ICMD_GETSTATIC: - ref->flags |= RESOLVE_STATIC; - break; - -#if !defined(NDEBUG) - default: - assert(false); -#endif - } - - fieldref = iptr->sx.s23.s3.fmiref; - - assert(fieldref); - -#ifdef RESOLVE_VERBOSE -/* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout);*/ - printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout); - printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout); - printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd); - fputc('\n',stdout); -#endif - - ref->fieldref = fieldref; - - return ref; -} - -/* resolve_constrain_unresolved_field ****************************************** - - Record subtype constraints for a field access. - - IN: - ref..............the unresolved_field structure of the access - referer..........the class containing the reference - refmethod........the method triggering the resolution (if any) - instanceti.......instance typeinfo, if available - valueti..........value typeinfo, if available - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -bool resolve_constrain_unresolved_field(unresolved_field *ref, - classinfo *referer, - methodinfo *refmethod, - typeinfo *instanceti, - typeinfo *valueti) -{ - constant_FMIref *fieldref; - int type; - typeinfo tinfo; - typedesc *fd; - - assert(ref); - - fieldref = ref->fieldref; - assert(fieldref); - -#ifdef RESOLVE_VERBOSE - printf("constrain_unresolved_field\n"); - printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); - printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); - printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); -/* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout); */ - printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout); - printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout); - printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd); - fputc('\n',stdout); -#endif - - assert(instanceti || ((ref->flags & RESOLVE_STATIC) != 0)); - fd = fieldref->parseddesc.fd; - assert(fd); - - /* record subtype constraints for the instance type, if any */ - if (instanceti) { - typeinfo *insttip; - - /* The instanceslot must contain a reference to a non-array type */ - if (!TYPEINFO_IS_REFERENCE(*instanceti)) { - exceptions_throw_verifyerror(refmethod, - "illegal instruction: field access on non-reference"); - return false; - } - if (TYPEINFO_IS_ARRAY(*instanceti)) { - exceptions_throw_verifyerror(refmethod, - "illegal instruction: field access on array"); - return false; - } - - if (((ref->flags & RESOLVE_PUTFIELD) != 0) && - TYPEINFO_IS_NEWOBJECT(*instanceti)) - { - /* The instruction writes a field in an uninitialized object. */ - /* This is only allowed when a field of an uninitialized 'this' object is */ - /* written inside an initialization method */ - - classinfo *initclass; - instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); - - if (ins != NULL) { - exceptions_throw_verifyerror(refmethod, - "accessing field of uninitialized object"); - return false; - } - /* XXX check that class of field == refmethod->class */ - initclass = refmethod->class; /* XXX classrefs */ - assert(initclass->state & CLASS_LOADED); - assert(initclass->state & CLASS_LINKED); - - typeinfo_init_classinfo(&tinfo, initclass); - insttip = &tinfo; - } - else { - insttip = instanceti; - } - if (!unresolved_subtype_set_from_typeinfo(referer, refmethod, - &(ref->instancetypes), insttip, - FIELDREF_CLASSNAME(fieldref))) - return false; - } - else { - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); - } - - /* record subtype constraints for the value type, if any */ - type = fd->type; - if (type == TYPE_ADR && ((ref->flags & RESOLVE_PUTFIELD) != 0)) { - assert(valueti); - if (!unresolved_subtype_set_from_typeinfo(referer, refmethod, - &(ref->valueconstraints), valueti, - fieldref->parseddesc.fd->classref->name)) - return false; - } - else { - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); - } - - return true; -} -#endif /* ENABLE_VERIFIER */ - -/* resolve_create_unresolved_method ******************************************** - - Create an unresolved_method struct for the given method invocation - - IN: - referer..........the class containing the reference - refmethod........the method triggering the resolution (if any) - iptr.............the INVOKE* instruction - - RETURN VALUE: - a pointer to a new unresolved_method struct, or - NULL if an exception has been thrown - -*******************************************************************************/ - -unresolved_method * resolve_create_unresolved_method(classinfo *referer, - methodinfo *refmethod, - constant_FMIref *methodref, - bool invokestatic, - bool invokespecial) -{ - unresolved_method *ref; - - assert(methodref); - -#ifdef RESOLVE_VERBOSE - printf("create_unresolved_method\n"); - printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); - printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); - printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); - printf(" name : ");utf_fprint_printable_ascii(stdout,methodref->name);fputc('\n',stdout); - printf(" desc : ");utf_fprint_printable_ascii(stdout,methodref->descriptor);fputc('\n',stdout); -#endif - - /* allocate params if necessary */ - if (!methodref->parseddesc.md->params) - if (!descriptor_params_from_paramtypes(methodref->parseddesc.md, - (invokestatic) ? ACC_STATIC : ACC_NONE)) - return NULL; - - /* create the data structure */ - ref = NEW(unresolved_method); - ref->flags = ((invokestatic) ? RESOLVE_STATIC : 0) - | ((invokespecial) ? RESOLVE_SPECIAL : 0); - ref->referermethod = refmethod; - ref->methodref = methodref; - ref->paramconstraints = NULL; - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); - - return ref; -} - - -/* resolve_constrain_unresolved_method_instance ******************************** - - Record subtype constraints for the instance argument of a method call. - - IN: - ref..............the unresolved_method structure of the call - referer..........the class containing the reference - refmethod........the method triggering the resolution (if any) - iptr.............the INVOKE* instruction - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -bool resolve_constrain_unresolved_method_instance(unresolved_method *ref, - methodinfo *refmethod, - typeinfo *instanceti, - bool invokespecial) -{ - constant_FMIref *methodref; - constant_classref *instanceref; - typeinfo tinfo; - typeinfo *tip; - - assert(ref); - methodref = ref->methodref; - assert(methodref); - - /* XXX clean this up */ - instanceref = IS_FMIREF_RESOLVED(methodref) - ? class_get_self_classref(methodref->p.method->class) - : methodref->p.classref; - -#ifdef RESOLVE_VERBOSE - printf("resolve_constrain_unresolved_method_instance\n"); - printf(" rmethod: "); method_println(refmethod); - printf(" mref : "); method_methodref_println(methodref); -#endif - - /* record subtype constraints for the instance type, if any */ - - if (invokespecial && TYPEINFO_IS_NEWOBJECT(*instanceti)) - { /* XXX clean up */ - instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); - classref_or_classinfo initclass = (ins) ? ins[-1].sx.val.c - : CLASSREF_OR_CLASSINFO(refmethod->class); - tip = &tinfo; - if (!typeinfo_init_class(tip, initclass)) - return false; - } - else { - tip = instanceti; - } - - if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, - &(ref->instancetypes),tip,instanceref->name)) - return false; - - return true; -} -#endif /* defined(ENABLE_VERIFIER) */ - - -/* resolve_constrain_unresolved_method_params ********************************* - - Record subtype constraints for the non-instance arguments of a method call. - - IN: - jd...............current jitdata (for looking up variables) - ref..............the unresolved_method structure of the call - refmethod........the method triggering the resolution (if any) - iptr.............the INVOKE* instruction - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -bool resolve_constrain_unresolved_method_params(jitdata *jd, - unresolved_method *ref, - methodinfo *refmethod, - instruction *iptr) -{ - constant_FMIref *methodref; - varinfo *param; - methoddesc *md; - int i,j; - int type; - int instancecount; - - assert(ref); - methodref = ref->methodref; - assert(methodref); - md = methodref->parseddesc.md; - assert(md); - assert(md->params != NULL); - -#ifdef RESOLVE_VERBOSE - printf("resolve_constrain_unresolved_method_params\n"); - printf(" rmethod: "); method_println(refmethod); - printf(" mref : "); method_methodref_println(methodref); -#endif - - instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1; - - /* record subtype constraints for the parameter types, if any */ - - for (i=md->paramcount-1-instancecount; i>=0; --i) { - param = VAR(iptr->sx.s23.s2.args[i+instancecount]); - type = md->paramtypes[i+instancecount].type; - - assert(param); - assert(type == param->type); - - if (type == TYPE_ADR) { - if (!ref->paramconstraints) { - ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount); - for (j=md->paramcount-1-instancecount; j>i; --j) - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]); - } - assert(ref->paramconstraints); - if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, - ref->paramconstraints + i,&(param->typeinfo), - md->paramtypes[i+instancecount].classref->name)) - return false; - } - else { - if (ref->paramconstraints) - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]); - } - } - - return true; -} -#endif /* ENABLE_VERIFIER */ - - -/* resolve_constrain_unresolved_method_params_stackbased *********************** - - Record subtype constraints for the non-instance arguments of a method call. - - IN: - ref..............the unresolved_method structure of the call - refmethod........the method triggering the resolution (if any) - stack............TOS before the INVOKE instruction - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - -*******************************************************************************/ - -#if defined(ENABLE_VERIFIER) -bool resolve_constrain_unresolved_method_params_stackbased( - unresolved_method *ref, - methodinfo *refmethod, - typedescriptor *stack) -{ - constant_FMIref *methodref; - typedescriptor *param; - methoddesc *md; - int i,j; - int type; - int instancecount; - - assert(ref); - methodref = ref->methodref; - assert(methodref); - md = methodref->parseddesc.md; - assert(md); - assert(md->params != NULL); - -#ifdef RESOLVE_VERBOSE - printf("resolve_constrain_unresolved_method_params_stackbased\n"); - printf(" rmethod: "); method_println(refmethod); - printf(" mref : "); method_methodref_println(methodref); -#endif - - instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1; - - /* record subtype constraints for the parameter types, if any */ - - param = stack - (md->paramslots - 1 - instancecount); - - for (i = instancecount; i < md->paramcount; ++i) { - type = md->paramtypes[i].type; - - assert(type == param->type); - - if (type == TYPE_ADR) { - if (!ref->paramconstraints) { - ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount); - for (j = 0; j < i - instancecount; ++j) - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]); - } - assert(ref->paramconstraints); - if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, - ref->paramconstraints + i - instancecount,&(param->typeinfo), - md->paramtypes[i].classref->name)) - return false; - } - else { - if (ref->paramconstraints) - UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]); - } - - param += (IS_2_WORD_TYPE(type)) ? 2 : 1; - } - - return true; -} -#endif /* ENABLE_VERIFIER */ - - -/******************************************************************************/ -/* FREEING MEMORY */ -/******************************************************************************/ - -#ifdef ENABLE_VERIFIER -inline static void unresolved_subtype_set_free_list(classref_or_classinfo *list) -{ - if (list) { - classref_or_classinfo *p = list; - - /* this is silly. we *only* need to count the elements for MFREE */ - while ((p++)->any) - ; - MFREE(list,classref_or_classinfo,(p - list)); - } -} -#endif /* ENABLE_VERIFIER */ - -/* unresolved_class_free ******************************************************* - - Free the memory used by an unresolved_class - - IN: - ref..............the unresolved_class - -*******************************************************************************/ - -void unresolved_class_free(unresolved_class *ref) -{ - assert(ref); - -#ifdef ENABLE_VERIFIER - unresolved_subtype_set_free_list(ref->subtypeconstraints.subtyperefs); -#endif - FREE(ref,unresolved_class); -} - -/* unresolved_field_free ******************************************************* - - Free the memory used by an unresolved_field - - IN: - ref..............the unresolved_field - -*******************************************************************************/ - -void unresolved_field_free(unresolved_field *ref) -{ - assert(ref); - -#ifdef ENABLE_VERIFIER - unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs); - unresolved_subtype_set_free_list(ref->valueconstraints.subtyperefs); -#endif - FREE(ref,unresolved_field); -} - -/* unresolved_method_free ****************************************************** - - Free the memory used by an unresolved_method - - IN: - ref..............the unresolved_method - -*******************************************************************************/ - -void unresolved_method_free(unresolved_method *ref) -{ - assert(ref); - -#ifdef ENABLE_VERIFIER - unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs); - if (ref->paramconstraints) { - int i; - int count = ref->methodref->parseddesc.md->paramcount; - - for (i=0; iparamconstraints[i].subtyperefs); - MFREE(ref->paramconstraints,unresolved_subtype_set,count); - } -#endif - FREE(ref,unresolved_method); -} - -/******************************************************************************/ -/* DEBUG DUMPS */ -/******************************************************************************/ - -#if !defined(NDEBUG) - -/* unresolved_subtype_set_debug_dump ******************************************* - - Print debug info for unresolved_subtype_set to stream - - IN: - stset............the unresolved_subtype_set - file.............the stream - -*******************************************************************************/ - -void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file) -{ - classref_or_classinfo *p; - - if (SUBTYPESET_IS_EMPTY(*stset)) { - fprintf(file," (empty)\n"); - } - else { - p = stset->subtyperefs; - for (;p->any; ++p) { - if (IS_CLASSREF(*p)) { - fprintf(file," ref: "); - utf_fprint_printable_ascii(file,p->ref->name); - } - else { - fprintf(file," cls: "); - utf_fprint_printable_ascii(file,p->cls->name); - } - fputc('\n',file); - } - } -} - -/* unresolved_class_debug_dump ************************************************* - - Print debug info for unresolved_class to stream - - IN: - ref..............the unresolved_class - file.............the stream - -*******************************************************************************/ - -void unresolved_class_debug_dump(unresolved_class *ref,FILE *file) -{ - fprintf(file,"unresolved_class(%p):\n",(void *)ref); - if (ref) { - fprintf(file," referer : "); - utf_fprint_printable_ascii(file,ref->classref->referer->name); fputc('\n',file); - fprintf(file," refmethod : "); - utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); - fprintf(file," refmethodd: "); - utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); - fprintf(file," classname : "); - utf_fprint_printable_ascii(file,ref->classref->name); fputc('\n',file); - fprintf(file," subtypeconstraints:\n"); - unresolved_subtype_set_debug_dump(&(ref->subtypeconstraints),file); - } -} - -/* unresolved_field_debug_dump ************************************************* - - Print debug info for unresolved_field to stream - - IN: - ref..............the unresolved_field - file.............the stream - -*******************************************************************************/ - -void unresolved_field_debug_dump(unresolved_field *ref,FILE *file) -{ - fprintf(file,"unresolved_field(%p):\n",(void *)ref); - if (ref) { - fprintf(file," referer : "); - utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); - fprintf(file," refmethod : "); - utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); - fprintf(file," refmethodd: "); - utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); - fprintf(file," classname : "); - utf_fprint_printable_ascii(file,FIELDREF_CLASSNAME(ref->fieldref)); fputc('\n',file); - fprintf(file," name : "); - utf_fprint_printable_ascii(file,ref->fieldref->name); fputc('\n',file); - fprintf(file," descriptor: "); - utf_fprint_printable_ascii(file,ref->fieldref->descriptor); fputc('\n',file); - fprintf(file," parseddesc: "); - descriptor_debug_print_typedesc(file,ref->fieldref->parseddesc.fd); fputc('\n',file); - fprintf(file," flags : %04x\n",ref->flags); - fprintf(file," instancetypes:\n"); - unresolved_subtype_set_debug_dump(&(ref->instancetypes),file); - fprintf(file," valueconstraints:\n"); - unresolved_subtype_set_debug_dump(&(ref->valueconstraints),file); - } -} - -/* unresolved_method_debug_dump ************************************************ - - Print debug info for unresolved_method to stream - - IN: - ref..............the unresolved_method - file.............the stream - -*******************************************************************************/ - -void unresolved_method_debug_dump(unresolved_method *ref,FILE *file) -{ - int i; - - fprintf(file,"unresolved_method(%p):\n",(void *)ref); - if (ref) { - fprintf(file," referer : "); - utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); - fprintf(file," refmethod : "); - utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); - fprintf(file," refmethodd: "); - utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); - fprintf(file," classname : "); - utf_fprint_printable_ascii(file,METHODREF_CLASSNAME(ref->methodref)); fputc('\n',file); - fprintf(file," name : "); - utf_fprint_printable_ascii(file,ref->methodref->name); fputc('\n',file); - fprintf(file," descriptor: "); - utf_fprint_printable_ascii(file,ref->methodref->descriptor); fputc('\n',file); - fprintf(file," parseddesc: "); - descriptor_debug_print_methoddesc(file,ref->methodref->parseddesc.md); fputc('\n',file); - fprintf(file," flags : %04x\n",ref->flags); - fprintf(file," instancetypes:\n"); - unresolved_subtype_set_debug_dump(&(ref->instancetypes),file); - fprintf(file," paramconstraints:\n"); - if (ref->paramconstraints) { - for (i=0; imethodref->parseddesc.md->paramcount; ++i) { - fprintf(file," param %d:\n",i); - unresolved_subtype_set_debug_dump(ref->paramconstraints + i,file); - } - } - else { - fprintf(file," (empty)\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: - */ - diff --git a/src/vm/resolve.h b/src/vm/resolve.h deleted file mode 100644 index 5abc7dcf5..000000000 --- a/src/vm/resolve.h +++ /dev/null @@ -1,277 +0,0 @@ -/* src/vm/resolve.h - resolving classes/interfaces/fields/methods - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id: resolve.h 6241 2006-12-26 23:42:35Z twisti $ - -*/ - - -#ifndef _RESOLVE_H -#define _RESOLVE_H - -/* forward declarations *******************************************************/ - -typedef struct unresolved_class unresolved_class; -typedef struct unresolved_field unresolved_field; -typedef struct unresolved_method unresolved_method; -typedef struct unresolved_subtype_set unresolved_subtype_set; - - -#include "config.h" -#include "vm/types.h" - -#include "vm/class.h" -#include "vm/field.h" -#include "vm/global.h" -#include "vm/method.h" -#include "vm/references.h" -#include "vm/jit/jit.h" -#include "vm/jit/reg.h" -#include "vm/jit/verify/typeinfo.h" - - -/* constants ******************************************************************/ - -#define RESOLVE_STATIC 0x0001 /* ref to static fields/methods */ -#define RESOLVE_PUTFIELD 0x0002 /* field ref inside a PUT{FIELD,STATIC}... */ -#define RESOLVE_SPECIAL 0x0004 /* method ref inside INVOKESPECIAL */ - - -/* enums **********************************************************************/ - -typedef enum { - resolveLazy, - resolveEager -} resolve_mode_t; - -typedef enum { - resolveLinkageError, - resolveIllegalAccessError -} resolve_err_t; - -typedef enum { - resolveFailed = false, /* this must be a false value */ - resolveDeferred = true, /* this must be a true value */ - resolveSucceeded -} resolve_result_t; - -/* structs ********************************************************************/ - -struct unresolved_subtype_set { - classref_or_classinfo *subtyperefs; /* NULL terminated list */ -}; - -struct unresolved_class { - constant_classref *classref; - methodinfo *referermethod; - unresolved_subtype_set subtypeconstraints; -}; - -/* XXX unify heads of unresolved_field and unresolved_method? */ - -struct unresolved_field { - constant_FMIref *fieldref; - methodinfo *referermethod; - s4 flags; - - unresolved_subtype_set instancetypes; - unresolved_subtype_set valueconstraints; -}; - -struct unresolved_method { - constant_FMIref *methodref; - methodinfo *referermethod; - s4 flags; - - unresolved_subtype_set instancetypes; - unresolved_subtype_set *paramconstraints; -}; - -#define SUBTYPESET_IS_EMPTY(stset) \ - ((stset).subtyperefs == NULL) - -#define UNRESOLVED_SUBTYPE_SET_EMTPY(stset) \ - do { (stset).subtyperefs = NULL; } while(0) - -/* function prototypes ********************************************************/ - -bool resolve_class_from_name(classinfo* referer,methodinfo *refmethod, - utf *classname, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result); - -bool resolve_classref(methodinfo *refmethod, - constant_classref *ref, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result); - -bool resolve_classref_or_classinfo(methodinfo *refmethod, - classref_or_classinfo cls, - resolve_mode_t mode, - bool checkaccess, - bool link, - classinfo **result); - -bool resolve_class_from_typedesc(typedesc *d,bool checkaccess,bool link,classinfo **result); - -#ifdef ENABLE_VERIFIER -bool resolve_class(unresolved_class *ref, - resolve_mode_t mode, - bool checkaccess, - classinfo **result); - -classinfo * resolve_class_eager(unresolved_class *ref); -#endif /* ENABLE_VERIFIER */ - -bool resolve_field(unresolved_field *ref, - resolve_mode_t mode, - fieldinfo **result); - -bool resolve_method(unresolved_method *ref, - resolve_mode_t mode, - methodinfo **result); - -classinfo * resolve_classref_eager(constant_classref *ref); -classinfo * resolve_classref_eager_nonabstract(constant_classref *ref); -fieldinfo * resolve_field_eager(unresolved_field *ref); -methodinfo * resolve_method_eager(unresolved_method *ref); - -#ifdef ENABLE_VERIFIER -unresolved_class * create_unresolved_class(methodinfo *refmethod, - constant_classref *classref, - typeinfo *valuetype); -#endif - -unresolved_field *resolve_create_unresolved_field(classinfo *referer, - methodinfo *refmethod, - instruction *iptr); - -unresolved_method * resolve_create_unresolved_method(classinfo *referer, - methodinfo *refmethod, - constant_FMIref *methodref, - bool invokestatic, - bool invokespecial); - -void unresolved_class_free(unresolved_class *ref); -void unresolved_field_free(unresolved_field *ref); -void unresolved_method_free(unresolved_method *ref); - -resolve_result_t resolve_method_lazy(methodinfo *refmethod, - constant_FMIref *methodref, - bool invokespecial); - -resolve_result_t resolve_field_lazy(methodinfo *refmethod, - constant_FMIref *fieldref); - -#if defined(ENABLE_VERIFIER) -resolve_result_t resolve_field_verifier_checks(methodinfo *refmethod, - constant_FMIref *fieldref, - classinfo *container, - fieldinfo *fi, - typeinfo *instanceti, - typeinfo *valueti, - bool isstatic, - bool isput); - -bool resolve_constrain_unresolved_field(unresolved_field *ref, - classinfo *referer, - methodinfo *refmethod, - typeinfo *instanceti, - typeinfo *valueti); - -resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, - constant_FMIref *methodref, - methodinfo *mi, - bool invokestatic); - -resolve_result_t resolve_method_instance_type_checks(methodinfo *refmethod, - methodinfo *mi, - typeinfo *instanceti, - bool invokespecial); - -resolve_result_t resolve_method_param_type_checks(jitdata *jd, - methodinfo *refmethod, - instruction *iptr, - methodinfo *mi, - bool invokestatic); - -resolve_result_t resolve_method_param_type_checks_stackbased( - methodinfo *refmethod, - methodinfo *mi, - bool invokestatic, - typedescriptor *stack); - -bool resolve_method_loading_constraints(classinfo *referer, - methodinfo *mi); - -bool resolve_constrain_unresolved_method_instance(unresolved_method *ref, - methodinfo *refmethod, - typeinfo *instanceti, - bool invokespecial); - -bool resolve_constrain_unresolved_method_params(jitdata *jd, - unresolved_method *ref, - methodinfo *refmethod, - instruction *iptr); - -bool resolve_constrain_unresolved_method_params_stackbased( - unresolved_method *ref, - methodinfo *refmethod, - typedescriptor *stack); - -#endif /* defined(ENABLE_VERIFIER) */ - -#ifndef NDEBUG -void unresolved_class_debug_dump(unresolved_class *ref,FILE *file); -void unresolved_field_debug_dump(unresolved_field *ref,FILE *file); -void unresolved_method_debug_dump(unresolved_method *ref,FILE *file); -void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file); -#endif - -#endif /* _RESOLVE_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: - */ - diff --git a/src/vm/rt-timing.c b/src/vm/rt-timing.c deleted file mode 100644 index c16fbe0fa..000000000 --- a/src/vm/rt-timing.c +++ /dev/null @@ -1,188 +0,0 @@ -/* src/vm/rt-timing.c - POSIX real-time timing utilities - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id$ - -*/ - - -#include "config.h" -#include "vm/types.h" - -#include -#include -#include -#include - -#include "vm/rt-timing.h" -#include "mm/memory.h" -#include "vm/global.h" - -struct rt_timing_stat { - int index; - int totalindex; - const char *name; -}; - -static struct rt_timing_stat rt_timing_stat_defs[] = { - { RT_TIMING_JIT_CHECKS ,RT_TIMING_JIT_TOTAL , "checks at beginning" }, - { RT_TIMING_JIT_PARSE ,RT_TIMING_JIT_TOTAL , "parse" }, - { RT_TIMING_JIT_STACK ,RT_TIMING_JIT_TOTAL , "analyse_stack" }, - { RT_TIMING_JIT_TYPECHECK ,RT_TIMING_JIT_TOTAL , "typecheck" }, - { RT_TIMING_JIT_LOOP ,RT_TIMING_JIT_TOTAL , "loop" }, - { RT_TIMING_JIT_IFCONV ,RT_TIMING_JIT_TOTAL , "if conversion" }, - { RT_TIMING_JIT_ALLOC ,RT_TIMING_JIT_TOTAL , "register allocation" }, - { RT_TIMING_JIT_RPLPOINTS ,RT_TIMING_JIT_TOTAL , "replacement point generation" }, - { RT_TIMING_JIT_CODEGEN ,RT_TIMING_JIT_TOTAL , "codegen" }, - { RT_TIMING_JIT_TOTAL ,-1 , "total compile time" }, - { -1 ,-1 , "" }, - - { RT_TIMING_LINK_RESOLVE ,RT_TIMING_LINK_TOTAL, "link: resolve superclass/superinterfaces"}, - { RT_TIMING_LINK_C_VFTBL ,RT_TIMING_LINK_TOTAL, "link: compute vftbl length"}, - { RT_TIMING_LINK_ABSTRACT ,RT_TIMING_LINK_TOTAL, "link: handle abstract methods"}, - { RT_TIMING_LINK_C_IFTBL ,RT_TIMING_LINK_TOTAL, "link: compute interface table"}, - { RT_TIMING_LINK_F_VFTBL ,RT_TIMING_LINK_TOTAL, "link: fill vftbl"}, - { RT_TIMING_LINK_OFFSETS ,RT_TIMING_LINK_TOTAL, "link: set offsets"}, - { RT_TIMING_LINK_F_IFTBL ,RT_TIMING_LINK_TOTAL, "link: fill interface table"}, - { RT_TIMING_LINK_FINALIZER ,RT_TIMING_LINK_TOTAL, "link: set finalizer"}, - { RT_TIMING_LINK_EXCEPTS ,RT_TIMING_LINK_TOTAL, "link: resolve exception classes"}, - { RT_TIMING_LINK_SUBCLASS ,RT_TIMING_LINK_TOTAL, "link: re-calculate subclass indices"}, - { RT_TIMING_LINK_TOTAL ,-1 , "total link time" }, - { -1 ,-1 , "" }, - - { RT_TIMING_LOAD_CHECKS ,RT_TIMING_LOAD_TOTAL, "load: initial checks"}, - { RT_TIMING_LOAD_NDPOOL ,RT_TIMING_LOAD_TOTAL, "load: new descriptor pool"}, - { RT_TIMING_LOAD_CPOOL ,RT_TIMING_LOAD_TOTAL, "load: load constant pool"}, - { RT_TIMING_LOAD_SETUP ,RT_TIMING_LOAD_TOTAL, "load: class setup"}, - { RT_TIMING_LOAD_FIELDS ,RT_TIMING_LOAD_TOTAL, "load: load fields"}, - { RT_TIMING_LOAD_METHODS ,RT_TIMING_LOAD_TOTAL, "load: load methods"}, - { RT_TIMING_LOAD_CLASSREFS ,RT_TIMING_LOAD_TOTAL, "load: create classrefs"}, - { RT_TIMING_LOAD_DESCS ,RT_TIMING_LOAD_TOTAL, "load: allocate descriptors"}, - { RT_TIMING_LOAD_SETREFS ,RT_TIMING_LOAD_TOTAL, "load: set classrefs"}, - { RT_TIMING_LOAD_PARSEFDS ,RT_TIMING_LOAD_TOTAL, "load: parse field descriptors"}, - { RT_TIMING_LOAD_PARSEMDS ,RT_TIMING_LOAD_TOTAL, "load: parse method descriptors"}, - { RT_TIMING_LOAD_PARSECP ,RT_TIMING_LOAD_TOTAL, "load: parse descriptors in constant pool"}, - { RT_TIMING_LOAD_VERIFY ,RT_TIMING_LOAD_TOTAL, "load: verifier checks"}, - { RT_TIMING_LOAD_ATTRS ,RT_TIMING_LOAD_TOTAL, "load: load attributes"}, - { RT_TIMING_LOAD_TOTAL ,-1 , "total load time (from classbuffer)"}, - { -1 ,-1 , "" }, - - { RT_TIMING_LOAD_BOOT_LOOKUP,-1 , "boot: lookup in classcache"}, - { RT_TIMING_LOAD_BOOT_ARRAY ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: load array classes"}, - { RT_TIMING_LOAD_BOOT_SUCK ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: suck class files"}, - { RT_TIMING_LOAD_BOOT_LOAD ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: load from class buffer"}, - { RT_TIMING_LOAD_BOOT_CACHE ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: store in classcache"}, - { RT_TIMING_LOAD_BOOT_TOTAL ,-1 , "total bootstrap loader time"}, - { -1 ,-1 , "" }, - - { RT_TIMING_LOAD_CL_LOOKUP ,-1 , "classloader: lookup in classcache" }, - { RT_TIMING_LOAD_CL_PREPARE ,-1 , "classloader: prepare loader call" }, - { RT_TIMING_LOAD_CL_JAVA ,-1 , "classloader: loader Java code" }, - { RT_TIMING_LOAD_CL_CACHE ,-1 , "classloader: store in classcache" }, - { -1 ,-1 , "" }, - - { RT_TIMING_NEW_OBJECT ,-1 , "builtin_new time" }, - { RT_TIMING_NEW_ARRAY ,-1 , "builtin_newarray time" }, - { -1 ,-1 , "" }, - - { 0 ,-1 , NULL } -}; - -static long long rt_timing_sum[RT_TIMING_N] = { 0 }; - -void rt_timing_gettime(struct timespec *ts) -{ - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,ts) != 0) { - fprintf(stderr,"could not get time by clock_gettime: %s\n",strerror(errno)); - abort(); - } -} - -long rt_timing_diff_usec(struct timespec *a,struct timespec *b) -{ - long diff; - time_t atime; - - diff = (b->tv_nsec - a->tv_nsec) / 1000; - atime = a->tv_sec; - while (atime < b->tv_sec) { - atime++; - diff += 1000000; - } - return diff; -} - -void rt_timing_time_diff(struct timespec *a,struct timespec *b,int index) -{ - long diff; - - diff = rt_timing_diff_usec(a,b); - rt_timing_sum[index] += diff; -} - -void rt_timing_print_time_stats(FILE *file) -{ - struct rt_timing_stat *stats; - double total; - - for (stats = rt_timing_stat_defs; stats->name; ++stats) { - if (stats->index < 0) { - fprintf(file,"%s\n",stats->name); - continue; - } - - if (stats->totalindex >= 0) { - total = rt_timing_sum[stats->totalindex]; - fprintf(file,"%12lld usec %3.0f%% %s\n", - rt_timing_sum[stats->index], - (total != 0.0) ? rt_timing_sum[stats->index] / total * 100.0 : 0.0, - stats->name); - } - else { - fprintf(file,"%12lld usec %s\n", - rt_timing_sum[stats->index], - stats->name); - } - } -} - -/* - * 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: - */ diff --git a/src/vm/rt-timing.h b/src/vm/rt-timing.h deleted file mode 100644 index 432f656ee..000000000 --- a/src/vm/rt-timing.h +++ /dev/null @@ -1,140 +0,0 @@ -/* src/vm/rt-timing.h - POSIX real-time timing utilities - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Edwin Steiner - - Changes: - - $Id$ - -*/ - -#ifndef _RT_TIMING_H -#define _RT_TIMING_H - -#include "config.h" - -#if defined(ENABLE_RT_TIMING) - -#include "vm/types.h" - -#include - -#include "mm/memory.h" -#include "vm/global.h" - -#define RT_TIMING_GET_TIME(ts) \ - rt_timing_gettime(&(ts)); - -#define RT_TIMING_TIME_DIFF(a,b,index) \ - rt_timing_time_diff(&(a),&(b),(index)); - -#define RT_TIMING_JIT_CHECKS 0 -#define RT_TIMING_JIT_PARSE 1 -#define RT_TIMING_JIT_STACK 2 -#define RT_TIMING_JIT_TYPECHECK 3 -#define RT_TIMING_JIT_LOOP 4 -#define RT_TIMING_JIT_IFCONV 5 -#define RT_TIMING_JIT_ALLOC 6 -#define RT_TIMING_JIT_RPLPOINTS 7 -#define RT_TIMING_JIT_CODEGEN 8 -#define RT_TIMING_JIT_TOTAL 9 - -#define RT_TIMING_LINK_RESOLVE 10 -#define RT_TIMING_LINK_C_VFTBL 11 -#define RT_TIMING_LINK_ABSTRACT 12 -#define RT_TIMING_LINK_C_IFTBL 13 -#define RT_TIMING_LINK_F_VFTBL 14 -#define RT_TIMING_LINK_OFFSETS 15 -#define RT_TIMING_LINK_F_IFTBL 16 -#define RT_TIMING_LINK_FINALIZER 17 -#define RT_TIMING_LINK_EXCEPTS 18 -#define RT_TIMING_LINK_SUBCLASS 19 -#define RT_TIMING_LINK_TOTAL 20 - -#define RT_TIMING_LOAD_CHECKS 21 -#define RT_TIMING_LOAD_NDPOOL 22 -#define RT_TIMING_LOAD_CPOOL 23 -#define RT_TIMING_LOAD_SETUP 24 -#define RT_TIMING_LOAD_FIELDS 25 -#define RT_TIMING_LOAD_METHODS 26 -#define RT_TIMING_LOAD_CLASSREFS 27 -#define RT_TIMING_LOAD_DESCS 28 -#define RT_TIMING_LOAD_SETREFS 29 -#define RT_TIMING_LOAD_PARSEFDS 30 -#define RT_TIMING_LOAD_PARSEMDS 31 -#define RT_TIMING_LOAD_PARSECP 32 -#define RT_TIMING_LOAD_VERIFY 33 -#define RT_TIMING_LOAD_ATTRS 34 -#define RT_TIMING_LOAD_TOTAL 35 - -#define RT_TIMING_LOAD_BOOT_LOOKUP 36 -#define RT_TIMING_LOAD_BOOT_ARRAY 37 -#define RT_TIMING_LOAD_BOOT_SUCK 38 -#define RT_TIMING_LOAD_BOOT_LOAD 39 -#define RT_TIMING_LOAD_BOOT_CACHE 40 -#define RT_TIMING_LOAD_BOOT_TOTAL 41 - -#define RT_TIMING_LOAD_CL_LOOKUP 42 -#define RT_TIMING_LOAD_CL_PREPARE 43 -#define RT_TIMING_LOAD_CL_JAVA 44 -#define RT_TIMING_LOAD_CL_CACHE 45 - -#define RT_TIMING_NEW_OBJECT 46 -#define RT_TIMING_NEW_ARRAY 47 - -#define RT_TIMING_N 48 - -void rt_timing_gettime(struct timespec *ts); - -void rt_timing_time_diff(struct timespec *a,struct timespec *b,int index); - -long rt_timing_diff_usec(struct timespec *a,struct timespec *b); - -void rt_timing_print_time_stats(FILE *file); - -#else /* !defined(ENABLE_RT_TIMING) */ - -#define RT_TIMING_GET_TIME(ts) -#define RT_TIMING_TIME_DIFF(a,b,index) - -#endif /* defined(ENABLE_RT_TIMING) */ - -#endif /* _RT_TIMING_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: - */ diff --git a/src/vm/signal.c b/src/vm/signal.c index c8e5a31db..17279a70c 100644 --- a/src/vm/signal.c +++ b/src/vm/signal.c @@ -1,6 +1,6 @@ /* src/vm/signal.c - machine independent signal functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: signal.c 6256 2006-12-28 12:30:09Z twisti $ + $Id: signal.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -47,22 +43,38 @@ #include "vm/types.h" +#include "mm/memory.h" + +#include "native/jni.h" +#include "native/include/java_lang_Thread.h" + +#if defined(WITH_CLASSPATH_GNU) +# include "native/include/java_lang_VMThread.h" +#endif + #if defined(ENABLE_THREADS) # include "threads/native/threads.h" #endif -#include "mm/memory.h" +#include "vm/builtin.h" #include "vm/signallocal.h" -#include "vm/options.h" +#include "vm/stringlocal.h" #include "vm/vm.h" #include "vm/jit/stacktrace.h" +#include "vmcore/options.h" + + +/* global variables ***********************************************************/ + +#if defined(ENABLE_THREADS) +static threadobject *thread_signal; +#endif + /* function prototypes ********************************************************/ void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p); -void signal_handler_sigint(int sig, siginfo_t *siginfo, void *_p); -void signal_handler_sigquit(int sig, siginfo_t *siginfo, void *_p); /* signal_init ***************************************************************** @@ -76,6 +88,7 @@ void signal_init(void) #if !defined(__CYGWIN__) int pagesize; struct sigaction act; + sigset_t mask; /* mmap a memory page at address 0x0, so our hardware-exceptions work. */ @@ -91,7 +104,8 @@ void signal_init(void) (void) GCNEW(u1); #endif - /* install signal handlers we need to convert to exceptions */ + /* Install signal handlers for signals we want to catch in all + threads. */ sigemptyset(&act.sa_mask); @@ -99,7 +113,7 @@ void signal_init(void) # if defined(ENABLE_INTRP) if (!opt_intrp) { # endif - /* catch NullPointerException/StackOverFlowException */ + /* SIGSEGV handler */ act.sa_sigaction = md_signal_handler_sigsegv; act.sa_flags = SA_NODEFER | SA_SIGINFO; @@ -112,9 +126,9 @@ void signal_init(void) sigaction(SIGBUS, &act, NULL); #endif - /* catch ArithmeticException */ - #if SUPPORT_HARDWARE_DIVIDE_BY_ZERO + /* SIGFPE handler */ + act.sa_sigaction = md_signal_handler_sigfpe; act.sa_flags = SA_NODEFER | SA_SIGINFO; sigaction(SIGFPE, &act, NULL); @@ -125,93 +139,149 @@ void signal_init(void) #endif /* !defined(ENABLE_INTRP) */ #if defined(ENABLE_THREADS) - /* catch SIGHUP for threads_thread_interrupt */ + /* SIGHUP handler for threads_thread_interrupt */ act.sa_sigaction = signal_handler_sighup; act.sa_flags = 0; sigaction(SIGHUP, &act, NULL); #endif - /* catch SIGINT for exiting properly on -c */ - - act.sa_sigaction = signal_handler_sigint; - act.sa_flags = SA_NODEFER | SA_SIGINFO; - sigaction(SIGINT, &act, NULL); - -#if defined(ENABLE_THREADS) - /* catch SIGQUIT for thread dump */ - -# if !defined(__FREEBSD__) - act.sa_sigaction = signal_handler_sigquit; - act.sa_flags = SA_SIGINFO; - sigaction(SIGQUIT, &act, NULL); -# endif -#endif - #if defined(ENABLE_THREADS) && defined(ENABLE_PROFILING) - /* install signal handler for profiling sampling */ + /* SIGUSR2 handler for profiling sampling */ act.sa_sigaction = md_signal_handler_sigusr2; act.sa_flags = SA_SIGINFO; sigaction(SIGUSR2, &act, NULL); #endif + /* Block the following signals (SIGINT for -c, SIGQUIT for + -\). We enable them later in signal_thread, but only for + this thread. */ + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); +#if !defined(__FREEBSD__) + sigaddset(&mask, SIGQUIT); +#endif + sigprocmask(SIG_BLOCK, &mask, NULL); + #endif /* !defined(__CYGWIN__) */ } -/* signal_handler_sighup ******************************************************* +/* signal_thread ************************************************************ - This handler is required by threads_thread_interrupt and does - nothing. + This thread sets the signal mask to catch the user input signals + (SIGINT, SIGQUIT). We use such a thread, so we don't get the + signals on every single thread running. Especially, this makes + problems on slow machines. *******************************************************************************/ -#if defined(ENABLE_THREADS) -void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p) +static void signal_thread(void) { - /* do nothing */ -} + sigset_t mask; + int sig; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); +#if !defined(__FREEBSD__) + sigaddset(&mask, SIGQUIT); #endif + while (true) { + /* just wait for a signal */ -/* signal_handler_sigquit ****************************************************** + sigwait(&mask, &sig); - Handle for SIGQUIT (-\) which print a stacktrace for every - running thread. + switch (sig) { + case SIGINT: + /* exit the vm properly */ -*******************************************************************************/ + vm_exit(0); + break; -#if defined(ENABLE_THREADS) -void signal_handler_sigquit(int sig, siginfo_t *siginfo, void *_p) -{ - /* do thread dump */ + case SIGQUIT: + /* print a thread dump */ - threads_dump(); -} + threads_dump(); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + statistics_print_memory_usage(); #endif + break; + } + } + + /* this should not happen */ + + vm_abort("signal_thread: this thread should not exit!"); +} -/* signal_handler_sigint ******************************************************* +/* signal_start_thread ********************************************************* - Handler for SIGINT (-c) which shuts down CACAO properly with - Runtime.exit(I)V. + Starts the signal handler thread. *******************************************************************************/ -void signal_handler_sigint(int sig, siginfo_t *siginfo, void *_p) +bool signal_start_thread(void) { - /* if we are already in Runtime.exit(), just do it hardcore */ +#if defined(ENABLE_THREADS) +#if defined(WITH_CLASSPATH_GNU) + java_lang_VMThread *vmt; +#endif - if (vm_exiting) { - fprintf(stderr, "Caught SIGINT while already shutting down. Shutdown aborted...\n"); - exit(0); - } + /* create the finalizer object */ + + thread_signal = (threadobject *) builtin_new(class_java_lang_Thread); + + if (thread_signal == NULL) + return false; + +#if defined(WITH_CLASSPATH_GNU) + vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread); + + vmt->thread = (java_lang_Thread *) thread_signal; + + thread_signal->o.vmThread = vmt; +#endif + + thread_signal->flags = THREAD_FLAG_DAEMON; + + thread_signal->o.name = javastring_new_from_ascii("Signal Handler"); +#if defined(ENABLE_JAVASE) + thread_signal->o.daemon = true; +#endif + thread_signal->o.priority = 5; - /* exit the vm properly */ + /* actually start the finalizer thread */ - vm_exit(0); + threads_start_thread(thread_signal, signal_thread); + + /* everything's ok */ + + return true; +#else +#error FIX ME! +#endif +} + + +/* signal_handler_sighup ******************************************************* + + This handler is required by threads_thread_interrupt and does + nothing. + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) +void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p) +{ + /* do nothing */ } +#endif /* diff --git a/src/vm/signallocal.h b/src/vm/signallocal.h index f10a4dd10..0ee51976b 100644 --- a/src/vm/signallocal.h +++ b/src/vm/signallocal.h @@ -1,6 +1,6 @@ /* src/vm/signallocal.h - machine independent signal functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: signallocal.h 6172 2006-12-11 19:43:41Z twisti $ + $Id: signallocal.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -42,6 +38,7 @@ /* function prototypes ********************************************************/ void signal_init(void); +bool signal_start_thread(void); /* machine dependent signal handler */ diff --git a/src/vm/stackmap.c b/src/vm/stackmap.c deleted file mode 100644 index 93c1b70ab..000000000 --- a/src/vm/stackmap.c +++ /dev/null @@ -1,530 +0,0 @@ -/* src/vm/stackmap.c - class attribute StackMapTable - - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ - -*/ - - -#include "config.h" -#include "vm/types.h" - -#include "mm/memory.h" -#include "vm/class.h" -#include "vm/exceptions.h" -#include "vm/method.h" -#include "vm/options.h" -#include "vm/stackmap.h" - -#if defined(ENABLE_STATISTICS) -# include "vm/statistics.h" -#endif - -#include "vm/suck.h" - - -/* stackmap_get_verification_type_info ***************************************** - - union verification_type_info { - Top_variable_info; - Integer_variable_info; - Float_variable_info; - Long_variable_info; - Double_variable_info; - Null_variable_info; - UninitializedThis_variable_info; - Object_variable_info; - Uninitialized_variable_info; - } - - Top_variable_info { - u1 tag = ITEM_Top; // 0 - } - - Integer_variable_info { - u1 tag = ITEM_Integer; // 1 - } - - Float_variable_info { - u1 tag = ITEM_Float; // 2 - } - - Long_variable_info { - u1 tag = ITEM_Long; // 4 - } - - Double_variable_info { - u1 tag = ITEM_Double; // 3 - } - - Null_variable_info { - u1 tag = ITEM_Null; // 5 - } - - UninitializedThis_variable_info { - u1 tag = ITEM_UninitializedThis; // 6 - } - - Object_variable_info { - u1 tag = ITEM_Object; // 7 - u2 cpool_index; - } - - Uninitialized_variable_info { - u1 tag = ITEM_Uninitialized; // 8 - u2 offset; - } - -*******************************************************************************/ - -static bool stackmap_get_verification_type_info(classbuffer *cb, verification_type_info_t *verification_type_info) -{ - /* get verification type */ - - if (!suck_check_classbuffer_size(cb, 1)) - return false; - - verification_type_info->tag = suck_u1(cb); - - /* process the tag */ - - switch (verification_type_info->tag) { - case ITEM_Top: - case ITEM_Integer: - case ITEM_Float: - case ITEM_Long: - case ITEM_Double: - case ITEM_Null: - case ITEM_UninitializedThis: - break; - - case ITEM_Object: - /* get constant pool index */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - verification_type_info->Object_variable_info.cpool_index = suck_u2(cb); - break; - - case ITEM_Uninitialized: - /* get offset */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - verification_type_info->Uninitialized_variable_info.offset = suck_u2(cb); - break; - } - - return true; -} - - -/* stackmap_get_same_locals_1_stack_item_frame ********************************* - - same_locals_1_stack_item_frame { - u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 - verification_type_info stack[1]; - } - -*******************************************************************************/ - -static bool stackmap_get_same_locals_1_stack_item_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) -{ - same_locals_1_stack_item_frame_t *same_locals_1_stack_item_frame; - - /* for convenience */ - - same_locals_1_stack_item_frame = - &(stack_map_frame->same_locals_1_stack_item_frame); - - if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame->stack[0]))) - return false; - - return true; -} - - -/* stackmap_get_same_locals_1_stack_item_frame_extended ************************ - - same_locals_1_stack_item_frame_extended { - u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; // 247 - u2 offset_delta; - verification_type_info stack[1]; - } - -*******************************************************************************/ - -static bool stackmap_get_same_locals_1_stack_item_frame_extended(classbuffer *cb, stack_map_frame_t *stack_map_frame) -{ - same_locals_1_stack_item_frame_extended_t *same_locals_1_stack_item_frame_extended; - - /* for convenience */ - - same_locals_1_stack_item_frame_extended = - &(stack_map_frame->same_locals_1_stack_item_frame_extended); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - /* get offset delta */ - - same_locals_1_stack_item_frame_extended->offset_delta = suck_u2(cb); - - /* process stack */ - - if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame_extended->stack[0]))) - return false; - - return true; -} - - -/* stackmap_get_chop_frame ***************************************************** - - chop_frame { - u1 frame_type = CHOP_FRAME; // 248-250 - u2 offset_delta; - } - -*******************************************************************************/ - -static bool stackmap_get_chop_frame(classbuffer *cb, - stack_map_frame_t *stack_map_frame) -{ - chop_frame_t *chop_frame; - - /* for convenience */ - - chop_frame = &(stack_map_frame->chop_frame); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - /* get offset delta */ - - chop_frame->offset_delta = suck_u2(cb); - - return true; -} - - -/* stackmap_get_same_frame_extended ******************************************** - - same_frame_extended { - u1 frame_type = SAME_FRAME_EXTENDED; // 251 - u2 offset_delta; - } - -*******************************************************************************/ - -static bool stackmap_get_same_frame_extended(classbuffer *cb, - stack_map_frame_t *stack_map_frame) -{ - same_frame_extended_t *same_frame_extended; - - /* for convenience */ - - same_frame_extended = &(stack_map_frame->same_frame_extended); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - /* get offset delta */ - - same_frame_extended->offset_delta = suck_u2(cb); - - return true; -} - - -/* stackmap_get_append_frame *************************************************** - - append_frame { - u1 frame_type = APPEND_FRAME; // 252-254 - u2 offset_delta; - verification_type_info locals[frame_Type - 251]; - } - -*******************************************************************************/ - -static bool stackmap_get_append_frame(classbuffer *cb, - stack_map_frame_t *stack_map_frame) -{ - append_frame_t *append_frame; - s4 number_of_locals; - s4 i; - - /* for convenience */ - - append_frame = &(stack_map_frame->append_frame); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - /* get offset delta */ - - append_frame->offset_delta = suck_u2(cb); - - /* allocate locals array */ - - number_of_locals = append_frame->frame_type - 251; - - append_frame->locals = DMNEW(verification_type_info_t, number_of_locals); - - /* process all locals */ - - for (i = 0; i < number_of_locals; i++) - if (!stackmap_get_verification_type_info(cb, &(append_frame->locals[i]))) - return false; - - return true; -} - - -/* stackmap_get_full_frame ***************************************************** - - full_frame { - u1 frame_type = FULL_FRAME; - u2 offset_delta; - u2 number_of_locals; - verification_type_info locals[number_of_locals]; - u2 number_of_stack_items; - verification_type_info stack[number_of_stack_items]; - } - -*******************************************************************************/ - -static bool stackmap_get_full_frame(classbuffer *cb, - stack_map_frame_t *stack_map_frame) -{ - full_frame_t *full_frame; - s4 i; - - /* for convenience */ - - full_frame = &(stack_map_frame->full_frame); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 2 + 2)) - return false; - - /* get offset delta */ - - stack_map_frame->full_frame.offset_delta = suck_u2(cb); - - /* get number of locals */ - - full_frame->number_of_locals = suck_u2(cb); - - /* allocate locals array */ - - full_frame->locals = - DMNEW(verification_type_info_t, full_frame->number_of_locals); - - /* process all locals */ - - for (i = 0; i < full_frame->number_of_locals; i++) - if (!stackmap_get_verification_type_info(cb, &(full_frame->locals[i]))) - return false; - - /* get number of stack items */ - - if (!suck_check_classbuffer_size(cb, 2)) - return false; - - full_frame->number_of_stack_items = suck_u2(cb); - - /* allocate stack array */ - - full_frame->stack = - DMNEW(verification_type_info_t, full_frame->number_of_stack_items); - - /* process all stack items */ - - for (i = 0; i < full_frame->number_of_stack_items; i++) - if (!stackmap_get_verification_type_info(cb, &(full_frame->stack[i]))) - return false; - - return true; -} - - -/* stackmap_load_attribute_stackmaptable *************************************** - - stack_map { - u2 attribute_name_index; - u4 attribute_length; - u2 number_of_entries; - stack_map_frame entries[number_of_entries]; - } - - union stack_map_frame { - same_frame; - same_locals_1_stack_item_frame; - same_locals_1_stack_item_frame_extended; - chop_frame; - same_frame_extended; - append_frame; - full_frame; - } - - same_frame { - u1 frame_type = SAME; // 0-63 - } - -*******************************************************************************/ - -bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m) -{ - classinfo *c; - stack_map_t *stack_map; - s4 i; - u1 frame_type; - - /* get classinfo */ - - c = cb->class; - - /* allocate stack map structure */ - - stack_map = DNEW(stack_map_t); - - STATISTICS(size_stack_map += sizeof(stack_map_t)); - - /* check buffer size */ - - if (!suck_check_classbuffer_size(cb, 4 + 2)) - return false; - - /* attribute_length */ - - stack_map->attribute_length = suck_u4(cb); - - if (!suck_check_classbuffer_size(cb, stack_map->attribute_length)) - return false; - - /* get number of entries */ - - stack_map->number_of_entries = suck_u2(cb); - - /* process all entries */ - - stack_map->entries = DMNEW(stack_map_frame_t, stack_map->number_of_entries); - - for (i = 0; i < stack_map->number_of_entries; i++) { - /* get the frame type */ - - frame_type = suck_u1(cb); - - stack_map->entries[i].frame_type = frame_type; - - /* process frame */ - - if (frame_type <= FRAME_TYPE_SAME) { - /* same_frame */ - } - else if (frame_type <= FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM) { - /* same_locals_1_stack_item_frame */ - - if (!stackmap_get_same_locals_1_stack_item_frame(cb, &(stack_map->entries[i]))) - return false; - } - else if (frame_type <= FRAME_TYPE_RESERVED) { - /* reserved */ - - exceptions_throw_classformaterror(c, "reserved frame type"); - return false; - } - else if (frame_type == FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED) { - /* same_locals_1_stack_item_frame_extended */ - - if (!stackmap_get_same_locals_1_stack_item_frame_extended(cb, &(stack_map->entries[i]))) - return false; - } - else if (frame_type <= FRAME_TYPE_CHOP) { - /* chop_frame */ - - if (!stackmap_get_chop_frame(cb, &(stack_map->entries[i]))) - return false; - } - else if (frame_type == FRAME_TYPE_SAME_FRAME_EXTENDED) { - /* same_frame_extended */ - - if (!stackmap_get_same_frame_extended(cb, &(stack_map->entries[i]))) - return false; - } - else if (frame_type <= FRAME_TYPE_APPEND) { - /* append_frame */ - - if (!stackmap_get_append_frame(cb, &(stack_map->entries[i]))) - return false; - } - else if (frame_type == FRAME_TYPE_FULL_FRAME) { - /* full_frame */ - - if (!stackmap_get_full_frame(cb, &(stack_map->entries[i]))) - return false; - } - } - - /* store stack map in method structure */ - -#if 0 - /* currently not used */ - - m->stack_map = stack_map; -#endif - - return true; -} - - -/* - * 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: - */ diff --git a/src/vm/stackmap.h b/src/vm/stackmap.h deleted file mode 100644 index e86c7434b..000000000 --- a/src/vm/stackmap.h +++ /dev/null @@ -1,237 +0,0 @@ -/* src/vm/stackmap.h - class attribute StackMapTable - - Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ - -*/ - - -#ifndef _STACKMAP_H -#define _STACKMAP_H - -/* forward typedefs ***********************************************************/ - -typedef struct stack_map_t stack_map_t; -typedef union stack_map_frame_t stack_map_frame_t; -typedef struct same_locals_1_stack_item_frame_t same_locals_1_stack_item_frame_t; -typedef struct same_locals_1_stack_item_frame_extended_t same_locals_1_stack_item_frame_extended_t; -typedef struct chop_frame_t chop_frame_t; -typedef struct same_frame_extended_t same_frame_extended_t; -typedef struct append_frame_t append_frame_t; -typedef struct full_frame_t full_frame_t; - -typedef union verification_type_info_t verification_type_info_t; -typedef struct Top_variable_info_t Top_variable_info_t; -typedef struct Integer_variable_info_t Integer_variable_info_t; -typedef struct Float_variable_info_t Float_variable_info_t; -typedef struct Long_variable_info_t Long_variable_info_t; -typedef struct Double_variable_info_t Double_variable_info_t; -typedef struct Null_variable_info_t Null_variable_info_t; -typedef struct UninitializedThis_variable_info_t UninitializedThis_variable_info_t; -typedef struct Object_variable_info_t Object_variable_info_t; -typedef struct Uninitialized_variable_info_t Uninitialized_variable_info_t; - - -#include "config.h" -#include "vm/types.h" - -#include "vm/global.h" -#include "vm/loader.h" -#include "vm/method.h" - - -/* verification_type_info *****************************************************/ - -#define ITEM_Top 0 -#define ITEM_Integer 1 -#define ITEM_Float 2 -#define ITEM_Double 3 -#define ITEM_Long 4 -#define ITEM_Null 5 -#define ITEM_UninitializedThis 6 -#define ITEM_Object 7 -#define ITEM_Uninitialized 8 - -struct Top_variable_info_t { - u1 tag; -}; - -struct Integer_variable_info_t { - u1 tag; -}; - -struct Float_variable_info_t { - u1 tag; -}; - -struct Long_variable_info_t { - u1 tag; -}; - -struct Double_variable_info_t { - u1 tag; -}; - -struct Null_variable_info_t { - u1 tag; -}; - -struct UninitializedThis_variable_info_t { - u1 tag; -}; - -struct Object_variable_info_t { - u1 tag; - u2 cpool_index; -}; - -struct Uninitialized_variable_info_t { - u1 tag; - u2 offset; -}; - -union verification_type_info_t { - u1 tag; - Top_variable_info_t Top_variable_info; - Integer_variable_info_t Integer_variable_info; - Float_variable_info_t Float_variable_info; - Long_variable_info_t Long_variable_info; - Double_variable_info_t Double_variable_info; - Null_variable_info_t Null_variable_info; - UninitializedThis_variable_info_t UninitializedThis_variable_info; - Object_variable_info_t Object_variable_info; - Uninitialized_variable_info_t Uninitialized_variable_info; -}; - - -/* stack_map_t ****************************************************************/ - -struct stack_map_t { - u2 attribute_name_index; - u4 attribute_length; - u2 number_of_entries; - stack_map_frame_t *entries; -}; - - -/* same_locals_1_stack_item_frame_t *******************************************/ - -struct same_locals_1_stack_item_frame_t { - u1 frame_type; - verification_type_info_t stack[1]; -}; - - -/* same_locals_1_stack_item_frame_extended_t **********************************/ - -struct same_locals_1_stack_item_frame_extended_t { - u1 frame_type; - u2 offset_delta; - verification_type_info_t stack[1]; -}; - - -/* chop_frame_t ***************************************************************/ - -struct chop_frame_t { - u1 frame_type; - u2 offset_delta; -}; - - -/* same_frame_extended_t ******************************************************/ - -struct same_frame_extended_t { - u1 frame_type; - u2 offset_delta; -}; - - -/* append_frame_t *************************************************************/ - -struct append_frame_t { - u1 frame_type; - u2 offset_delta; - verification_type_info_t *locals; -}; - - -/* full_frame_t ***************************************************************/ - -struct full_frame_t { - u1 frame_type; - u2 offset_delta; - u2 number_of_locals; - verification_type_info_t *locals; - u2 number_of_stack_items; - verification_type_info_t *stack; -}; - - -/* stack_map_frame_t **********************************************************/ - -#define FRAME_TYPE_SAME 63 /* 0-63 */ -#define FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM 127 /* 0-127 */ -#define FRAME_TYPE_RESERVED 246 /* 128-246 */ -#define FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED 247 /* 247 */ -#define FRAME_TYPE_CHOP 250 /* 248-250 */ -#define FRAME_TYPE_SAME_FRAME_EXTENDED 251 /* 251 */ -#define FRAME_TYPE_APPEND 254 /* 252-254 */ -#define FRAME_TYPE_FULL_FRAME 255 /* 255 */ - -union stack_map_frame_t { - u1 frame_type; - same_locals_1_stack_item_frame_t same_locals_1_stack_item_frame; - same_locals_1_stack_item_frame_extended_t same_locals_1_stack_item_frame_extended; - chop_frame_t chop_frame; - same_frame_extended_t same_frame_extended; - append_frame_t append_frame; - full_frame_t full_frame; -}; - - -/* function prototypes ********************************************************/ - -bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m); - -#endif /* _STACKMAP_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: - */ diff --git a/src/vm/statistics.c b/src/vm/statistics.c deleted file mode 100644 index 0f142ea3f..000000000 --- a/src/vm/statistics.c +++ /dev/null @@ -1,632 +0,0 @@ -/* src/vm/statistics.c - global varables for statistics - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: statistics.c 6216 2006-12-18 18:21:37Z twisti $ - -*/ - - -#include "config.h" - -#include -#include -#include - -#include "vm/types.h" - -#include "toolbox/logging.h" -#include "vm/global.h" -#include "vm/options.h" -#include "vm/statistics.h" - - -/* global variables ***********************************************************/ - -static s8 loadingtime = 0; /* accumulated loading time */ -static s8 loadingstarttime = 0; -static s8 loadingstoptime = 0; -static s4 loadingtime_recursion = 0; - -static s8 compilingtime = 0; /* accumulated compile time */ -static s8 compilingstarttime = 0; -static s8 compilingstoptime = 0; -static s4 compilingtime_recursion = 0; - -s4 codememusage = 0; -s4 maxcodememusage = 0; - -s4 memoryusage = 0; -s4 maxmemusage = 0; - -s4 maxdumpsize = 0; - -s4 globalallocateddumpsize = 0; -s4 globaluseddumpsize = 0; - - -/* variables for measurements *************************************************/ - -s4 size_classinfo = 0; -s4 size_fieldinfo = 0; -s4 size_methodinfo = 0; -s4 size_codeinfo = 0; - -s4 size_stack_map = 0; - -int count_const_pool_len = 0; -int count_classref_len = 0; -int count_parsed_desc_len = 0; -int count_vftbl_len = 0; -int count_all_methods = 0; -int count_methods_marked_used = 0; /* RTA */ - -int count_vmcode_len = 0; -int count_extable_len = 0; -int count_class_loads = 0; -int count_class_inits = 0; - -int count_utf_len = 0; /* size of utf hash */ -int count_utf_new = 0; /* calls of utf_new */ -int count_utf_new_found = 0; /* calls of utf_new with fast return */ - -int count_locals_conflicts = 0; /* register allocator statistics */ -int count_locals_spilled = 0; -int count_locals_register = 0; -int count_ss_spilled = 0; -int count_ss_register = 0; -int count_methods_allocated_by_lsra = 0; -int count_mem_move_bb = 0; -int count_interface_size = 0; -int count_argument_mem_ss = 0; -int count_argument_reg_ss = 0; -int count_method_in_register = 0; -int count_mov_reg_reg = 0; -int count_mov_mem_reg = 0; -int count_mov_reg_mem = 0; -int count_mov_mem_mem = 0; - -int count_jit_calls = 0; -int count_methods = 0; -int count_spills = 0; -int count_spills_read = 0; -int count_pcmd_activ = 0; -int count_pcmd_drop = 0; -int count_pcmd_zero = 0; -int count_pcmd_const_store = 0; -int count_pcmd_const_alu = 0; -int count_pcmd_const_bra = 0; -int count_pcmd_load = 0; -int count_pcmd_move = 0; -int count_load_instruction = 0; -int count_pcmd_store = 0; -int count_pcmd_store_comb = 0; -int count_dup_instruction = 0; -int count_pcmd_op = 0; -int count_pcmd_mem = 0; -int count_pcmd_met = 0; -int count_pcmd_bra = 0; -int count_pcmd_table = 0; -int count_pcmd_return = 0; -int count_pcmd_returnx = 0; -int count_check_null = 0; -int count_check_bound = 0; -int count_max_basic_blocks = 0; -int count_basic_blocks = 0; -int count_javainstr = 0; -int count_max_javainstr = 0; -int count_javacodesize = 0; -int count_javaexcsize = 0; -int count_calls = 0; -int count_tryblocks = 0; -int count_code_len = 0; -int count_data_len = 0; -int count_cstub_len = 0; -int count_nstub_len = 0; -int count_max_new_stack = 0; -int count_upper_bound_new_stack = 0; - -s4 count_branches_resolved = 0; -s4 count_branches_unresolved = 0; - -u8 count_native_function_calls=0; -u8 count_jni_callXmethod_calls=0; -u8 count_jni_calls=0; - - -static int count_block_stack_init[11] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0 -}; -int *count_block_stack = count_block_stack_init; -static int count_analyse_iterations_init[5] = { - 0, 0, 0, 0, 0 -}; -int *count_analyse_iterations = count_analyse_iterations_init; -static int count_method_bb_distribution_init[9] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0 -}; -int *count_method_bb_distribution = count_method_bb_distribution_init; -static int count_block_size_distribution_init[18] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0 -}; -int *count_block_size_distribution = count_block_size_distribution_init; -static int count_store_length_init[21] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0 -}; -int *count_store_length = count_store_length_init; -static int count_store_depth_init[11] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0 -}; -int *count_store_depth = count_store_depth_init; - - -/* instruction scheduler statistics *******************************************/ - -s4 count_schedule_basic_blocks = 0; -s4 count_schedule_nodes = 0; -s4 count_schedule_leaders = 0; -s4 count_schedule_max_leaders = 0; -s4 count_schedule_critical_path = 0; - - -/* nativeinvokation *********************************************************** - - increments the native invokation count by one - -*******************************************************************************/ - -void nativeinvokation(void) -{ - /* XXX do locking here */ - count_native_function_calls++; -} - - -/* jnicallXmethodinvokation *************************************************** - - increments the jni CallXMethod invokation count by one - -*******************************************************************************/ - -void jnicallXmethodnvokation(void) -{ - /* XXX do locking here */ - count_jni_callXmethod_calls++; -} - - -/* jniinvokation ************************************************************* - - increments the jni overall invokation count by one - -*******************************************************************************/ - -void jniinvokation(void) -{ - /* XXX do locking here */ - count_jni_calls++; -} - - -/* getcputime *********************************** ****************************** - - Returns the used CPU time in microseconds - -*******************************************************************************/ - -s8 getcputime(void) -{ - struct rusage ru; - int sec, usec; - - getrusage(RUSAGE_SELF, &ru); - sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec; - usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec; - - return sec * 1000000 + usec; -} - - -/* loadingtime_stop ************************************************************ - - XXX - -*******************************************************************************/ - -void loadingtime_start(void) -{ - loadingtime_recursion++; - - if (loadingtime_recursion == 1) - loadingstarttime = getcputime(); -} - - -/* loadingtime_stop ************************************************************ - - XXX - -*******************************************************************************/ - -void loadingtime_stop(void) -{ - if (loadingtime_recursion == 1) { - loadingstoptime = getcputime(); - loadingtime += (loadingstoptime - loadingstarttime); - } - - loadingtime_recursion--; -} - - -/* compilingtime_stop ********************************************************** - - XXX - -*******************************************************************************/ - -void compilingtime_start(void) -{ - compilingtime_recursion++; - - if (compilingtime_recursion == 1) - compilingstarttime = getcputime(); -} - - -/* compilingtime_stop ********************************************************** - - XXX - -*******************************************************************************/ - -void compilingtime_stop(void) -{ - if (compilingtime_recursion == 1) { - compilingstoptime = getcputime(); - compilingtime += (compilingstoptime - compilingstarttime); - } - - compilingtime_recursion--; -} - - -/* print_times ***************************************************************** - - Prints a summary of CPU time usage. - -*******************************************************************************/ - -void print_times(void) -{ - s8 totaltime; - s8 runtime; - - totaltime = getcputime(); - runtime = totaltime - loadingtime - compilingtime; - -#if SIZEOF_VOID_P == 8 - dolog("Time for loading classes: %6ld ms", loadingtime / 1000); - dolog("Time for compiling code: %6ld ms", compilingtime / 1000); - dolog("Time for running program: %6ld ms", runtime / 1000); - dolog("Total time: %6ld ms", totaltime / 1000); -#else - dolog("Time for loading classes: %6lld ms", loadingtime / 1000); - dolog("Time for compiling code: %6lld ms", compilingtime / 1000); - dolog("Time for running program: %6lld ms", runtime / 1000); - dolog("Total time: %6lld ms", totaltime / 1000); -#endif -} - - -/* print_stats ***************************************************************** - - outputs detailed compiler statistics - -*******************************************************************************/ - -void print_stats(void) -{ - s4 i; - float f; - s4 sum; - - - dolog("Number of JIT compiler calls: %6d", count_jit_calls); - dolog("Number of compiled methods: %6d", count_methods); - - dolog("Number of compiled basic blocks: %6d", - count_basic_blocks); - dolog("Number of max. basic blocks per method: %6d", - count_max_basic_blocks); - - dolog("Number of compiled JavaVM instructions: %6d", - count_javainstr); - dolog("Number of max. JavaVM instructions per method: %6d", - count_max_javainstr); - dolog("Size of compiled JavaVM instructions: %6d(%d)", - count_javacodesize, count_javacodesize - count_methods * 18); - - dolog("Size of compiled Exception Tables: %d", count_javaexcsize); - dolog("Number of Machine-Instructions: %d", count_code_len >> 2); - dolog("Number of Spills (write to memory): %d", count_spills); - dolog("Number of Spills (read from memory): %d", count_spills_read); - dolog("Number of Activ Pseudocommands: %6d", count_pcmd_activ); - dolog("Number of Drop Pseudocommands: %6d", count_pcmd_drop); - dolog("Number of Const Pseudocommands: %6d (zero:%5d)", - count_pcmd_load, count_pcmd_zero); - dolog("Number of ConstAlu Pseudocommands: %6d (cmp: %5d, store:%5d)", - count_pcmd_const_alu, count_pcmd_const_bra, count_pcmd_const_store); - dolog("Number of Move Pseudocommands: %6d", count_pcmd_move); - dolog("Number of Load Pseudocommands: %6d", count_load_instruction); - dolog("Number of Store Pseudocommands: %6d (combined: %5d)", - count_pcmd_store, count_pcmd_store - count_pcmd_store_comb); - dolog("Number of OP Pseudocommands: %6d", count_pcmd_op); - dolog("Number of DUP Pseudocommands: %6d", count_dup_instruction); - dolog("Number of Mem Pseudocommands: %6d", count_pcmd_mem); - dolog("Number of Method Pseudocommands: %6d", count_pcmd_met); - dolog("Number of Branch Pseudocommands: %6d (rets:%5d, Xrets: %5d)", - count_pcmd_bra, count_pcmd_return, count_pcmd_returnx); - log_println(" resolved branches: %6d", count_branches_resolved); - log_println(" unresolved branches: %6d", count_branches_unresolved); - dolog("Number of Table Pseudocommands: %6d", count_pcmd_table); - dolog("Number of Useful Pseudocommands: %6d", count_pcmd_table + - count_pcmd_bra + count_pcmd_load + count_pcmd_mem + count_pcmd_op); - dolog("Number of Null Pointer Checks: %6d", count_check_null); - dolog("Number of Array Bound Checks: %6d", count_check_bound); - dolog("Number of Try-Blocks: %d", count_tryblocks); - dolog("Maximal count of stack elements: %d", count_max_new_stack); - dolog("Upper bound of max stack elements: %d", count_upper_bound_new_stack); - dolog("Distribution of stack sizes at block boundary"); - dolog(" 0 1 2 3 4 5 6 7 8 9 >=10"); - dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", - count_block_stack[0], count_block_stack[1], count_block_stack[2], - count_block_stack[3], count_block_stack[4], count_block_stack[5], - count_block_stack[6], count_block_stack[7], count_block_stack[8], - count_block_stack[9], count_block_stack[10]); - dolog("Distribution of store stack depth"); - dolog(" 0 1 2 3 4 5 6 7 8 9 >=10"); - dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", - count_store_depth[0], count_store_depth[1], count_store_depth[2], - count_store_depth[3], count_store_depth[4], count_store_depth[5], - count_store_depth[6], count_store_depth[7], count_store_depth[8], - count_store_depth[9], count_store_depth[10]); - dolog("Distribution of store creator chains first part"); - dolog(" 0 1 2 3 4 5 6 7 8 9"); - dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", - count_store_length[0], count_store_length[1], count_store_length[2], - count_store_length[3], count_store_length[4], count_store_length[5], - count_store_length[6], count_store_length[7], count_store_length[8], - count_store_length[9]); - dolog("Distribution of store creator chains second part"); - dolog(" 10 11 12 13 14 15 16 17 18 19 >=20"); - dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", - count_store_length[10], count_store_length[11], - count_store_length[12], count_store_length[13], - count_store_length[14], count_store_length[15], - count_store_length[16], count_store_length[17], - count_store_length[18], count_store_length[19], - count_store_length[20]); - dolog("Distribution of analysis iterations"); - dolog(" 1 2 3 4 >=5"); - dolog("%6d%6d%6d%6d%6d", - count_analyse_iterations[0], count_analyse_iterations[1], - count_analyse_iterations[2], count_analyse_iterations[3], - count_analyse_iterations[4]); - - - /* Distribution of basic blocks per method ********************************/ - - log_println("Distribution of basic blocks per method:"); - log_println(" <=5 <=10 <=15 <=20 <=30 <=40 <=50 <=75 >75"); - - log_start(); - for (i = 0; i <= 8; i++) - log_print("%6d", count_method_bb_distribution[i]); - log_finish(); - - /* print ratio */ - - f = (float) count_methods; - - log_start(); - for (i = 0; i <= 8; i++) - log_print("%6.2f", (float) count_method_bb_distribution[i] / f); - log_finish(); - - /* print cumulated ratio */ - - log_start(); - for (i = 0, sum = 0; i <= 8; i++) { - sum += count_method_bb_distribution[i]; - log_print("%6.2f", (float) sum / f); - } - log_finish(); - - - /* Distribution of basic block sizes **************************************/ - - log_println("Distribution of basic block sizes:"); - log_println(" 0 1 2 3 4 5 6 7 8 9 <13 <15 <17 <19 <21 <26 <31 >30"); - - /* print block sizes */ - - log_start(); - for (i = 0; i <= 17; i++) - log_print("%6d", count_block_size_distribution[i]); - log_finish(); - - /* print ratio */ - - f = (float) count_basic_blocks; - - log_start(); - for (i = 0; i <= 17; i++) - log_print("%6.2f", (float) count_block_size_distribution[i] / f); - log_finish(); - - /* print cumulated ratio */ - - log_start(); - for (i = 0, sum = 0; i <= 17; i++) { - sum += count_block_size_distribution[i]; - log_print("%6.2f", (float) sum / f); - } - log_finish(); - - log_println("Size of Code Area: %10.3f kB", (float) count_code_len / 1024); - log_println("Size of Data Area: %10.3f kB", (float) count_data_len / 1024); - - log_println("Size of classinfo (%3d B): %10.3f kB", sizeof(classinfo), (float) size_classinfo / 1024); - log_println("Size of fieldinfo (%3d B): %10.3f kB", sizeof(fieldinfo), (float) size_fieldinfo / 1024); - log_println("Size of methodinfo (%3d B): %10.3f kB", sizeof(methodinfo), (float) size_methodinfo / 1024); - log_println("Size of codeinfo (%3d B): %10.3f kB", sizeof(codeinfo), (float) size_codeinfo / 1024); - - log_println("Size of Const Pool: %10.3f kB", (float) (count_const_pool_len + count_utf_len) / 1024); - log_println("Size of Class refs: %10.3f kB", (float) count_classref_len / 1024); - log_println("Size of descriptors: %10.3f kB", (float) count_parsed_desc_len / 1024); - log_println("Size of vftbl: %10.3f kB", (float) count_vftbl_len / 1024); - log_println("Size of compiler stubs: %10.3f kB", (float) count_cstub_len / 1024); - log_println("Size of native stubs: %10.3f kB", (float) count_nstub_len / 1024); - log_println("Size of utf: %10.3f kB", (float) count_utf_len / 1024); - log_println("Size of VMCode: %10.3f kB", (float) count_vmcode_len / 1024); - log_println("Size of exception tables: %10.3f kB", (float) count_extable_len / 1024); - log_println("size of stack map: %10.3f kb\n", (float) size_stack_map / 1024); - - dolog("Number of class loads: %6d", count_class_loads); - dolog("Number of class inits: %6d", count_class_inits); - dolog("Number of loaded Methods: %6d\n", count_all_methods); - - dolog("Calls of utf_new: %6d", count_utf_new); - dolog("Calls of utf_new (element found): %6d\n", count_utf_new_found); - - - /* LSRA statistics ********************************************************/ - - dolog("Moves reg -> reg: %6d", count_mov_reg_reg); - dolog("Moves mem -> reg: %6d", count_mov_mem_reg); - dolog("Moves reg -> mem: %6d", count_mov_reg_mem); - dolog("Moves mem -> mem: %6d", count_mov_mem_mem); - - dolog("Methods allocated by LSRA: %6d", - count_methods_allocated_by_lsra); - dolog("Conflicts between local Variables: %6d", count_locals_conflicts); - dolog("Local Variables held in Memory: %6d", count_locals_spilled); - dolog("Local Variables held in Registers: %6d", count_locals_register); - dolog("Stackslots held in Memory: %6d", count_ss_spilled); - dolog("Stackslots held in Registers: %6d", count_ss_register); - dolog("Memory moves at BB Boundaries: %6d", count_mem_move_bb); - dolog("Number of interface slots: %6d\n", count_interface_size); - dolog("Number of Argument stack slots in register: %6d", - count_argument_reg_ss); - dolog("Number of Argument stack slots in memory: %6d\n", - count_argument_mem_ss); - dolog("Number of Methods kept in registers: %6d\n", - count_method_in_register); - - - /* instruction scheduler statistics ***************************************/ - -#if defined(USE_SCHEDULER) - dolog("Instruction scheduler statistics:"); - dolog("Number of basic blocks: %7d", count_schedule_basic_blocks); - dolog("Number of nodes: %7d", count_schedule_nodes); - dolog("Number of leaders nodes: %7d", count_schedule_leaders); - dolog("Number of max. leaders nodes: %7d", count_schedule_max_leaders); - dolog("Length of critical path: %7d\n", count_schedule_critical_path); -#endif - - - /* call statistics ********************************************************/ - - dolog("Function call statistics:"); - dolog("Number of native function invokations: %ld", - count_native_function_calls); - dolog("Number of jni->CallXMethod function invokations: %ld", - count_jni_callXmethod_calls); - dolog("Overall number of jni invokations: %ld", - count_jni_calls); - - - /* now print other statistics ********************************************/ - -#if defined(ENABLE_INTRP) - print_dynamic_super_statistics(); -#endif -} - - -/* mem_usagelog **************************************************************** - - prints some memory related infos - -*******************************************************************************/ - -void mem_usagelog(bool givewarnings) -{ - if ((memoryusage != 0) && givewarnings) { - dolog("Allocated memory not returned: %9d", (s4) memoryusage); - } - - if ((globalallocateddumpsize != 0) && givewarnings) { - dolog("Dump memory not returned: %9d", - (s4) globalallocateddumpsize); - } - - dolog("Code - max. memory usage: %9d kB", - (s4) ((maxcodememusage + 1023) / 1024)); - dolog("Random - max. memory usage: %9d kB", - (s4) ((maxmemusage + 1023) / 1024)); - dolog("Dump - max. memory usage: %9d kB", - (s4) ((maxdumpsize + 1023) / 1024)); -} - - -/* - * 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: - */ diff --git a/src/vm/statistics.h b/src/vm/statistics.h deleted file mode 100644 index a19e78862..000000000 --- a/src/vm/statistics.h +++ /dev/null @@ -1,240 +0,0 @@ -/* src/vm/statistics.h - exports global varables for statistics - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: statistics.h 6216 2006-12-18 18:21:37Z twisti $ - -*/ - - -#ifndef _STATISTICS_H -#define _STATISTICS_H - -#include "config.h" -#include "vm/types.h" - -#include "vm/global.h" - - -/* statistic macros ***********************************************************/ - -#if defined(ENABLE_STATISTICS) -#define STATISTICS(x) \ - do { \ - if (opt_stat) { \ - x; \ - } \ - } while (0) -#else -#define STATISTICS(x) /* nothing */ -#endif - -/* in_ inline statistics */ - -#define IN_MAX 9 -#define IN_UNIQUEVIRT 0x0000 -#define IN_UNIQUE_INTERFACE 0x0001 -#define IN_OUTSIDERS 0x0004 -#define IN_MAXDEPTH 0x0008 -#define IN_MAXCODE 0x0010 -#define IN_JCODELENGTH 0x0020 -#define IN_EXCEPTION 0x0040 -#define IN_NOT_UNIQUE_VIRT 0x0080 -#define IN_NOT_UNIQUE_INTERFACE 0x0100 - -#define N_UNIQUEVIRT 0 -#define N_UNIQUE_INTERFACE 1 -#define N_OUTSIDERS 2 -#define N_MAXDEPTH 3 -#define N_MAXCODE 4 -#define N_JCODELENGTH 5 -#define N_EXCEPTION 6 -#define N_NOT_UNIQUE_VIRT 7 -#define N_NOT_UNIQUE_INTERFACE 8 - - -/* global variables ***********************************************************/ - -extern s4 codememusage; -extern s4 maxcodememusage; - -extern s4 memoryusage; -extern s4 maxmemusage; - -extern s4 maxdumpsize; - -extern s4 globalallocateddumpsize; -extern s4 globaluseddumpsize; - - -/* variables for measurements *************************************************/ - -extern s4 size_classinfo; -extern s4 size_fieldinfo; -extern s4 size_methodinfo; -extern s4 size_codeinfo; - -extern s4 size_stack_map; - -extern int count_const_pool_len; -extern int count_classref_len; -extern int count_parsed_desc_len; -extern int count_vftbl_len; -extern int count_all_methods; -extern int count_methods_marked_used; /*RTA*/ -extern int count_vmcode_len; -extern int count_extable_len; -extern int count_class_loads; -extern int count_class_inits; - -extern int count_utf_len; /* size of utf hash */ -extern int count_utf_new; -extern int count_utf_new_found; - -extern int count_locals_conflicts; -extern int count_locals_spilled; -extern int count_locals_register; -extern int count_ss_spilled; -extern int count_ss_register; -extern int count_methods_allocated_by_lsra; -extern int count_mem_move_bb; -extern int count_interface_size; -extern int count_argument_mem_ss; -extern int count_argument_reg_ss; -extern int count_method_in_register; -extern int count_mov_reg_reg; -extern int count_mov_mem_reg; -extern int count_mov_reg_mem; -extern int count_mov_mem_mem; - -extern int count_jit_calls; -extern int count_methods; -extern int count_spills; -extern int count_spills_read; -extern int count_pcmd_activ; -extern int count_pcmd_drop; -extern int count_pcmd_zero; -extern int count_pcmd_const_store; -extern int count_pcmd_const_alu; -extern int count_pcmd_const_bra; -extern int count_pcmd_load; -extern int count_pcmd_move; -extern int count_load_instruction; -extern int count_pcmd_store; -extern int count_pcmd_store_comb; -extern int count_dup_instruction; -extern int count_pcmd_op; -extern int count_pcmd_mem; -extern int count_pcmd_met; -extern int count_pcmd_bra; -extern int count_pcmd_table; -extern int count_pcmd_return; -extern int count_pcmd_returnx; -extern int count_check_null; -extern int count_check_bound; -extern int count_max_basic_blocks; -extern int count_basic_blocks; -extern int count_max_javainstr; -extern int count_javainstr; -extern int count_javacodesize; -extern int count_javaexcsize; -extern int count_calls; -extern int count_tryblocks; -extern int count_code_len; -extern int count_data_len; -extern int count_cstub_len; -extern int count_nstub_len; -extern int count_max_new_stack; -extern int count_upper_bound_new_stack; - -extern s4 count_branches_resolved; -extern s4 count_branches_unresolved; - -extern int *count_block_stack; -extern int *count_analyse_iterations; -extern int *count_method_bb_distribution; -extern int *count_block_size_distribution; -extern int *count_store_length; -extern int *count_store_depth; - /* in_ inline statistics */ -extern int count_in; -extern int count_in_uniqVirt; -extern int count_in_uniqIntf; -extern int count_in_rejected; -extern int count_in_rejected_mult; -extern int count_in_outsiders; -extern int count_in_uniqueVirt_not_inlined; -extern int count_in_uniqueInterface_not_inlined; -extern int count_in_maxDepth; -extern int count_in_maxMethods; - -extern u2 count_in_not [512]; - -/* instruction scheduler statistics *******************************************/ - -extern s4 count_schedule_basic_blocks; -extern s4 count_schedule_nodes; -extern s4 count_schedule_leaders; -extern s4 count_schedule_max_leaders; -extern s4 count_schedule_critical_path; - - -/* function prototypes ********************************************************/ - -s8 getcputime(void); - -void loadingtime_start(void); -void loadingtime_stop(void); -void compilingtime_start(void); -void compilingtime_stop(void); - -void print_times(void); -void print_stats(void); - -void mem_usagelog(bool givewarnings); - - -void nativeinvokation(void); -void compiledinvokation(void); -void jnicallXmethodnvokation(void); -void jniinvokation(void); - -#endif /* _STATISTICS_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: - */ diff --git a/src/vm/string.c b/src/vm/string.c index 9c26afa89..d01801818 100644 --- a/src/vm/string.c +++ b/src/vm/string.c @@ -1,6 +1,6 @@ /* src/vm/string.c - java.lang.String related functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,16 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Roman Obermaisser - Andreas Krall - - Changes: Christian Thalinger - Edwin Steiner - - $Id: string.c 5823 2006-10-24 23:24:19Z edwin $ + $Id: string.c 7246 2007-01-29 18:49:05Z twisti $ */ @@ -55,10 +46,10 @@ #include "vm/builtin.h" #include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" -#include "vm/utf8.h" + +#include "vmcore/options.h" +#include "vmcore/utf8.h" /* global variables ***********************************************************/ @@ -74,134 +65,6 @@ static java_objectheader *lock_hashtable_string; #endif -/* global string definitions **************************************************/ - -/* exception/error super class */ - -const char *string_java_lang_Throwable = - "java/lang/Throwable"; - -const char *string_java_lang_VMThrowable = - "java/lang/VMThrowable"; - - -/* specify some exception strings for code generation */ - -const char *string_java_lang_ArithmeticException = - "java/lang/ArithmeticException"; - -const char *string_java_lang_ArithmeticException_message = - "/ by zero"; - -const char *string_java_lang_ArrayIndexOutOfBoundsException = - "java/lang/ArrayIndexOutOfBoundsException"; - -const char *string_java_lang_ArrayStoreException = - "java/lang/ArrayStoreException"; - -const char *string_java_lang_ClassCastException = - "java/lang/ClassCastException"; - -const char *string_java_lang_ClassNotFoundException = - "java/lang/ClassNotFoundException"; - -const char *string_java_lang_CloneNotSupportedException = - "java/lang/CloneNotSupportedException"; - -const char *string_java_lang_Exception = - "java/lang/Exception"; - -const char *string_java_lang_IllegalAccessException = - "java/lang/IllegalAccessException"; - -const char *string_java_lang_IllegalArgumentException = - "java/lang/IllegalArgumentException"; - -const char *string_java_lang_IllegalMonitorStateException = - "java/lang/IllegalMonitorStateException"; - -const char *string_java_lang_IndexOutOfBoundsException = - "java/lang/IndexOutOfBoundsException"; - -const char *string_java_lang_InstantiationException = - "java/lang/InstantiationException"; - -const char *string_java_lang_InterruptedException = - "java/lang/InterruptedException"; - -const char *string_java_lang_NegativeArraySizeException = - "java/lang/NegativeArraySizeException"; - -const char *string_java_lang_NoSuchFieldException = - "java/lang/NoSuchFieldException"; - -const char *string_java_lang_NoSuchMethodException = - "java/lang/NoSuchMethodException"; - -const char *string_java_lang_NullPointerException = - "java/lang/NullPointerException"; - -const char *string_java_lang_StringIndexOutOfBoundsException = - "java/lang/StringIndexOutOfBoundsException"; - -const char *string_java_lang_reflect_InvocationTargetException = - "java/lang/reflect/InvocationTargetException"; - - -/* specify some error strings for code generation */ - -const char *string_java_lang_AbstractMethodError = - "java/lang/AbstractMethodError"; - -const char *string_java_lang_ClassCircularityError = - "java/lang/ClassCircularityError"; - -const char *string_java_lang_ClassFormatError = - "java/lang/ClassFormatError"; - -const char *string_java_lang_Error = - "java/lang/Error"; - -const char *string_java_lang_ExceptionInInitializerError = - "java/lang/ExceptionInInitializerError"; - -const char *string_java_lang_IncompatibleClassChangeError = - "java/lang/IncompatibleClassChangeError"; - -const char *string_java_lang_InstantiationError = - "java/lang/InstantiationError"; - -const char *string_java_lang_InternalError = - "java/lang/InternalError"; - -const char *string_java_lang_LinkageError = - "java/lang/LinkageError"; - -const char *string_java_lang_NoClassDefFoundError = - "java/lang/NoClassDefFoundError"; - -const char *string_java_lang_NoSuchFieldError = - "java/lang/NoSuchFieldError"; - -const char *string_java_lang_NoSuchMethodError = - "java/lang/NoSuchMethodError"; - -const char *string_java_lang_OutOfMemoryError = - "java/lang/OutOfMemoryError"; - -const char *string_java_lang_UnsatisfiedLinkError = - "java/lang/UnsatisfiedLinkError"; - -const char *string_java_lang_UnsupportedClassVersionError = - "java/lang/UnsupportedClassVersionError"; - -const char *string_java_lang_VerifyError = - "java/lang/VerifyError"; - -const char *string_java_lang_VirtualMachineError = - "java/lang/VirtualMachineError"; - - /* string_init ***************************************************************** Initialize the string hashtable lock. @@ -289,36 +152,43 @@ void stringtable_update(void) *******************************************************************************/ -java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength) +java_objectheader *javastring_new_from_utf_buffer(const char *buffer, u4 blength) { const char *utf_ptr; /* current utf character in utf string */ u4 utflength; /* length of utf-string if uncompressed */ - java_lang_String *s; /* result-string */ - java_chararray *a; + java_objectheader *o; + java_lang_String *s; /* result-string */ + java_chararray *a; u4 i; assert(buffer); utflength = utf_get_number_of_u2s_for_buffer(buffer,blength); - s = (java_lang_String *) builtin_new(class_java_lang_String); + o = builtin_new(class_java_lang_String); a = builtin_newarray_char(utflength); /* javastring or character-array could not be created */ - if (!a || !s) + + if ((o == NULL) || (a == NULL)) return NULL; /* decompress utf-string */ + utf_ptr = buffer; + for (i = 0; i < utflength; i++) - a->data[i] = utf_nextu2((char **)&utf_ptr); + a->data[i] = utf_nextu2((char **) &utf_ptr); /* set fields of the javastring-object */ + + s = (java_lang_String *) o; + s->value = a; s->offset = 0; s->count = utflength; - return s; + return o; } @@ -337,10 +207,11 @@ java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength) *******************************************************************************/ -java_lang_String *javastring_safe_new_from_utf8(const char *text) +java_objectheader *javastring_safe_new_from_utf8(const char *text) { - java_lang_String *s; /* result-string */ - java_chararray *a; + java_objectheader *o; + java_chararray *a; + java_lang_String *s; s4 nbytes; s4 len; @@ -357,12 +228,12 @@ java_lang_String *javastring_safe_new_from_utf8(const char *text) /* allocate the String object and the char array */ - s = (java_lang_String *) builtin_new(class_java_lang_String); + o = builtin_new(class_java_lang_String); a = builtin_newarray_char(len); /* javastring or character-array could not be created? */ - if (!a || !s) + if ((o == NULL) || (a == NULL)) return NULL; /* decompress UTF-8 string */ @@ -371,11 +242,13 @@ java_lang_String *javastring_safe_new_from_utf8(const char *text) /* set fields of the String object */ + s = (java_lang_String *) o; + s->value = a; s->offset = 0; s->count = len; - return s; + return o; } @@ -394,7 +267,7 @@ java_lang_String *javastring_safe_new_from_utf8(const char *text) *******************************************************************************/ -java_lang_String *javastring_new_from_utf_string(const char *utfstr) +java_objectheader *javastring_new_from_utf_string(const char *utfstr) { assert(utfstr); @@ -411,15 +284,16 @@ java_lang_String *javastring_new_from_utf_string(const char *utfstr) *******************************************************************************/ -java_lang_String *javastring_new(utf *u) +java_objectheader *javastring_new(utf *u) { char *utf_ptr; /* current utf character in utf string */ u4 utflength; /* length of utf-string if uncompressed */ - java_lang_String *s; /* result-string */ - java_chararray *a; + java_objectheader *o; + java_chararray *a; + java_lang_String *s; s4 i; - if (!u) { + if (u == NULL) { exceptions_throw_nullpointerexception(); return NULL; } @@ -427,25 +301,31 @@ java_lang_String *javastring_new(utf *u) utf_ptr = u->text; utflength = utf_get_number_of_u2s(u); - s = (java_lang_String *) builtin_new(class_java_lang_String); + o = builtin_new(class_java_lang_String); a = builtin_newarray_char(utflength); /* javastring or character-array could not be created */ - if (!a || !s) + + if ((o == NULL) || (a == NULL)) return NULL; /* decompress utf-string */ + for (i = 0; i < utflength; i++) a->data[i] = utf_nextu2(&utf_ptr); /* set fields of the javastring-object */ + + s = (java_lang_String *) o; + s->value = a; s->offset = 0; s->count = utflength; - return s; + return o; } + /* javastring_new_slash_to_dot ************************************************* creates a new object of type java/lang/String with the text of @@ -455,16 +335,17 @@ java_lang_String *javastring_new(utf *u) *******************************************************************************/ -java_lang_String *javastring_new_slash_to_dot(utf *u) +java_objectheader *javastring_new_slash_to_dot(utf *u) { char *utf_ptr; /* current utf character in utf string */ u4 utflength; /* length of utf-string if uncompressed */ - java_lang_String *s; /* result-string */ - java_chararray *a; + java_objectheader *o; + java_chararray *a; + java_lang_String *s; s4 i; u2 ch; - if (!u) { + if (u == NULL) { exceptions_throw_nullpointerexception(); return NULL; } @@ -472,14 +353,15 @@ java_lang_String *javastring_new_slash_to_dot(utf *u) utf_ptr = u->text; utflength = utf_get_number_of_u2s(u); - s = (java_lang_String *) builtin_new(class_java_lang_String); + o = builtin_new(class_java_lang_String); a = builtin_newarray_char(utflength); /* javastring or character-array could not be created */ - if (!a || !s) + if ((o == NULL) || (a == NULL)) return NULL; /* decompress utf-string */ + for (i = 0; i < utflength; i++) { ch = utf_nextu2(&utf_ptr); if (ch == '/') @@ -488,11 +370,14 @@ java_lang_String *javastring_new_slash_to_dot(utf *u) } /* set fields of the javastring-object */ + + s = (java_lang_String *) o; + s->value = a; s->offset = 0; s->count = utflength; - return s; + return o; } @@ -510,37 +395,43 @@ java_lang_String *javastring_new_slash_to_dot(utf *u) *******************************************************************************/ -java_lang_String *javastring_new_from_ascii(const char *text) +java_objectheader *javastring_new_from_ascii(const char *text) { s4 i; s4 len; /* length of the string */ - java_lang_String *s; /* result-string */ - java_chararray *a; + java_objectheader *o; + java_lang_String *s; + java_chararray *a; - if (!text) { + if (text == NULL) { exceptions_throw_nullpointerexception(); return NULL; } len = strlen(text); - s = (java_lang_String *) builtin_new(class_java_lang_String); + o = builtin_new(class_java_lang_String); a = builtin_newarray_char(len); /* javastring or character-array could not be created */ - if (!a || !s) + + if ((o == NULL) || (a == NULL)) return NULL; /* copy text */ + for (i = 0; i < len; i++) a->data[i] = text[i]; /* set fields of the javastring-object */ + + s = (java_lang_String *) o; + s->value = a; s->offset = 0; s->count = len; - return s; + return o; } @@ -586,27 +477,16 @@ char *javastring_tochar(java_objectheader *so) *******************************************************************************/ -utf *javastring_toutf(java_lang_String *s, bool isclassname) +utf *javastring_toutf(java_objectheader *string, bool isclassname) { - if (s == NULL) - return utf_null; - - return utf_new_u2(s->value->data + s->offset, s->count, isclassname); -} - - -/* javastring_strlen *********************************************************** + java_lang_String *s; - Returns the length of the Java string. - -*******************************************************************************/ + s = (java_lang_String *) string; -s4 javastring_strlen(java_lang_String *s) -{ if (s == NULL) - return 0; + return utf_null; - return s->count; + return utf_new_u2(s->value->data + s->offset, s->count, isclassname); } @@ -794,12 +674,12 @@ java_objectheader *literalstring_new(utf *u) *******************************************************************************/ -void literalstring_free(java_objectheader* sobj) +void literalstring_free(java_objectheader* string) { java_lang_String *s; java_chararray *a; - s = (java_lang_String *) sobj; + s = (java_lang_String *) string; a = s->value; /* dispose memory of java.lang.String object */ diff --git a/src/vm/stringlocal.h b/src/vm/stringlocal.h index 99fee6bda..b7faec3c2 100644 --- a/src/vm/stringlocal.h +++ b/src/vm/stringlocal.h @@ -1,6 +1,6 @@ /* src/vm/stringlocal.h - string header - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien @@ -22,13 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Edwin Steiner - - $Id: stringlocal.h 5821 2006-10-24 16:41:54Z edwin $ + $Id: stringlocal.h 7246 2007-01-29 18:49:05Z twisti $ */ @@ -42,11 +36,11 @@ typedef struct literalstring literalstring; #include "config.h" #include "vm/types.h" -#include "vm/global.h" /* required before java_lang_String.h */ -#include "native/include/java_lang_String.h" +#include "toolbox/hashtable.h" + +#include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/utf8.h" +#include "vmcore/utf8.h" /* data structure of internal javastrings stored in global hashtable **********/ @@ -61,59 +55,6 @@ struct literalstring { extern hashtable hashtable_string; -/* global string definitions **************************************************/ - -/* exception/error super class */ - -extern const char *string_java_lang_Throwable; -extern const char *string_java_lang_VMThrowable; - - -/* specify some exception strings for code generation */ - -extern const char *string_java_lang_ArithmeticException; -extern const char *string_java_lang_ArithmeticException_message; -extern const char *string_java_lang_ArrayIndexOutOfBoundsException; -extern const char *string_java_lang_ArrayStoreException; -extern const char *string_java_lang_ClassCastException; -extern const char *string_java_lang_ClassNotFoundException; -extern const char *string_java_lang_CloneNotSupportedException; -extern const char *string_java_lang_Exception; -extern const char *string_java_lang_IllegalAccessException; -extern const char *string_java_lang_IllegalArgumentException; -extern const char *string_java_lang_IllegalMonitorStateException; -extern const char *string_java_lang_IndexOutOfBoundsException; -extern const char *string_java_lang_InstantiationException; -extern const char *string_java_lang_InterruptedException; -extern const char *string_java_lang_NegativeArraySizeException; -extern const char *string_java_lang_NoSuchFieldException; -extern const char *string_java_lang_NoSuchMethodException; -extern const char *string_java_lang_NullPointerException; -extern const char *string_java_lang_StringIndexOutOfBoundsException; -extern const char *string_java_lang_reflect_InvocationTargetException; - - -/* specify some error strings for code generation */ - -extern const char *string_java_lang_AbstractMethodError; -extern const char *string_java_lang_ClassCircularityError; -extern const char *string_java_lang_ClassFormatError; -extern const char *string_java_lang_Error; -extern const char *string_java_lang_ExceptionInInitializerError; -extern const char *string_java_lang_IncompatibleClassChangeError; -extern const char *string_java_lang_InternalError; -extern const char *string_java_lang_InstantiationError; -extern const char *string_java_lang_LinkageError; -extern const char *string_java_lang_NoClassDefFoundError; -extern const char *string_java_lang_NoSuchFieldError; -extern const char *string_java_lang_NoSuchMethodError; -extern const char *string_java_lang_OutOfMemoryError; -extern const char *string_java_lang_UnsatisfiedLinkError; -extern const char *string_java_lang_UnsupportedClassVersionError; -extern const char *string_java_lang_VerifyError; -extern const char *string_java_lang_VirtualMachineError; - - /* function prototypes ********************************************************/ /* initialize string subsystem */ @@ -122,29 +63,26 @@ bool string_init(void); void stringtable_update(void); /* creates a new object of type java/lang/String from a utf-text */ -java_lang_String *javastring_new(utf *text); +java_objectheader *javastring_new(utf *text); /* creates a new object of type java/lang/String from a utf-text, changes slashes to dots */ -java_lang_String *javastring_new_slash_to_dot(utf *text); +java_objectheader *javastring_new_slash_to_dot(utf *text); /* creates a new object of type java/lang/String from an ASCII c-string */ -java_lang_String *javastring_new_from_ascii(const char *text); +java_objectheader *javastring_new_from_ascii(const char *text); /* creates a new object of type java/lang/String from UTF-8 */ -java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength); -java_lang_String *javastring_new_from_utf_string(const char *utfstr); +java_objectheader *javastring_new_from_utf_buffer(const char *buffer, u4 blength); +java_objectheader *javastring_new_from_utf_string(const char *utfstr); /* creates a new object of type java/lang/String from (possibly invalid) UTF-8 */ -java_lang_String *javastring_safe_new_from_utf8(const char *text); +java_objectheader *javastring_safe_new_from_utf8(const char *text); /* make c-string from a javastring (debugging) */ -char *javastring_tochar(java_objectheader *s); +char *javastring_tochar(java_objectheader *string); /* make utf symbol from javastring */ -utf *javastring_toutf(java_lang_String *string, bool isclassname); - -/* returns length of javastring */ -s4 javastring_strlen(java_lang_String *s); +utf *javastring_toutf(java_objectheader *string, bool isclassname); /* creates a new javastring with the text of the u2-array */ java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset, diff --git a/src/vm/suck.c b/src/vm/suck.c deleted file mode 100644 index 859c89037..000000000 --- a/src/vm/suck.c +++ /dev/null @@ -1,650 +0,0 @@ -/* src/vm/suck.c - functions to read LE ordered types from a buffer - - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - $Id: suck.c 6286 2007-01-10 10:03:38Z twisti $ - -*/ - - -#include "config.h" - -#include -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#else -# include "threads/none/lock.h" -#endif - -#include "toolbox/list.h" -#include "toolbox/logging.h" -#include "toolbox/util.h" -#include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" -#include "vm/properties.h" -#include "vm/stringlocal.h" -#include "vm/suck.h" -#include "vm/vm.h" -#include "vm/zip.h" - - -/* global variables ***********************************************************/ - -list *list_classpath_entries; - - -/* suck_init ******************************************************************* - - Initializes the suck subsystem like initializing the classpath - entries list. - -*******************************************************************************/ - -bool suck_init(void) -{ - list_classpath_entries = list_create(OFFSET(list_classpath_entry, linkage)); - - /* everything's ok */ - - return true; -} - - -/* scandir_filter ************************************************************** - - Filters for zip/jar files. - -*******************************************************************************/ - -#if defined(__LINUX__) -static int scandir_filter(const struct dirent *a) -#else -static int scandir_filter(struct dirent *a) -#endif -{ - s4 namlen; - -#if defined(_DIRENT_HAVE_D_NAMLEN) - namlen = a->d_namlen; -#else - namlen = strlen(a->d_name); -#endif - - if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) || - (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0)) - return 1; - - return 0; -} - - -/* suck_add ******************************************************************** - - Adds a classpath to the global classpath entries list. - -*******************************************************************************/ - -void suck_add(char *classpath) -{ - list_classpath_entry *lce; - char *start; - char *end; - char *filename; - s4 filenamelen; - bool is_zip; - char *cwd; - s4 cwdlen; -#if defined(ENABLE_ZLIB) - hashtable *ht; -#endif - - /* parse the classpath string */ - - for (start = classpath; (*start) != '\0'; ) { - - /* search for ':' delimiter to get the end of the current entry */ - for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); - - if (start != end) { - is_zip = false; - filenamelen = end - start; - - if (filenamelen > 4) { - if ((strncasecmp(end - 4, ".zip", 4) == 0) || - (strncasecmp(end - 4, ".jar", 4) == 0)) { - is_zip = true; - } - } - - /* save classpath entries as absolute pathnames */ - - cwd = NULL; - cwdlen = 0; - - if (*start != '/') { /* XXX fix me for win32 */ - cwd = _Jv_getcwd(); - cwdlen = strlen(cwd) + strlen("/"); - } - - /* allocate memory for filename and fill it */ - - filename = MNEW(char, filenamelen + cwdlen + strlen("/") + - strlen("0")); - - if (cwd) { - strcpy(filename, cwd); - strcat(filename, "/"); - strncat(filename, start, filenamelen); - - /* add cwd length to file length */ - filenamelen += cwdlen; - - } else { - strncpy(filename, start, filenamelen); - filename[filenamelen] = '\0'; - } - - lce = NULL; - - if (is_zip) { -#if defined(ENABLE_ZLIB) - ht = zip_open(filename); - - if (ht != NULL) { - lce = NEW(list_classpath_entry); - - lce->type = CLASSPATH_ARCHIVE; - lce->htclasses = ht; - lce->path = filename; - lce->pathlen = filenamelen; - - /* SUN compatible -verbose:class output */ - - if (opt_verboseclass) - printf("[Opened %s]\n", filename); - } - -#else - vm_abort("suck_add: zip/jar files not supported"); -#endif - } - else { - if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */ - filename[filenamelen] = '/'; - filename[filenamelen + 1] = '\0'; - filenamelen++; - } - - lce = NEW(list_classpath_entry); - - lce->type = CLASSPATH_PATH; - lce->path = filename; - lce->pathlen = filenamelen; - } - - /* add current classpath entry, if no error */ - - if (lce != NULL) - list_add_last(list_classpath_entries, lce); - } - - /* goto next classpath entry, skip ':' delimiter */ - - if ((*end) == ':') - start = end + 1; - else - start = end; - } -} - - -/* suck_add_from_property ****************************************************** - - Adds a classpath form a property entry to the global classpath - entries list. - -*******************************************************************************/ - -void suck_add_from_property(char *key) -{ - char *value; - char *start; - char *end; - char *path; - s4 pathlen; - struct dirent **namelist; - s4 n; - s4 i; - s4 namlen; - char *tmpbootclasspath; - - /* get the property value */ - - value = properties_get(key); - - if (value == NULL) - return; - - /* get the directory entries of the property */ - - for (start = value; (*start) != '\0'; ) { - - /* search for ':' delimiter to get the end of the current entry */ - - for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); - - /* found an entry */ - - if (start != end) { - /* allocate memory for the path entry */ - - pathlen = end - start; - path = MNEW(char, pathlen + strlen("0")); - - /* copy and terminate the string */ - - strncpy(path, start, pathlen); - path[pathlen] = '\0'; - - /* Reset namelist to NULL for the freeing in an error case - (see below). */ - - namelist = NULL; - - /* scan the directory found for zip/jar files */ - - n = scandir(path, &namelist, scandir_filter, alphasort); - - /* On error, just continue, this should be ok. */ - - if (n > 0) { - for (i = 0; i < n; i++) { -#if defined(_DIRENT_HAVE_D_NAMLEN) - namlen = namelist[i]->d_namlen; -#else - namlen = strlen(namelist[i]->d_name); -#endif - - /* reallocate memory for bootclasspath */ - - tmpbootclasspath = MNEW(char, - pathlen + strlen("/") + namlen + - strlen(":") + - strlen(_Jv_bootclasspath) + - strlen("0")); - - /* prepend the file found to bootclasspath */ - - strcpy(tmpbootclasspath, path); - strcat(tmpbootclasspath, "/"); - strcat(tmpbootclasspath, namelist[i]->d_name); - strcat(tmpbootclasspath, ":"); - - strcat(tmpbootclasspath, _Jv_bootclasspath); - - /* free old bootclasspath memory */ - - MFREE(_Jv_bootclasspath, u1, strlen(_Jv_bootclasspath)); - - /* and set the new bootclasspath */ - - _Jv_bootclasspath = tmpbootclasspath; - - /* free the memory allocated by scandir */ - /* (We use `free` as the memory came from the C library.) */ - - free(namelist[i]); - } - } - - /* On some systems (like Linux) when n == 0, then namelist - returned from scnadir is NULL, thus we don't have to - free it. - (Use `free` as the memory came from the C library.) */ - - if (namelist != NULL) - free(namelist); - - MFREE(path, char, pathlen + strlen("0")); - } - - /* goto next entry, skip ':' delimiter */ - - if ((*end) == ':') - start = end + 1; - else - start = end; - } -} - - -/* suck_check_classbuffer_size ************************************************* - - Assert that at least bytes are left to read is limited - to the range of non-negative s4 values. - -*******************************************************************************/ - -bool suck_check_classbuffer_size(classbuffer *cb, s4 len) -{ -#ifdef ENABLE_VERIFIER - if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) { - *exceptionptr = - new_classformaterror((cb)->class, "Truncated class file"); - - return false; - } -#endif /* ENABLE_VERIFIER */ - - return true; -} - - -u1 suck_u1(classbuffer *cb) -{ - u1 a; - - a = SUCK_BE_U1(cb->pos); - cb->pos++; - - return a; -} - - -u2 suck_u2(classbuffer *cb) -{ - u2 a; - - a = SUCK_BE_U2(cb->pos); - cb->pos += 2; - - return a; -} - - -u4 suck_u4(classbuffer *cb) -{ - u4 a; - - a = SUCK_BE_U4(cb->pos); - cb->pos += 4; - - return a; -} - - -u8 suck_u8(classbuffer *cb) -{ -#if U8_AVAILABLE == 1 - u8 a; - - a = SUCK_BE_U8(cb->pos); - cb->pos += 8; - - return a; -#else - u8 v; - - v.high = suck_u4(cb); - v.low = suck_u4(cb); - - return v; -#endif -} - - -float suck_float(classbuffer *cb) -{ - float f; - -#if WORDS_BIGENDIAN == 0 - u1 buffer[4]; - u2 i; - - for (i = 0; i < 4; i++) - buffer[3 - i] = suck_u1(cb); - - MCOPY((u1 *) (&f), buffer, u1, 4); -#else - suck_nbytes((u1*) (&f), cb, 4); -#endif - - if (sizeof(float) != 4) { - exceptions_throw_internalerror("Incompatible float-format"); - - /* XXX should we exit in such a case? */ - throw_exception_exit(); - } - - return f; -} - - -double suck_double(classbuffer *cb) -{ - double d; - -#if WORDS_BIGENDIAN == 0 - u1 buffer[8]; - u2 i; - -#if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__) - /* - * On little endian ARM processors when using FPA, word order - * of doubles is still big endian. So take that into account - * here. When using VFP, word order of doubles follows byte - * order. (michi 2005/07/24) - */ - for (i = 0; i < 4; i++) - buffer[3 - i] = suck_u1(cb); - for (i = 0; i < 4; i++) - buffer[7 - i] = suck_u1(cb); -#else - for (i = 0; i < 8; i++) - buffer[7 - i] = suck_u1(cb); -#endif /* defined(__ARM__) && ... */ - - MCOPY((u1 *) (&d), buffer, u1, 8); -#else - suck_nbytes((u1*) (&d), cb, 8); -#endif - - if (sizeof(double) != 8) { - exceptions_throw_internalerror("Incompatible double-format"); - - /* XXX should we exit in such a case? */ - throw_exception_exit(); - } - - return d; -} - - -/* suck_nbytes ***************************************************************** - - Transfer block of classfile data into a buffer. - -*******************************************************************************/ - -void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len) -{ - MCOPY(buffer, cb->pos, u1, len); - cb->pos += len; -} - - -/* suck_skip_nbytes ************************************************************ - - Skip block of classfile data. - -*******************************************************************************/ - -void suck_skip_nbytes(classbuffer *cb, s4 len) -{ - cb->pos += len; -} - - -/* suck_start ****************************************************************** - - Returns true if classbuffer is already loaded or a file for the - specified class has succussfully been read in. All directories of - the searchpath are used to find the classfile (.class). - Returns NULL if no classfile is found and writes an error message. - -*******************************************************************************/ - -classbuffer *suck_start(classinfo *c) -{ - list_classpath_entry *lce; - char *filename; - s4 filenamelen; - char *path; - FILE *classfile; - s4 len; - struct stat buffer; - classbuffer *cb; - - /* initialize return value */ - - cb = NULL; - - /* get the classname as char string (do it here for the warning at - the end of the function) */ - - filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0"); - filename = MNEW(char, filenamelen); - - utf_copy(filename, c->name); - strcat(filename, ".class"); - - /* walk through all classpath entries */ - - for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL; - lce = list_next(list_classpath_entries, lce)) { -#if defined(ENABLE_ZLIB) - if (lce->type == CLASSPATH_ARCHIVE) { - - /* enter a monitor on zip/jar archives */ - - LOCK_MONITOR_ENTER(lce); - - /* try to get the file in current archive */ - - cb = zip_get(lce, c); - - /* leave the monitor */ - - LOCK_MONITOR_EXIT(lce); - - } else { -#endif /* defined(ENABLE_ZLIB) */ - path = MNEW(char, lce->pathlen + filenamelen); - strcpy(path, lce->path); - strcat(path, filename); - - classfile = fopen(path, "r"); - - if (classfile) { /* file exists */ - if (!stat(path, &buffer)) { /* read classfile data */ - cb = NEW(classbuffer); - cb->class = c; - cb->size = buffer.st_size; - cb->data = MNEW(u1, cb->size); - cb->pos = cb->data; - cb->path = lce->path; - - /* read class data */ - - len = fread(cb->data, 1, cb->size, classfile); - - if (len != buffer.st_size) { - suck_stop(cb); -/* if (ferror(classfile)) { */ -/* } */ - } - - /* close the class file */ - - fclose(classfile); - } - } - - MFREE(path, char, lce->pathlen + filenamelen); -#if defined(ENABLE_ZLIB) - } -#endif - } - - if (opt_verbose) - if (cb == NULL) - dolog("Warning: Can not open class file '%s'", filename); - - MFREE(filename, char, filenamelen); - - return cb; -} - - -/* suck_stop ******************************************************************* - - Frees memory for buffer with classfile data. - - CAUTION: This function may only be called if buffer has been - allocated by suck_start with reading a file. - -*******************************************************************************/ - -void suck_stop(classbuffer *cb) -{ - /* free memory */ - - MFREE(cb->data, u1, cb->size); - FREE(cb, classbuffer); -} - - -/* - * 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: - */ diff --git a/src/vm/suck.h b/src/vm/suck.h deleted file mode 100644 index f8eca8418..000000000 --- a/src/vm/suck.h +++ /dev/null @@ -1,205 +0,0 @@ -/* src/vm/suck.h - functions to read LE ordered types from a buffer - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: suck.h 5810 2006-10-20 13:54:54Z twisti $ - -*/ - - -#ifndef _SUCK_H -#define _SUCK_H - -#include "config.h" -#include "vm/types.h" - -#include "vm/class.h" -#include "vm/hashtable.h" -#include "vm/loader.h" - - -/* list_classpath_entry *******************************************************/ - -enum { - CLASSPATH_PATH, - CLASSPATH_ARCHIVE -}; - -typedef struct list_classpath_entry list_classpath_entry; - -struct list_classpath_entry { -#if defined(ENABLE_THREADS) - java_objectheader header; /* monitor locking on zip/jar files */ -#endif - s4 type; - char *path; - s4 pathlen; -#if defined(ENABLE_ZLIB) - hashtable *htclasses; -#endif - listnode linkage; -}; - - -/* macros to read LE and BE types from a buffer ******************************** - - BE macros are for Java class file loading. - LE macros are for ZIP file loading. - -*******************************************************************************/ - -/* LE macros (for ZIP files ) *************************************************/ - -#if defined(__I386__) || defined(__X86_64__) - -/* we can optimize the LE access on little endian machines without alignment */ - -#define SUCK_LE_U1(p) *((u1 *) (p)) -#define SUCK_LE_U2(p) *((u2 *) (p)) -#define SUCK_LE_U4(p) *((u4 *) (p)) - -#if U8_AVAILABLE == 1 -#define SUCK_LE_U8(p) *((u8 *) (p)) -#endif - -#else /* defined(__I386__) || defined(__X86_64__) */ - -#define SUCK_LE_U1(p) \ - ((u1) (p)[0]) - -#define SUCK_LE_U2(p) \ - ((((u2) (p)[1]) << 8) + \ - ((u2) (p)[0])) - -#define SUCK_LE_U4(p) \ - ((((u4) (p)[3]) << 24) + \ - (((u4) (p)[2]) << 16) + \ - (((u4) (p)[1]) << 8) + \ - ((u4) (p)[0])) - -#if U8_AVAILABLE == 1 -#define SUCK_LE_U8(p) \ - ((((u8) (p)[7]) << 56) + \ - (((u8) (p)[6]) << 48) + \ - (((u8) (p)[5]) << 40) + \ - (((u8) (p)[4]) << 32) + \ - (((u8) (p)[3]) << 24) + \ - (((u8) (p)[2]) << 16) + \ - (((u8) (p)[1]) << 8) + \ - ((u8) (p)[0])) -#endif - -#endif /* defined(__I386__) || defined(__X86_64__) */ - - -/* BE macros (for Java class files ) ******************************************/ - -#define SUCK_BE_U1(p) \ - ((u1) (p)[0]) - -#define SUCK_BE_U2(p) \ - ((((u2) (p)[0]) << 8) + \ - ((u2) (p)[1])) - -#define SUCK_BE_U4(p) \ - ((((u4) (p)[0]) << 24) + \ - (((u4) (p)[1]) << 16) + \ - (((u4) (p)[2]) << 8) + \ - ((u4) (p)[3])) - -#if U8_AVAILABLE == 1 -#define SUCK_BE_U8(p) \ - ((((u8) (p)[0]) << 56) + \ - (((u8) (p)[1]) << 48) + \ - (((u8) (p)[2]) << 40) + \ - (((u8) (p)[3]) << 32) + \ - (((u8) (p)[4]) << 24) + \ - (((u8) (p)[5]) << 16) + \ - (((u8) (p)[6]) << 8) + \ - ((u8) (p)[7])) -#endif - - -#define SUCK_BE_S1(p) (s1) SUCK_BE_U1(p) -#define SUCK_BE_S2(p) (s2) SUCK_BE_U2(p) -#define SUCK_BE_S4(p) (s4) SUCK_BE_U4(p) -#define SUCK_BE_S8(p) (s8) SUCK_BE_U8(p) - - -/* signed suck defines ********************************************************/ - -#define suck_s1(a) (s1) suck_u1((a)) -#define suck_s2(a) (s2) suck_u2((a)) -#define suck_s4(a) (s4) suck_u4((a)) -#define suck_s8(a) (s8) suck_u8((a)) - - -/* export variables ***********************************************************/ - -extern list *list_classpath_entries; - - -/* function prototypes ********************************************************/ - -bool suck_init(void); - -void suck_add(char *classpath); -void suck_add_from_property(char *key); - -bool suck_check_classbuffer_size(classbuffer *cb, s4 len); - -u1 suck_u1(classbuffer *cb); -u2 suck_u2(classbuffer *cb); -u4 suck_u4(classbuffer *cb); -u8 suck_u8(classbuffer *cb); - -float suck_float(classbuffer *cb); -double suck_double(classbuffer *cb); - -void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len); -void suck_skip_nbytes(classbuffer *cb, s4 len); - -classbuffer *suck_start(classinfo *c); - -void suck_stop(classbuffer *cb); - -#endif /* _SUCK_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: - */ diff --git a/src/vm/utf8.c b/src/vm/utf8.c deleted file mode 100644 index 2619b0c03..000000000 --- a/src/vm/utf8.c +++ /dev/null @@ -1,1795 +0,0 @@ -/* src/vm/utf8.c - utf8 string functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - Mark Probst - Andreas Krall - Christian Thalinger - Edwin Steiner - - $Id: utf8.c 6286 2007-01-10 10:03:38Z twisti $ - -*/ - - -#include "config.h" - -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#else -# include "threads/none/lock.h" -#endif - -#include "vm/builtin.h" -#include "vm/exceptions.h" -#include "vm/hashtable.h" -#include "vm/options.h" -#include "vm/statistics.h" -#include "vm/stringlocal.h" -#include "vm/utf8.h" - - -/* global variables ***********************************************************/ - -/* hashsize must be power of 2 */ - -#define HASHTABLE_UTF_SIZE 16384 /* initial size of utf-hash */ - -hashtable *hashtable_utf; /* hashtable for utf8-symbols */ - - -/* utf-symbols for pointer comparison of frequently used strings **************/ - -utf *utf_java_lang_Object; - -utf *utf_java_lang_Class; -utf *utf_java_lang_ClassLoader; -utf *utf_java_lang_Cloneable; -utf *utf_java_lang_SecurityManager; -utf *utf_java_lang_String; -utf *utf_java_lang_System; -utf *utf_java_lang_ThreadGroup; -utf *utf_java_io_Serializable; - -utf *utf_java_lang_Throwable; -utf *utf_java_lang_Error; -utf *utf_java_lang_LinkageError; -utf *utf_java_lang_NoClassDefFoundError; -utf *utf_java_lang_OutOfMemoryError; -utf *utf_java_lang_VirtualMachineError; - -#if defined(ENABLE_JAVASE) -utf *utf_java_lang_AbstractMethodError; -utf *utf_java_lang_NoSuchMethodError; -#endif - -#if defined(WITH_CLASSPATH_GNU) -utf *utf_java_lang_VMThrowable; -#endif - -utf *utf_java_lang_Exception; -utf *utf_java_lang_ClassCastException; -utf *utf_java_lang_ClassNotFoundException; -utf *utf_java_lang_IllegalArgumentException; -utf *utf_java_lang_IllegalMonitorStateException; - -utf *utf_java_lang_NullPointerException; - -#if defined(ENABLE_JAVASE) -utf* utf_java_lang_Void; -#endif - -utf* utf_java_lang_Boolean; -utf* utf_java_lang_Byte; -utf* utf_java_lang_Character; -utf* utf_java_lang_Short; -utf* utf_java_lang_Integer; -utf* utf_java_lang_Long; -utf* utf_java_lang_Float; -utf* utf_java_lang_Double; - -#if defined(ENABLE_JAVASE) -utf *utf_java_lang_StackTraceElement; -utf *utf_java_lang_reflect_Constructor; -utf *utf_java_lang_reflect_Field; -utf *utf_java_lang_reflect_Method; -utf *utf_java_util_Vector; -#endif - -utf *utf_InnerClasses; /* InnerClasses */ -utf *utf_ConstantValue; /* ConstantValue */ -utf *utf_Code; /* Code */ -utf *utf_Exceptions; /* Exceptions */ -utf *utf_LineNumberTable; /* LineNumberTable */ -utf *utf_SourceFile; /* SourceFile */ - -#if defined(ENABLE_JAVASE) -utf *utf_EnclosingMethod; -utf *utf_Signature; -utf *utf_RuntimeVisibleAnnotations; -utf *utf_StackMapTable; -#endif - -utf *utf_init; /* */ -utf *utf_clinit; /* */ -utf *utf_clone; /* clone */ -utf *utf_finalize; /* finalize */ -utf *utf_run; /* run */ - -utf *utf_add; -utf *utf_remove; -utf *utf_addThread; -utf *utf_removeThread; -utf *utf_put; -utf *utf_get; -utf *utf_value; - -utf *utf_fillInStackTrace; -utf *utf_getSystemClassLoader; -utf *utf_loadClass; -utf *utf_printStackTrace; - -utf *utf_Z; /* Z */ -utf *utf_B; /* B */ -utf *utf_C; /* C */ -utf *utf_S; /* S */ -utf *utf_I; /* I */ -utf *utf_J; /* J */ -utf *utf_F; /* F */ -utf *utf_D; /* D */ - -utf *utf_void__void; /* ()V */ -utf *utf_boolean__void; /* (Z)V */ -utf *utf_byte__void; /* (B)V */ -utf *utf_char__void; /* (C)V */ -utf *utf_short__void; /* (S)V */ -utf *utf_int__void; /* (I)V */ -utf *utf_long__void; /* (J)V */ -utf *utf_float__void; /* (F)V */ -utf *utf_double__void; /* (D)V */ - -utf *utf_void__java_lang_ClassLoader; /* ()Ljava/lang/ClassLoader; */ -utf *utf_void__java_lang_Object; /* ()Ljava/lang/Object; */ -utf *utf_void__java_lang_Throwable; /* ()Ljava/lang/Throwable; */ -utf *utf_java_lang_Object__java_lang_Object; -utf *utf_java_lang_String__void; /* (Ljava/lang/String;)V */ -utf *utf_java_lang_String__java_lang_Class; -utf *utf_java_lang_Thread__V; /* (Ljava/lang/Thread;)V */ -utf *utf_java_lang_Throwable__void; /* (Ljava/lang/Throwable;)V */ - -utf *utf_not_named_yet; /* special name for unnamed classes */ -utf *utf_null; -utf *array_packagename; - - -/* utf_init ******************************************************************** - - Initializes the utf8 subsystem. - -*******************************************************************************/ - -bool utf8_init(void) -{ - /* create utf8 hashtable */ - - hashtable_utf = NEW(hashtable); - - hashtable_create(hashtable_utf, HASHTABLE_UTF_SIZE); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_utf_len += sizeof(utf*) * hashtable_utf->size; -#endif - - /* create utf-symbols for pointer comparison of frequently used strings */ - - utf_java_lang_Object = utf_new_char("java/lang/Object"); - - utf_java_lang_Class = utf_new_char("java/lang/Class"); - utf_java_lang_ClassLoader = utf_new_char("java/lang/ClassLoader"); - utf_java_lang_Cloneable = utf_new_char("java/lang/Cloneable"); - utf_java_lang_SecurityManager = utf_new_char("java/lang/SecurityManager"); - utf_java_lang_String = utf_new_char("java/lang/String"); - utf_java_lang_System = utf_new_char("java/lang/System"); - utf_java_lang_ThreadGroup = utf_new_char("java/lang/ThreadGroup"); - utf_java_io_Serializable = utf_new_char("java/io/Serializable"); - - utf_java_lang_Throwable = utf_new_char(string_java_lang_Throwable); - utf_java_lang_Error = utf_new_char(string_java_lang_Error); - - utf_java_lang_LinkageError = - utf_new_char(string_java_lang_LinkageError); - - utf_java_lang_NoClassDefFoundError = - utf_new_char(string_java_lang_NoClassDefFoundError); - - utf_java_lang_OutOfMemoryError = - utf_new_char(string_java_lang_OutOfMemoryError); - - utf_java_lang_VirtualMachineError = - utf_new_char(string_java_lang_VirtualMachineError); - -#if defined(ENABLE_JAVASE) - utf_java_lang_AbstractMethodError = - utf_new_char(string_java_lang_AbstractMethodError); - - utf_java_lang_NoSuchMethodError = - utf_new_char(string_java_lang_NoSuchMethodError); -#endif - -#if defined(WITH_CLASSPATH_GNU) - utf_java_lang_VMThrowable = utf_new_char(string_java_lang_VMThrowable); -#endif - - utf_java_lang_Exception = utf_new_char(string_java_lang_Exception); - - utf_java_lang_ClassCastException = - utf_new_char(string_java_lang_ClassCastException); - - utf_java_lang_ClassNotFoundException = - utf_new_char(string_java_lang_ClassNotFoundException); - - utf_java_lang_IllegalArgumentException = - utf_new_char(string_java_lang_IllegalArgumentException); - - utf_java_lang_IllegalMonitorStateException = - utf_new_char(string_java_lang_IllegalMonitorStateException); - - utf_java_lang_NullPointerException = - utf_new_char(string_java_lang_NullPointerException); - -#if defined(ENABLE_JAVASE) - utf_java_lang_Void = utf_new_char("java/lang/Void"); -#endif - - utf_java_lang_Boolean = utf_new_char("java/lang/Boolean"); - utf_java_lang_Byte = utf_new_char("java/lang/Byte"); - utf_java_lang_Character = utf_new_char("java/lang/Character"); - utf_java_lang_Short = utf_new_char("java/lang/Short"); - utf_java_lang_Integer = utf_new_char("java/lang/Integer"); - utf_java_lang_Long = utf_new_char("java/lang/Long"); - utf_java_lang_Float = utf_new_char("java/lang/Float"); - utf_java_lang_Double = utf_new_char("java/lang/Double"); - -#if defined(ENABLE_JAVASE) - utf_java_lang_StackTraceElement = - utf_new_char("java/lang/StackTraceElement"); - - utf_java_lang_reflect_Constructor = - utf_new_char("java/lang/reflect/Constructor"); - - utf_java_lang_reflect_Field = utf_new_char("java/lang/reflect/Field"); - utf_java_lang_reflect_Method = utf_new_char("java/lang/reflect/Method"); - utf_java_util_Vector = utf_new_char("java/util/Vector"); -#endif - - utf_InnerClasses = utf_new_char("InnerClasses"); - utf_ConstantValue = utf_new_char("ConstantValue"); - utf_Code = utf_new_char("Code"); - utf_Exceptions = utf_new_char("Exceptions"); - utf_LineNumberTable = utf_new_char("LineNumberTable"); - utf_SourceFile = utf_new_char("SourceFile"); - -#if defined(ENABLE_JAVASE) - utf_EnclosingMethod = utf_new_char("EnclosingMethod"); - utf_Signature = utf_new_char("Signature"); - utf_RuntimeVisibleAnnotations = utf_new_char("RuntimeVisibleAnnotations"); - utf_StackMapTable = utf_new_char("StackMapTable"); -#endif - - utf_init = utf_new_char(""); - utf_clinit = utf_new_char(""); - utf_clone = utf_new_char("clone"); - utf_finalize = utf_new_char("finalize"); - utf_run = utf_new_char("run"); - - utf_add = utf_new_char("add"); - utf_remove = utf_new_char("remove"); - utf_addThread = utf_new_char("addThread"); - utf_removeThread = utf_new_char("removeThread"); - utf_put = utf_new_char("put"); - utf_get = utf_new_char("get"); - utf_value = utf_new_char("value"); - - utf_printStackTrace = utf_new_char("printStackTrace"); - utf_fillInStackTrace = utf_new_char("fillInStackTrace"); - utf_loadClass = utf_new_char("loadClass"); - utf_getSystemClassLoader = utf_new_char("getSystemClassLoader"); - - utf_Z = utf_new_char("Z"); - utf_B = utf_new_char("B"); - utf_C = utf_new_char("C"); - utf_S = utf_new_char("S"); - utf_I = utf_new_char("I"); - utf_J = utf_new_char("J"); - utf_F = utf_new_char("F"); - utf_D = utf_new_char("D"); - - utf_void__void = utf_new_char("()V"); - utf_boolean__void = utf_new_char("(Z)V"); - utf_byte__void = utf_new_char("(B)V"); - utf_char__void = utf_new_char("(C)V"); - utf_short__void = utf_new_char("(S)V"); - utf_int__void = utf_new_char("(I)V"); - utf_long__void = utf_new_char("(J)V"); - utf_float__void = utf_new_char("(F)V"); - utf_double__void = utf_new_char("(D)V"); - utf_void__java_lang_Object = utf_new_char("()Ljava/lang/Object;"); - utf_void__java_lang_Throwable = utf_new_char("()Ljava/lang/Throwable;"); - - utf_void__java_lang_ClassLoader = - utf_new_char("()Ljava/lang/ClassLoader;"); - - utf_java_lang_Object__java_lang_Object = - utf_new_char("(Ljava/lang/Object;)Ljava/lang/Object;"); - - utf_java_lang_String__void = utf_new_char("(Ljava/lang/String;)V"); - - utf_java_lang_String__java_lang_Class = - utf_new_char("(Ljava/lang/String;)Ljava/lang/Class;"); - - utf_java_lang_Thread__V = utf_new_char("(Ljava/lang/Thread;)V"); - utf_java_lang_Throwable__void = utf_new_char("(Ljava/lang/Throwable;)V"); - - utf_null = utf_new_char("null"); - utf_not_named_yet = utf_new_char("\t"); - array_packagename = utf_new_char("\t"); - - /* everything's ok */ - - return true; -} - - -/* utf_hashkey ***************************************************************** - - The hashkey is computed from the utf-text by using up to 8 - characters. For utf-symbols longer than 15 characters 3 characters - are taken from the beginning and the end, 2 characters are taken - from the middle. - -*******************************************************************************/ - -#define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val */ -#define fbs(val) ((u4) *( text) << val) /* get first byte, left shift by val */ - -u4 utf_hashkey(const char *text, u4 length) -{ - const char *start_pos = text; /* pointer to utf text */ - u4 a; - - switch (length) { - case 0: /* empty string */ - return 0; - - case 1: return fbs(0); - case 2: return fbs(0) ^ nbs(3); - case 3: return fbs(0) ^ nbs(3) ^ nbs(5); - case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6); - case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6); - case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6); - case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6); - case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7); - - case 9: - a = fbs(0); - a ^= nbs(1); - a ^= nbs(2); - text++; - return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8); - - case 10: - a = fbs(0); - text++; - a ^= nbs(2); - a ^= nbs(3); - a ^= nbs(4); - text++; - return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9); - - case 11: - a = fbs(0); - text++; - a ^= nbs(2); - a ^= nbs(3); - a ^= nbs(4); - text++; - return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10); - - case 12: - a = fbs(0); - text += 2; - a ^= nbs(2); - a ^= nbs(3); - text++; - a ^= nbs(5); - a ^= nbs(6); - a ^= nbs(7); - text++; - return a ^ nbs(9) ^ nbs(10); - - case 13: - a = fbs(0); - a ^= nbs(1); - text++; - a ^= nbs(3); - a ^= nbs(4); - text += 2; - a ^= nbs(7); - a ^= nbs(8); - text += 2; - return a ^ nbs(9) ^ nbs(10); - - case 14: - a = fbs(0); - text += 2; - a ^= nbs(3); - a ^= nbs(4); - text += 2; - a ^= nbs(7); - a ^= nbs(8); - text += 2; - return a ^ nbs(9) ^ nbs(10) ^ nbs(11); - - case 15: - a = fbs(0); - text += 2; - a ^= nbs(3); - a ^= nbs(4); - text += 2; - a ^= nbs(7); - a ^= nbs(8); - text += 2; - return a ^ nbs(9) ^ nbs(10) ^ nbs(11); - - default: /* 3 characters from beginning */ - a = fbs(0); - text += 2; - a ^= nbs(3); - a ^= nbs(4); - - /* 2 characters from middle */ - text = start_pos + (length / 2); - a ^= fbs(5); - text += 2; - a ^= nbs(6); - - /* 3 characters from end */ - text = start_pos + length - 4; - - a ^= fbs(7); - text++; - - return a ^ nbs(10) ^ nbs(11); - } -} - -/* utf_full_hashkey ************************************************************ - - This function computes a hash value using all bytes in the string. - - The algorithm is the "One-at-a-time" algorithm as published - by Bob Jenkins on http://burtleburtle.net/bob/hash/doobs.html. - -*******************************************************************************/ - -u4 utf_full_hashkey(const char *text, u4 length) -{ - register const unsigned char *p = (const unsigned char *) text; - register u4 hash; - register u4 i; - - hash = 0; - for (i=length; i--;) - { - hash += *p++; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - - return hash; -} - -/* unicode_hashkey ************************************************************* - - Compute the hashkey of a unicode string. - -*******************************************************************************/ - -u4 unicode_hashkey(u2 *text, u2 len) -{ - return utf_hashkey((char *) text, len); -} - - -/* utf_new ********************************************************************* - - Creates a new utf-symbol, the text of the symbol is passed as a - u1-array. The function searches the utf-hashtable for a utf-symbol - with this text. On success the element returned, otherwise a new - hashtable element is created. - - If the number of entries in the hashtable exceeds twice the size of - the hashtable slots a reorganization of the hashtable is done and - the utf symbols are copied to a new hashtable with doubled size. - -*******************************************************************************/ - -utf *utf_new(const char *text, u2 length) -{ - u4 key; /* hashkey computed from utf-text */ - u4 slot; /* slot in hashtable */ - utf *u; /* hashtable element */ - u2 i; - - LOCK_MONITOR_ENTER(hashtable_utf->header); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_utf_new++; -#endif - - key = utf_hashkey(text, length); - slot = key & (hashtable_utf->size - 1); - u = hashtable_utf->ptr[slot]; - - /* search external hash chain for utf-symbol */ - - while (u) { - if (u->blength == length) { - /* compare text of hashtable elements */ - - for (i = 0; i < length; i++) - if (text[i] != u->text[i]) - goto nomatch; - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_utf_new_found++; -#endif - - /* symbol found in hashtable */ - - LOCK_MONITOR_EXIT(hashtable_utf->header); - - return u; - } - - nomatch: - u = u->hashlink; /* next element in external chain */ - } - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_utf_len += sizeof(utf) + length + 1; -#endif - - /* location in hashtable found, create new utf element */ - u = NEW(utf); - u->blength = length; /* length in bytes of utfstring */ - u->hashlink = hashtable_utf->ptr[slot]; /* link in external hashchain */ - u->text = mem_alloc(length + 1);/* allocate memory for utf-text */ - - memcpy(u->text, text, length); /* copy utf-text */ - u->text[length] = '\0'; - - hashtable_utf->ptr[slot] = u; /* insert symbol into table */ - hashtable_utf->entries++; /* update number of entries */ - - if (hashtable_utf->entries > (hashtable_utf->size * 2)) { - - /* reorganization of hashtable, average length of the external - chains is approx. 2 */ - - hashtable *newhash; /* the new hashtable */ - u4 i; - utf *u; - utf *nextu; - u4 slot; - - /* create new hashtable, double the size */ - - newhash = hashtable_resize(hashtable_utf, hashtable_utf->size * 2); - -#if defined(ENABLE_STATISTICS) - if (opt_stat) - count_utf_len += sizeof(utf*) * hashtable_utf->size; -#endif - - /* transfer elements to new hashtable */ - - for (i = 0; i < hashtable_utf->size; i++) { - u = hashtable_utf->ptr[i]; - - while (u) { - nextu = u->hashlink; - slot = utf_hashkey(u->text, u->blength) & (newhash->size - 1); - - u->hashlink = (utf *) newhash->ptr[slot]; - newhash->ptr[slot] = u; - - /* follow link in external hash chain */ - - u = nextu; - } - } - - /* dispose old table */ - - hashtable_free(hashtable_utf); - - hashtable_utf = newhash; - } - - LOCK_MONITOR_EXIT(hashtable_utf->header); - - return u; -} - - -/* utf_new_u2 ****************************************************************** - - Make utf symbol from u2 array, if isclassname is true '.' is - replaced by '/'. - -*******************************************************************************/ - -utf *utf_new_u2(u2 *unicode_pos, u4 unicode_length, bool isclassname) -{ - char *buffer; /* memory buffer for unicode characters */ - char *pos; /* pointer to current position in buffer */ - u4 left; /* unicode characters left */ - u4 buflength; /* utf length in bytes of the u2 array */ - utf *result; /* resulting utf-string */ - int i; - - /* determine utf length in bytes and allocate memory */ - - buflength = u2_utflength(unicode_pos, unicode_length); - buffer = MNEW(char, buflength); - - left = buflength; - pos = buffer; - - for (i = 0; i++ < unicode_length; unicode_pos++) { - /* next unicode character */ - u2 c = *unicode_pos; - - if ((c != 0) && (c < 0x80)) { - /* 1 character */ - left--; - if ((int) left < 0) break; - /* convert classname */ - if (isclassname && c == '.') - *pos++ = '/'; - else - *pos++ = (char) c; - - } else if (c < 0x800) { - /* 2 characters */ - unsigned char high = c >> 6; - unsigned char low = c & 0x3F; - left = left - 2; - if ((int) left < 0) break; - *pos++ = high | 0xC0; - *pos++ = low | 0x80; - - } else { - /* 3 characters */ - char low = c & 0x3f; - char mid = (c >> 6) & 0x3F; - char high = c >> 12; - left = left - 3; - if ((int) left < 0) break; - *pos++ = high | 0xE0; - *pos++ = mid | 0x80; - *pos++ = low | 0x80; - } - } - - /* insert utf-string into symbol-table */ - result = utf_new(buffer,buflength); - - MFREE(buffer, char, buflength); - - return result; -} - - -/* utf_new_char **************************************************************** - - Creates a new utf symbol, the text for this symbol is passed as a - c-string ( = char* ). - -*******************************************************************************/ - -utf *utf_new_char(const char *text) -{ - return utf_new(text, strlen(text)); -} - - -/* utf_new_char_classname ****************************************************** - - Creates a new utf symbol, the text for this symbol is passed as a - c-string ( = char* ) "." characters are going to be replaced by - "/". Since the above function is used often, this is a separte - function, instead of an if. - -*******************************************************************************/ - -utf *utf_new_char_classname(const char *text) -{ - if (strchr(text, '.')) { - char *txt = strdup(text); - char *end = txt + strlen(txt); - char *c; - utf *tmpRes; - - for (c = txt; c < end; c++) - if (*c == '.') *c = '/'; - - tmpRes = utf_new(txt, strlen(txt)); - FREE(txt, 0); - - return tmpRes; - - } else - return utf_new(text, strlen(text)); -} - - -/* utf_nextu2 ****************************************************************** - - Read the next unicode character from the utf string and increment - the utf-string pointer accordingly. - - CAUTION: This function is unsafe for input that was not checked - by is_valid_utf! - -*******************************************************************************/ - -u2 utf_nextu2(char **utf_ptr) -{ - /* uncompressed unicode character */ - u2 unicode_char = 0; - /* current position in utf text */ - unsigned char *utf = (unsigned char *) (*utf_ptr); - /* bytes representing the unicode character */ - unsigned char ch1, ch2, ch3; - /* number of bytes used to represent the unicode character */ - int len = 0; - - switch ((ch1 = utf[0]) >> 4) { - default: /* 1 byte */ - (*utf_ptr)++; - return (u2) ch1; - case 0xC: - case 0xD: /* 2 bytes */ - if (((ch2 = utf[1]) & 0xC0) == 0x80) { - unsigned char high = ch1 & 0x1F; - unsigned char low = ch2 & 0x3F; - unicode_char = (high << 6) + low; - len = 2; - } - break; - - case 0xE: /* 2 or 3 bytes */ - if (((ch2 = utf[1]) & 0xC0) == 0x80) { - if (((ch3 = utf[2]) & 0xC0) == 0x80) { - unsigned char low = ch3 & 0x3f; - unsigned char mid = ch2 & 0x3f; - unsigned char high = ch1 & 0x0f; - unicode_char = (((high << 6) + mid) << 6) + low; - len = 3; - } else - len = 2; - } - break; - } - - /* update position in utf-text */ - *utf_ptr = (char *) (utf + len); - - return unicode_char; -} - - -/* utf_bytes ******************************************************************* - - Determine number of bytes (aka. octets) in the utf string. - - IN: - u............utf string - - OUT: - The number of octets of this utf string. - There is _no_ terminating zero included in this count. - -*******************************************************************************/ - -u4 utf_bytes(utf *u) -{ - return u->blength; -} - -/* utf_get_number_of_u2s_for_buffer ******************************************** - - Determine number of UTF-16 u2s in the given UTF-8 buffer - - CAUTION: This function is unsafe for input that was not checked - by is_valid_utf! - - CAUTION: Use this function *only* when you want to convert an UTF-8 buffer - to an array of u2s (UTF-16) and want to know how many of them you will get. - All other uses of this function are probably wrong. - - IN: - buffer........points to first char in buffer - blength.......number of _bytes_ in the buffer - - OUT: - the number of u2s needed to hold this string in UTF-16 encoding. - There is _no_ terminating zero included in this count. - - NOTE: Unlike utf_get_number_of_u2s, this function never throws an - exception. - -*******************************************************************************/ - -u4 utf_get_number_of_u2s_for_buffer(const char *buffer, u4 blength) -{ - const char *endpos; /* points behind utf string */ - const char *utf_ptr; /* current position in utf text */ - u4 len = 0; /* number of unicode characters */ - - utf_ptr = buffer; - endpos = utf_ptr + blength; - - while (utf_ptr < endpos) { - len++; - /* next unicode character */ - utf_nextu2((char **)&utf_ptr); - } - - assert(utf_ptr == endpos); - - return len; -} - - -/* utf_get_number_of_u2s ******************************************************* - - Determine number of UTF-16 u2s in the utf string. - - CAUTION: This function is unsafe for input that was not checked - by is_valid_utf! - - CAUTION: Use this function *only* when you want to convert a utf string - to an array of u2s and want to know how many of them you will get. - All other uses of this function are probably wrong. - - IN: - u............utf string - - OUT: - the number of u2s needed to hold this string in UTF-16 encoding. - There is _no_ terminating zero included in this count. - XXX 0 if a NullPointerException has been thrown (see below) - -*******************************************************************************/ - -u4 utf_get_number_of_u2s(utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - u4 len = 0; /* number of unicode characters */ - - /* XXX this is probably not checked by most callers! Review this after */ - /* the invalid uses of this function have been eliminated */ - if (u == NULL) { - exceptions_throw_nullpointerexception(); - return 0; - } - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - len++; - /* next unicode character */ - utf_nextu2(&utf_ptr); - } - - if (utf_ptr != endpos) { - /* string ended abruptly */ - exceptions_throw_internalerror("Illegal utf8 string"); - return NULL; - } - - return len; -} - - -/* utf8_safe_number_of_u2s ***************************************************** - - Determine number of UTF-16 u2s needed for decoding the given UTF-8 string. - (For invalid UTF-8 the U+fffd replacement character will be counted.) - - This function is safe even for invalid UTF-8 strings. - - IN: - text..........zero-terminated(!) UTF-8 string (may be invalid) - must NOT be NULL - nbytes........strlen(text). (This is needed to completely emulate - the RI). - - OUT: - the number of u2s needed to hold this string in UTF-16 encoding. - There is _no_ terminating zero included in this count. - -*******************************************************************************/ - -s4 utf8_safe_number_of_u2s(const char *text, s4 nbytes) { - register const unsigned char *t; - register s4 byte; - register s4 len; - register const unsigned char *tlimit; - s4 byte1; - s4 byte2; - s4 byte3; - s4 value; - s4 skip; - - assert(text); - assert(nbytes >= 0); - - len = 0; - t = (const unsigned char *) text; - tlimit = t + nbytes; - - /* CAUTION: Keep this code in sync with utf8_safe_convert_to_u2s! */ - - while (1) { - byte = *t++; - - if (byte & 0x80) { - /* highest bit set, non-ASCII character */ - - if ((byte & 0xe0) == 0xc0) { - /* 2-byte: should be 110..... 10...... ? */ - - if ((*t++ & 0xc0) == 0x80) - ; /* valid 2-byte */ - else - t--; /* invalid */ - } - else if ((byte & 0xf0) == 0xe0) { - /* 3-byte: should be 1110.... 10...... 10...... */ - /* ^t */ - - if (t + 2 > tlimit) - return len + 1; /* invalid, stop here */ - - if ((*t++ & 0xc0) == 0x80) { - if ((*t++ & 0xc0) == 0x80) - ; /* valid 3-byte */ - else - t--; /* invalid */ - } - else - t--; /* invalid */ - } - else if ((byte & 0xf8) == 0xf0) { - /* 4-byte: should be 11110... 10...... 10...... 10...... */ - /* ^t */ - - if (t + 3 > tlimit) - return len + 1; /* invalid, stop here */ - - if (((byte1 = *t++) & 0xc0) == 0x80) { - if (((byte2 = *t++) & 0xc0) == 0x80) { - if (((byte3 = *t++) & 0xc0) == 0x80) { - /* valid 4-byte UTF-8? */ - value = ((byte & 0x07) << 18) - | ((byte1 & 0x3f) << 12) - | ((byte2 & 0x3f) << 6) - | ((byte3 & 0x3f) ); - - if (value > 0x10FFFF) - ; /* invalid */ - else if (value > 0xFFFF) - len += 1; /* we need surrogates */ - else - ; /* 16bit suffice */ - } - else - t--; /* invalid */ - } - else - t--; /* invalid */ - } - else - t--; /* invalid */ - } - else if ((byte & 0xfc) == 0xf8) { - /* invalid 5-byte */ - if (t + 4 > tlimit) - return len + 1; /* invalid, stop here */ - - skip = 4; - for (; skip && ((*t & 0xc0) == 0x80); --skip) - t++; - } - else if ((byte & 0xfe) == 0xfc) { - /* invalid 6-byte */ - if (t + 5 > tlimit) - return len + 1; /* invalid, stop here */ - - skip = 5; - for (; skip && ((*t & 0xc0) == 0x80); --skip) - t++; - } - else - ; /* invalid */ - } - else { - /* NUL */ - - if (byte == 0) - break; - - /* ASCII character, common case */ - } - - len++; - } - - return len; -} - - -/* utf8_safe_convert_to_u2s **************************************************** - - Convert the given UTF-8 string to UTF-16 into a pre-allocated buffer. - (Invalid UTF-8 will be replaced with the U+fffd replacement character.) - Use utf8_safe_number_of_u2s to determine the number of u2s to allocate. - - This function is safe even for invalid UTF-8 strings. - - IN: - text..........zero-terminated(!) UTF-8 string (may be invalid) - must NOT be NULL - nbytes........strlen(text). (This is needed to completely emulate - the RI). - buffer........a preallocated array of u2s to receive the decoded - string. Use utf8_safe_number_of_u2s to get the - required number of u2s for allocating this. - -*******************************************************************************/ - -#define UNICODE_REPLACEMENT 0xfffd - -void utf8_safe_convert_to_u2s(const char *text, s4 nbytes, u2 *buffer) { - register const unsigned char *t; - register s4 byte; - register const unsigned char *tlimit; - s4 byte1; - s4 byte2; - s4 byte3; - s4 value; - s4 skip; - - assert(text); - assert(nbytes >= 0); - - t = (const unsigned char *) text; - tlimit = t + nbytes; - - /* CAUTION: Keep this code in sync with utf8_safe_number_of_u2s! */ - - while (1) { - byte = *t++; - - if (byte & 0x80) { - /* highest bit set, non-ASCII character */ - - if ((byte & 0xe0) == 0xc0) { - /* 2-byte: should be 110..... 10...... */ - - if (((byte1 = *t++) & 0xc0) == 0x80) { - /* valid 2-byte UTF-8 */ - *buffer++ = ((byte & 0x1f) << 6) - | ((byte1 & 0x3f) ); - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else if ((byte & 0xf0) == 0xe0) { - /* 3-byte: should be 1110.... 10...... 10...... */ - - if (t + 2 > tlimit) { - *buffer++ = UNICODE_REPLACEMENT; - return; - } - - if (((byte1 = *t++) & 0xc0) == 0x80) { - if (((byte2 = *t++) & 0xc0) == 0x80) { - /* valid 3-byte UTF-8 */ - *buffer++ = ((byte & 0x0f) << 12) - | ((byte1 & 0x3f) << 6) - | ((byte2 & 0x3f) ); - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else if ((byte & 0xf8) == 0xf0) { - /* 4-byte: should be 11110... 10...... 10...... 10...... */ - - if (t + 3 > tlimit) { - *buffer++ = UNICODE_REPLACEMENT; - return; - } - - if (((byte1 = *t++) & 0xc0) == 0x80) { - if (((byte2 = *t++) & 0xc0) == 0x80) { - if (((byte3 = *t++) & 0xc0) == 0x80) { - /* valid 4-byte UTF-8? */ - value = ((byte & 0x07) << 18) - | ((byte1 & 0x3f) << 12) - | ((byte2 & 0x3f) << 6) - | ((byte3 & 0x3f) ); - - if (value > 0x10FFFF) { - *buffer++ = UNICODE_REPLACEMENT; - } - else if (value > 0xFFFF) { - /* we need surrogates */ - *buffer++ = 0xd800 | ((value >> 10) - 0x40); - *buffer++ = 0xdc00 | (value & 0x03ff); - } - else - *buffer++ = value; /* 16bit suffice */ - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else { - *buffer++ = UNICODE_REPLACEMENT; - t--; - } - } - else if ((byte & 0xfc) == 0xf8) { - if (t + 4 > tlimit) { - *buffer++ = UNICODE_REPLACEMENT; - return; - } - - skip = 4; - for (; skip && ((*t & 0xc0) == 0x80); --skip) - t++; - *buffer++ = UNICODE_REPLACEMENT; - } - else if ((byte & 0xfe) == 0xfc) { - if (t + 5 > tlimit) { - *buffer++ = UNICODE_REPLACEMENT; - return; - } - - skip = 5; - for (; skip && ((*t & 0xc0) == 0x80); --skip) - t++; - *buffer++ = UNICODE_REPLACEMENT; - } - else - *buffer++ = UNICODE_REPLACEMENT; - } - else { - /* NUL */ - - if (byte == 0) - break; - - /* ASCII character, common case */ - - *buffer++ = byte; - } - } -} - - -/* u2_utflength **************************************************************** - - Returns the utf length in bytes of a u2 array. - -*******************************************************************************/ - -u4 u2_utflength(u2 *text, u4 u2_length) -{ - u4 result_len = 0; /* utf length in bytes */ - u2 ch; /* current unicode character */ - u4 len; - - for (len = 0; len < u2_length; len++) { - /* next unicode character */ - ch = *text++; - - /* determine bytes required to store unicode character as utf */ - if (ch && (ch < 0x80)) - result_len++; - else if (ch < 0x800) - result_len += 2; - else - result_len += 3; - } - - return result_len; -} - - -/* utf_copy ******************************************************************** - - Copy the given utf string byte-for-byte to a buffer. - - IN: - buffer.......the buffer - u............the utf string - -*******************************************************************************/ - -void utf_copy(char *buffer, utf *u) -{ - /* our utf strings are zero-terminated (done by utf_new) */ - MCOPY(buffer, u->text, char, u->blength + 1); -} - - -/* utf_cat ********************************************************************* - - Append the given utf string byte-for-byte to a buffer. - - IN: - buffer.......the buffer - u............the utf string - -*******************************************************************************/ - -void utf_cat(char *buffer, utf *u) -{ - /* our utf strings are zero-terminated (done by utf_new) */ - MCOPY(buffer + strlen(buffer), u->text, char, u->blength + 1); -} - - -/* utf_copy_classname ********************************************************** - - Copy the given utf classname byte-for-byte to a buffer. - '/' is replaced by '.' - - IN: - buffer.......the buffer - u............the utf string - -*******************************************************************************/ - -void utf_copy_classname(char *buffer, utf *u) -{ - char *bufptr; - char *srcptr; - char *endptr; - char ch; - - bufptr = buffer; - srcptr = u->text; - endptr = UTF_END(u) + 1; /* utfs are zero-terminared by utf_new */ - - while (srcptr != endptr) { - ch = *srcptr++; - if (ch == '/') - ch = '.'; - *bufptr++ = ch; - } -} - - -/* utf_cat ********************************************************************* - - Append the given utf classname byte-for-byte to a buffer. - '/' is replaced by '.' - - IN: - buffer.......the buffer - u............the utf string - -*******************************************************************************/ - -void utf_cat_classname(char *buffer, utf *u) -{ - utf_copy_classname(buffer + strlen(buffer), u); -} - -/* utf_display_printable_ascii ************************************************* - - Write utf symbol to stdout (for debugging purposes). - Non-printable and non-ASCII characters are printed as '?'. - -*******************************************************************************/ - -void utf_display_printable_ascii(utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - - if (u == NULL) { - printf("NULL"); - fflush(stdout); - return; - } - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - /* read next unicode character */ - - u2 c = utf_nextu2(&utf_ptr); - - if ((c >= 32) && (c <= 127)) - printf("%c", c); - else - printf("?"); - } - - fflush(stdout); -} - - -/* utf_display_printable_ascii_classname *************************************** - - Write utf symbol to stdout with `/' converted to `.' (for debugging - purposes). - Non-printable and non-ASCII characters are printed as '?'. - -*******************************************************************************/ - -void utf_display_printable_ascii_classname(utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - - if (u == NULL) { - printf("NULL"); - fflush(stdout); - return; - } - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - /* read next unicode character */ - - u2 c = utf_nextu2(&utf_ptr); - - if (c == '/') - c = '.'; - - if ((c >= 32) && (c <= 127)) - printf("%c", c); - else - printf("?"); - } - - fflush(stdout); -} - - -/* utf_sprint_convert_to_latin1 ************************************************ - - Write utf symbol into c-string (for debugging purposes). - Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield - invalid results. - -*******************************************************************************/ - -void utf_sprint_convert_to_latin1(char *buffer, utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - u2 pos = 0; /* position in c-string */ - - if (!u) { - strcpy(buffer, "NULL"); - return; - } - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) - /* copy next unicode character */ - buffer[pos++] = utf_nextu2(&utf_ptr); - - /* terminate string */ - buffer[pos] = '\0'; -} - - -/* utf_sprint_convert_to_latin1_classname ************************************** - - Write utf symbol into c-string with `/' converted to `.' (for debugging - purposes). - Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield - invalid results. - -*******************************************************************************/ - -void utf_sprint_convert_to_latin1_classname(char *buffer, utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - u2 pos = 0; /* position in c-string */ - - if (!u) { - strcpy(buffer, "NULL"); - return; - } - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - /* copy next unicode character */ - u2 c = utf_nextu2(&utf_ptr); - if (c == '/') c = '.'; - buffer[pos++] = c; - } - - /* terminate string */ - buffer[pos] = '\0'; -} - - -/* utf_strcat_convert_to_latin1 ************************************************ - - Like libc strcat, but uses an utf8 string. - Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield - invalid results. - -*******************************************************************************/ - -void utf_strcat_convert_to_latin1(char *buffer, utf *u) -{ - utf_sprint_convert_to_latin1(buffer + strlen(buffer), u); -} - - -/* utf_strcat_convert_to_latin1_classname ************************************** - - Like libc strcat, but uses an utf8 string. - Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield - invalid results. - -*******************************************************************************/ - -void utf_strcat_convert_to_latin1_classname(char *buffer, utf *u) -{ - utf_sprint_convert_to_latin1_classname(buffer + strlen(buffer), u); -} - - -/* utf_fprint_printable_ascii ************************************************** - - Write utf symbol into file. - Non-printable and non-ASCII characters are printed as '?'. - -*******************************************************************************/ - -void utf_fprint_printable_ascii(FILE *file, utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - - if (!u) - return; - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - /* read next unicode character */ - u2 c = utf_nextu2(&utf_ptr); - - if (c >= 32 && c <= 127) fprintf(file, "%c", c); - else fprintf(file, "?"); - } -} - - -/* utf_fprint_printable_ascii_classname **************************************** - - Write utf symbol into file with `/' converted to `.'. - Non-printable and non-ASCII characters are printed as '?'. - -*******************************************************************************/ - -void utf_fprint_printable_ascii_classname(FILE *file, utf *u) -{ - char *endpos; /* points behind utf string */ - char *utf_ptr; /* current position in utf text */ - - if (!u) - return; - - endpos = UTF_END(u); - utf_ptr = u->text; - - while (utf_ptr < endpos) { - /* read next unicode character */ - u2 c = utf_nextu2(&utf_ptr); - if (c == '/') c = '.'; - - if (c >= 32 && c <= 127) fprintf(file, "%c", c); - else fprintf(file, "?"); - } -} - - -/* is_valid_utf **************************************************************** - - Return true if the given string is a valid UTF-8 string. - - utf_ptr...points to first character - end_pos...points after last character - -*******************************************************************************/ - -/* static unsigned long min_codepoint[6] = {0,1L<<7,1L<<11,1L<<16,1L<<21,1L<<26}; */ - -bool is_valid_utf(char *utf_ptr, char *end_pos) -{ - int bytes; - int len,i; - char c; - unsigned long v; - - if (end_pos < utf_ptr) return false; - bytes = end_pos - utf_ptr; - while (bytes--) { - c = *utf_ptr++; - - if (!c) return false; /* 0x00 is not allowed */ - if ((c & 0x80) == 0) continue; /* ASCII */ - - if ((c & 0xe0) == 0xc0) len = 1; /* 110x xxxx */ - else if ((c & 0xf0) == 0xe0) len = 2; /* 1110 xxxx */ - else if ((c & 0xf8) == 0xf0) len = 3; /* 1111 0xxx */ - else if ((c & 0xfc) == 0xf8) len = 4; /* 1111 10xx */ - else if ((c & 0xfe) == 0xfc) len = 5; /* 1111 110x */ - else return false; /* invalid leading byte */ - - if (len > 2) return false; /* Java limitation */ - - v = (unsigned long)c & (0x3f >> len); - - if ((bytes -= len) < 0) return false; /* missing bytes */ - - for (i = len; i--; ) { - c = *utf_ptr++; - if ((c & 0xc0) != 0x80) /* 10xx xxxx */ - return false; - v = (v << 6) | (c & 0x3f); - } - - if (v == 0) { - if (len != 1) return false; /* Java special */ - - } else { - /* Sun Java seems to allow overlong UTF-8 encodings */ - - /* if (v < min_codepoint[len]) */ - /* XXX throw exception? */ - } - - /* surrogates in UTF-8 seem to be allowed in Java classfiles */ - /* if (v >= 0xd800 && v <= 0xdfff) return false; */ /* surrogates */ - - /* even these seem to be allowed */ - /* if (v == 0xfffe || v == 0xffff) return false; */ /* invalid codepoints */ - } - - return true; -} - - -/* is_valid_name *************************************************************** - - Return true if the given string may be used as a class/field/method - name. (Currently this only disallows empty strings and control - characters.) - - NOTE: The string is assumed to have passed is_valid_utf! - - utf_ptr...points to first character - end_pos...points after last character - -*******************************************************************************/ - -bool is_valid_name(char *utf_ptr, char *end_pos) -{ - if (end_pos <= utf_ptr) return false; /* disallow empty names */ - - while (utf_ptr < end_pos) { - unsigned char c = *utf_ptr++; - - if (c < 0x20) return false; /* disallow control characters */ - if (c == 0xc0 && (unsigned char) *utf_ptr == 0x80) /* disallow zero */ - return false; - } - - return true; -} - -bool is_valid_name_utf(utf *u) -{ - return is_valid_name(u->text, UTF_END(u)); -} - - -/* utf_show ******************************************************************** - - Writes the utf symbols in the utfhash to stdout and displays the - number of external hash chains grouped according to the chainlength - (for debugging purposes). - -*******************************************************************************/ - -#if !defined(NDEBUG) -void utf_show(void) -{ - -#define CHAIN_LIMIT 20 /* limit for seperated enumeration */ - - u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */ - u4 max_chainlength = 0; /* maximum length of the chains */ - u4 sum_chainlength = 0; /* sum of the chainlengths */ - u4 beyond_limit = 0; /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */ - u4 i; - - printf("UTF-HASH:\n"); - - /* show element of utf-hashtable */ - - for (i = 0; i < hashtable_utf->size; i++) { - utf *u = hashtable_utf->ptr[i]; - - if (u) { - printf("SLOT %d: ", (int) i); - - while (u) { - printf("'"); - utf_display_printable_ascii(u); - printf("' "); - u = u->hashlink; - } - printf("\n"); - } - } - - printf("UTF-HASH: %d slots for %d entries\n", - (int) hashtable_utf->size, (int) hashtable_utf->entries ); - - if (hashtable_utf->entries == 0) - return; - - printf("chains:\n chainlength number of chains %% of utfstrings\n"); - - for (i=0;isize; i++) { - - utf *u = (utf*) hashtable_utf->ptr[i]; - u4 chain_length = 0; - - /* determine chainlength */ - while (u) { - u = u->hashlink; - chain_length++; - } - - /* update sum of all chainlengths */ - sum_chainlength+=chain_length; - - /* determine the maximum length of the chains */ - if (chain_length>max_chainlength) - max_chainlength = chain_length; - - /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */ - if (chain_length>=CHAIN_LIMIT) { - beyond_limit+=chain_length; - chain_length=CHAIN_LIMIT-1; - } - - /* update number of hashchains of current length */ - chain_count[chain_length]++; - } - - /* display results */ - for (i=1;ientries)); - - printf(" >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/hashtable_utf->entries); - - - printf("max. chainlength:%5d\n",max_chainlength); - - /* avg. chainlength = sum of chainlengths / number of chains */ - printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (hashtable_utf->size-chain_count[0])); -} -#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: - */ diff --git a/src/vm/utf8.h b/src/vm/utf8.h deleted file mode 100644 index a4f2e106c..000000000 --- a/src/vm/utf8.h +++ /dev/null @@ -1,267 +0,0 @@ -/* src/vm/utf8.h - utf8 string functions - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - Edwin Steiner - - $Id: utf8.h 6244 2006-12-27 15:15:31Z twisti $ - -*/ - - -#ifndef _UTF_H -#define _UTF_H - -#include "config.h" - -#include - -/* forward typedefs ***********************************************************/ - -typedef struct utf utf; - -#include "vm/types.h" -#include "vm/global.h" - - -/* data structure for utf8 symbols ********************************************/ - -struct utf { - utf *hashlink; /* link for external hash chain */ - s4 blength; /* text length in bytes */ - char *text; /* pointer to text */ -}; - -/* to determine the end of utf strings */ - -#define UTF_END(u) ((char *) u->text + u->blength) - - -/* utf-symbols for pointer comparison of frequently used strings **************/ - -extern utf *utf_java_lang_Object; - -extern utf *utf_java_lang_Class; -extern utf *utf_java_lang_ClassLoader; -extern utf *utf_java_lang_Cloneable; -extern utf *utf_java_lang_SecurityManager; -extern utf *utf_java_lang_String; -extern utf *utf_java_lang_System; -extern utf *utf_java_lang_ThreadGroup; -extern utf *utf_java_io_Serializable; - -extern utf *utf_java_lang_Throwable; -extern utf *utf_java_lang_Error; -extern utf *utf_java_lang_LinkageError; -extern utf *utf_java_lang_NoClassDefFoundError; -extern utf *utf_java_lang_OutOfMemoryError; -extern utf *utf_java_lang_VirtualMachineError; - -#if defined(ENABLE_JAVASE) -extern utf *utf_java_lang_AbstractMethodError; -extern utf *utf_java_lang_NoSuchMethodError; -#endif - -#if defined(WITH_CLASSPATH_GNU) -extern utf *utf_java_lang_VMThrowable; -#endif - -extern utf *utf_java_lang_Exception; -extern utf *utf_java_lang_ClassCastException; -extern utf *utf_java_lang_ClassNotFoundException; -extern utf *utf_java_lang_IllegalArgumentException; -extern utf *utf_java_lang_IllegalMonitorStateException; - -extern utf *utf_java_lang_NullPointerException; - -#if defined(ENABLE_JAVASE) -extern utf* utf_java_lang_Void; -#endif - -extern utf* utf_java_lang_Boolean; -extern utf* utf_java_lang_Byte; -extern utf* utf_java_lang_Character; -extern utf* utf_java_lang_Short; -extern utf* utf_java_lang_Integer; -extern utf* utf_java_lang_Long; -extern utf* utf_java_lang_Float; -extern utf* utf_java_lang_Double; - -#if defined(ENABLE_JAVASE) -extern utf *utf_java_lang_StackTraceElement; -extern utf *utf_java_lang_reflect_Constructor; -extern utf *utf_java_lang_reflect_Field; -extern utf *utf_java_lang_reflect_Method; -extern utf *utf_java_util_Vector; -#endif - -extern utf *utf_InnerClasses; -extern utf *utf_ConstantValue; -extern utf *utf_Code; -extern utf *utf_Exceptions; -extern utf *utf_LineNumberTable; -extern utf *utf_SourceFile; - -#if defined(ENABLE_JAVASE) -extern utf *utf_EnclosingMethod; -extern utf *utf_Signature; -extern utf *utf_RuntimeVisibleAnnotations; -extern utf *utf_StackMapTable; -#endif - -extern utf *utf_init; -extern utf *utf_clinit; -extern utf *utf_clone; -extern utf *utf_finalize; -extern utf *utf_run; - -extern utf *utf_add; -extern utf *utf_remove; -extern utf *utf_addThread; -extern utf *utf_removeThread; -extern utf *utf_put; -extern utf *utf_get; -extern utf *utf_value; - -extern utf *utf_fillInStackTrace; -extern utf *utf_getSystemClassLoader; -extern utf *utf_loadClass; -extern utf *utf_printStackTrace; - -extern utf *utf_Z; -extern utf *utf_B; -extern utf *utf_C; -extern utf *utf_S; -extern utf *utf_I; -extern utf *utf_J; -extern utf *utf_F; -extern utf *utf_D; - -extern utf *utf_void__void; -extern utf *utf_boolean__void; -extern utf *utf_byte__void; -extern utf *utf_char__void; -extern utf *utf_short__void; -extern utf *utf_int__void; -extern utf *utf_long__void; -extern utf *utf_float__void; -extern utf *utf_double__void; - -extern utf *utf_void__java_lang_ClassLoader; -extern utf *utf_void__java_lang_Object; -extern utf *utf_void__java_lang_Throwable; -extern utf *utf_java_lang_Object__java_lang_Object; -extern utf *utf_java_lang_String__void; -extern utf *utf_java_lang_String__java_lang_Class; -extern utf *utf_java_lang_Thread__V; -extern utf *utf_java_lang_Throwable__void; - -extern utf *utf_not_named_yet; -extern utf *utf_null; -extern utf *array_packagename; - - -/* function prototypes ********************************************************/ - -/* initialize the utf8 subsystem */ -bool utf8_init(void); - -u4 utf_hashkey(const char *text, u4 length); -u4 utf_full_hashkey(const char *text, u4 length); - -/* determine hashkey of a unicode-symbol */ -u4 unicode_hashkey(u2 *text, u2 length); - -/* create new utf-symbol */ -utf *utf_new(const char *text, u2 length); - -/* make utf symbol from u2 array */ -utf *utf_new_u2(u2 *unicodedata, u4 unicodelength, bool isclassname); - -utf *utf_new_char(const char *text); -utf *utf_new_char_classname(const char *text); - -/* get number of bytes */ -u4 utf_bytes(utf *u); - -/* get next unicode character of a utf-string */ -u2 utf_nextu2(char **utf); - -/* get (number of) unicode characters of a utf string (safe) */ -s4 utf8_safe_number_of_u2s(const char *text, s4 nbytes); -void utf8_safe_convert_to_u2s(const char *text, s4 nbytes, u2 *buffer); - -/* get (number of) unicode characters of a utf string (UNSAFE!) */ -u4 utf_get_number_of_u2s(utf *u); -u4 utf_get_number_of_u2s_for_buffer(const char *buffer, u4 blength); - -/* determine utf length in bytes of a u2 array */ -u4 u2_utflength(u2 *text, u4 u2_length); - -void utf_copy(char *buffer, utf *u); -void utf_cat(char *buffer, utf *u); -void utf_copy_classname(char *buffer, utf *u); -void utf_cat_classname(char *buffer, utf *u); - -/* write utf symbol to file/buffer */ -void utf_display_printable_ascii(utf *u); -void utf_display_printable_ascii_classname(utf *u); - -void utf_sprint_convert_to_latin1(char *buffer, utf *u); -void utf_sprint_convert_to_latin1_classname(char *buffer, utf *u); - -void utf_strcat_convert_to_latin1(char *buffer, utf *u); -void utf_strcat_convert_to_latin1_classname(char *buffer, utf *u); - -void utf_fprint_printable_ascii(FILE *file, utf *u); -void utf_fprint_printable_ascii_classname(FILE *file, utf *u); - -/* check if a UTF-8 string is valid */ -bool is_valid_utf(char *utf_ptr, char *end_pos); - -/* check if a UTF-8 string may be used as a class/field/method name */ -bool is_valid_name(char *utf_ptr, char *end_pos); -bool is_valid_name_utf(utf *u); - -/* show utf-table */ -void utf_show(void); - -#endif /* _UTF_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: - */ diff --git a/src/vm/vm.c b/src/vm/vm.c index 4997ee10e..69aded785 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -42,25 +42,27 @@ #include "mm/gc-common.h" #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" +#include "native/include/java_lang_String.h" #if defined(ENABLE_THREADS) # include "threads/native/threads.h" #endif -#include "vm/classcache.h" +#include "toolbox/logging.h" + +#include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/finalizer.h" #include "vm/global.h" #include "vm/initialize.h" -#include "vm/options.h" #include "vm/properties.h" -#include "vm/rt-timing.h" #include "vm/signallocal.h" #include "vm/stringlocal.h" -#include "vm/suck.h" #include "vm/vm.h" + #include "vm/jit/jit.h" #include "vm/jit/md.h" #include "vm/jit/asmpart.h" @@ -71,6 +73,10 @@ #include "vm/jit/optimizing/recompile.h" +#include "vmcore/classcache.h" +#include "vmcore/options.h" +#include "vmcore/suck.h" + #if defined(ENABLE_JVMTI) # include "native/jvmti/cacaodbg.h" #endif @@ -565,7 +571,7 @@ static void version(bool opt_exit) puts("java version \""JAVA_VERSION"\""); puts("CACAO version "VERSION""); - puts("Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,"); + puts("Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,"); puts("C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,"); puts("E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,"); puts("J. Wenninger, Institut f. Computersprachen - TU Wien\n"); @@ -1495,7 +1501,7 @@ bool vm_create(JavaVMInitArgs *vm_args) if (!finalizer_init()) throw_main_exception_exit(); - /* install architecture dependent signal handler used for exceptions */ + /* install architecture dependent signal handlers */ signal_init(); @@ -1564,7 +1570,12 @@ bool vm_create(JavaVMInitArgs *vm_args) if (!recompile_init()) throw_main_exception_exit(); - + + /* start the signal handler thread */ + + if (!signal_start_thread()) + throw_main_exception_exit(); + /* finally, start the finalizer thread */ if (!finalizer_start_thread()) @@ -1614,15 +1625,15 @@ bool vm_create(JavaVMInitArgs *vm_args) void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) { - utf *mainutf; - classinfo *mainclass; - methodinfo *m; - java_objectarray *oa; - s4 oalength; - utf *u; - java_lang_String *s; - s4 status; - s4 i; + utf *mainutf; + classinfo *mainclass; + methodinfo *m; + java_objectarray *oa; + s4 oalength; + utf *u; + java_objectheader *s; + s4 status; + s4 i; #if !defined(NDEBUG) if (compileall) { @@ -1654,16 +1665,14 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) mainutf = utf_new_char(mainstring); #if defined(ENABLE_JAVAME_CLDC1_1) - if (!(mainclass = load_class_bootstrap(mainutf))) - throw_main_exception_exit(); + mainclass = load_class_bootstrap(mainutf); #else - if (!(mainclass = load_class_from_sysloader(mainutf))) - throw_main_exception_exit(); + mainclass = load_class_from_sysloader(mainutf); #endif /* error loading class */ - if ((*exceptionptr != NULL) || (mainclass == NULL)) + if ((exceptions_get_exception() != NULL) || (mainclass == NULL)) throw_main_exception_exit(); if (!link_class(mainclass)) @@ -1684,10 +1693,11 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) /* there is no main method or it isn't static */ if ((m == NULL) || !(m->flags & ACC_STATIC)) { - *exceptionptr = NULL; + exceptions_clear_exception(); + exceptions_throw_nosuchmethoderror(mainclass, + utf_new_char("main"), + utf_new_char("([Ljava/lang/String;)V")); - *exceptionptr = - new_exception_message(string_java_lang_NoSuchMethodError, "main"); throw_main_exception_exit(); } @@ -1701,7 +1711,7 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) u = utf_new_char(vm_args->options[opt_index + i].optionString); s = javastring_new(u); - oa->data[i] = (java_objectheader *) s; + oa->data[i] = s; } #ifdef TYPEINFO_DEBUG_TEST @@ -1899,8 +1909,6 @@ void vm_exit_handler(void) #endif } - mem_usagelog(1); - if (opt_getcompilingtime) print_times(); #endif /* defined(ENABLE_STATISTICS) */ @@ -2080,7 +2088,7 @@ static void vm_compile_all(void) /* print out exception and cause */ - exceptions_print_exception(*exceptionptr); + exceptions_print_current_exception(); /* goto next class */ @@ -2104,7 +2112,7 @@ static void vm_compile_all(void) /* print out exception and cause */ - exceptions_print_exception(*exceptionptr); + exceptions_print_current_exception(); } } } @@ -2149,17 +2157,9 @@ static void vm_compile_method(void) false); } - if (m == NULL) { - char message[MAXLOGTEXT]; - sprintf(message, "%s%s", opt_method, - opt_signature ? opt_signature : ""); - - *exceptionptr = - new_exception_message(string_java_lang_NoSuchMethodException, - message); - - throw_main_exception_exit(); - } + if (m == NULL) + vm_abort("vm_compile_method: java.lang.NoSuchMethodException: %s.%s", + opt_method, opt_signature ? opt_signature : ""); jit_compile(m); } diff --git a/src/vm/zip.c b/src/vm/zip.c deleted file mode 100644 index 233c1a515..000000000 --- a/src/vm/zip.c +++ /dev/null @@ -1,499 +0,0 @@ -/* src/vm/zip.c - ZIP file handling for bootstrap classloader - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Edwin Steiner - - $Id: zip.c 4888 2006-05-06 00:11:18Z edwin $ - -*/ - - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "vm/types.h" - -#include "mm/memory.h" -#include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/suck.h" -#include "vm/utf8.h" -#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 - - -/* 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; -}; - - -/* 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 */ - - if ((htzfe = zip_find(lce, c->name)) == 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) - assert(0); - - /* decompress the file into buffer */ - - err = inflate(&zs, Z_SYNC_FLUSH); - - if ((err != Z_STREAM_END) && (err != Z_OK)) - assert(0); - - /* finish this inflate run */ - - if (inflateEnd(&zs) != Z_OK) - assert(0); - break; - - case 0: - /* uncompressed file, just copy the data */ - MCOPY(outdata, indata, u1, htzfe->compressedsize); - break; - - default: - assert(0); - } - - /* allocate classbuffer */ - - cb = NEW(classbuffer); - - cb->class = 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: - */ diff --git a/src/vm/zip.h b/src/vm/zip.h deleted file mode 100644 index babca6d3b..000000000 --- a/src/vm/zip.h +++ /dev/null @@ -1,83 +0,0 @@ -/* src/vm/zip.c - ZIP file handling for bootstrap classloader - - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien - - 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. - - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - - $Id: zip.h 4357 2006-01-22 23:33:38Z twisti $ - -*/ - - -#ifndef _ZIP_H -#define _ZIP_H - -#include "config.h" -#include "vm/types.h" - -#include "vm/class.h" -#include "vm/global.h" -#include "vm/hashtable.h" -#include "vm/loader.h" -#include "vm/suck.h" -#include "vm/utf8.h" - - -/* 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 ********************************************************/ - -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); - -#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: - */ diff --git a/src/vmcore/.cvsignore b/src/vmcore/.cvsignore new file mode 100644 index 000000000..8f719f94e --- /dev/null +++ b/src/vmcore/.cvsignore @@ -0,0 +1,9 @@ +*.a +*.o +*.la +*.lo +.deps +.libs +Makefile +Makefile.in +TAGS diff --git a/src/vmcore/Makefile.am b/src/vmcore/Makefile.am new file mode 100644 index 000000000..7c5e353a6 --- /dev/null +++ b/src/vmcore/Makefile.am @@ -0,0 +1,101 @@ +## src/vmcore/Makefile.am +## +## Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel, +## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, +## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, +## J. Wenninger, Institut f. Computersprachen - TU Wien +## +## 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. +## +## $Id: Makefile.am 6216 2006-12-18 18:21:37Z twisti $ + +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR) -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR)/$(OS_DIR) + +LIBS = + +if ENABLE_JAVASE +ANNOTATION_SOURCES = \ + annotation.c \ + annotation.h + +STACKMAP_SOURCES = \ + stackmap.c \ + stackmap.h +endif + +if ENABLE_RT_TIMING +RT_TIMING_SOURCES = \ + rt-timing.c \ + rt-timing.h +endif + +if ENABLE_STATISTICS +STATISTICS_SOURCES = \ + statistics.c \ + statistics.h +endif + +if ENABLE_ZLIB +ZLIB_SOURCES = \ + zip.c \ + zip.h +endif + +noinst_LTLIBRARIES = \ + libvmcore.la + +libvmcore_la_SOURCES = \ + $(ANNOTATION_SOURCES) \ + class.c \ + class.h \ + classcache.c \ + classcache.h \ + descriptor.c \ + descriptor.h \ + field.c \ + field.h \ + linker.c \ + linker.h \ + loader.c \ + loader.h \ + method.c \ + method.h \ + options.c \ + options.h \ + references.h \ + resolve.c \ + resolve.h \ + $(RT_TIMING_SOURCES) \ + $(STACKMAP_SOURCES) \ + $(STATISTICS_SOURCES) \ + suck.c \ + suck.h \ + utf8.c \ + utf8.h \ + $(ZLIB_SOURCES) + + +## Local variables: +## mode: Makefile +## indent-tabs-mode: t +## c-basic-offset: 4 +## tab-width: 8 +## compile-command: "automake --add-missing" +## End: diff --git a/src/vmcore/annotation.c b/src/vmcore/annotation.c new file mode 100644 index 000000000..fa2fb11bd --- /dev/null +++ b/src/vmcore/annotation.c @@ -0,0 +1,178 @@ +/* src/vmcore/annotation.c - class annotations + + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, + R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, + C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, + Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vmcore/annotation.h" +#include "vmcore/class.h" +#include "vmcore/suck.h" + + +/* annotation_load_attribute_runtimevisibleannotations ************************* + + RuntimeVisibleAnnotations_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 num_annotations; + annotation annotations[num_annotations]; + } + + annotation { + u2 type_index; + u2 num_element_value_pairs; + { + u2 element_name_index; + element_value element; + } element_value_pairs[num_element_value_pairs]; + } + + element_value { + u1 tag; + union { + u2 const_value_index; + { + u2 type_name_index; + u2 const_name_index; + } enum_const_value; + u2 class_info_index; + annotation annotation_value; + { + u2 num_values; + element_value values[num_values]; + } array_value; + } value; + } + +*******************************************************************************/ + +bool annotation_load_attribute_runtimevisibleannotations(classbuffer *cb) +{ + classinfo *c; + u4 attribute_length; + u2 num_annotations; + annotation_t *aa; + element_value_t *element_value; + u2 type_index; + u2 num_element_value_pairs; + u2 element_name_index; + u4 i, j; + + /* get classinfo */ + + c = cb->class; + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* attribute_length */ + + attribute_length = suck_u4(cb); + + if (!suck_check_classbuffer_size(cb, attribute_length)) + return false; + + /* get number of annotations */ + + num_annotations = suck_u2(cb); + + printf("num_annotations: %d\n", num_annotations); + + /* allocate annotations-array */ + + aa = MNEW(annotation_t, num_annotations); + + /* parse all annotations */ + + for (i = 0; i < num_annotations; i++) { + /* get annotation type */ + + type_index = suck_u2(cb); + + if (!(aa[i].type = class_getconstant(c, type_index, CONSTANT_Utf8))) + return false; + + printf("type: "); + utf_display_printable_ascii(aa[i].type); + printf("\n"); + + /* get number of element values */ + + num_element_value_pairs = suck_u2(cb); + + printf("num_element_value_pairs: %d\n", num_element_value_pairs); + + element_value = MNEW(element_value_t, num_element_value_pairs); + + /* parse all element values */ + + for (j = 0; j < num_element_value_pairs; j++) { + /* get element name */ + + element_name_index = suck_u2(cb); + + if (!(element_value[j].name = + class_getconstant(c, element_name_index, CONSTANT_Utf8))) + return false; + + /* get element tag */ + + element_value[i].tag = suck_u1(cb); + } + + /* store element value data */ + + aa[i].element_valuescount = num_element_value_pairs; + aa[i].element_values = element_value; + } + + /* store annotation variables */ + + c->runtimevisibleannotationscount = num_annotations; + c->runtimevisibleannotations = aa; + + return true; +} + + +/* + * 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: + */ diff --git a/src/vmcore/annotation.h b/src/vmcore/annotation.h new file mode 100644 index 000000000..cafa190f7 --- /dev/null +++ b/src/vmcore/annotation.h @@ -0,0 +1,83 @@ +/* src/vmcore/annotation.h - class annotations + + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, + R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, + C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, + Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ + +*/ + + +#ifndef _ANNOTATION_H +#define _ANNOTATION_H + +/* forward typedefs ***********************************************************/ + +typedef struct annotation_t annotation_t; +typedef struct element_value_t element_value_t; + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vmcore/loader.h" +#include "vmcore/utf8.h" + + +/* annotation *****************************************************************/ + +struct annotation_t { + utf *type; + s4 element_valuescount; + element_value_t *element_values; +}; + + +/* element_value **************************************************************/ + +struct element_value_t { + utf *name; + u1 tag; +}; + + +/* function prototypes ********************************************************/ + +bool annotation_load_attribute_runtimevisibleannotations(classbuffer *cb); + +#endif /* _ANNOTATION_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: + */ diff --git a/src/vmcore/class.c b/src/vmcore/class.c new file mode 100644 index 000000000..d370cebec --- /dev/null +++ b/src/vmcore/class.c @@ -0,0 +1,1676 @@ +/* src/vmcore/class.c - class related functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: class.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "toolbox/logging.h" + +#include "vm/exceptions.h" +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/classcache.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#include "vmcore/suck.h" +#include "vmcore/utf8.h" + + +/* global variables ***********************************************************/ + +list unlinkedclasses; /* this is only used for eager class */ + /* loading */ + + +/* frequently used classes ****************************************************/ + +/* important system classes */ + +classinfo *class_java_lang_Object; +classinfo *class_java_lang_Class; +classinfo *class_java_lang_ClassLoader; +classinfo *class_java_lang_Cloneable; +classinfo *class_java_lang_SecurityManager; +classinfo *class_java_lang_String; +classinfo *class_java_lang_System; +classinfo *class_java_lang_Thread; +classinfo *class_java_lang_ThreadGroup; +classinfo *class_java_lang_VMSystem; +classinfo *class_java_lang_VMThread; +classinfo *class_java_io_Serializable; + + +/* system exception classes required in cacao */ + +classinfo *class_java_lang_Throwable; +classinfo *class_java_lang_Error; +classinfo *class_java_lang_LinkageError; +classinfo *class_java_lang_NoClassDefFoundError; +classinfo *class_java_lang_OutOfMemoryError; +classinfo *class_java_lang_VirtualMachineError; + +#if defined(WITH_CLASSPATH_GNU) +classinfo *class_java_lang_VMThrowable; +#endif + +classinfo *class_java_lang_Exception; +classinfo *class_java_lang_ClassCastException; +classinfo *class_java_lang_ClassNotFoundException; + +#if defined(ENABLE_JAVASE) +classinfo *class_java_lang_Void; +#endif +classinfo *class_java_lang_Boolean; +classinfo *class_java_lang_Byte; +classinfo *class_java_lang_Character; +classinfo *class_java_lang_Short; +classinfo *class_java_lang_Integer; +classinfo *class_java_lang_Long; +classinfo *class_java_lang_Float; +classinfo *class_java_lang_Double; + + +/* some runtime exception */ + +classinfo *class_java_lang_NullPointerException; + + +/* some classes which may be used more often */ + +#if defined(ENABLE_JAVASE) +classinfo *class_java_lang_StackTraceElement; +classinfo *class_java_lang_reflect_Constructor; +classinfo *class_java_lang_reflect_Field; +classinfo *class_java_lang_reflect_Method; +classinfo *class_java_security_PrivilegedAction; +classinfo *class_java_util_Vector; + +classinfo *arrayclass_java_lang_Object; +#endif + + +/* pseudo classes for the typechecker */ + +classinfo *pseudo_class_Arraystub; +classinfo *pseudo_class_Null; +classinfo *pseudo_class_New; + + +/* class_set_packagename ******************************************************* + + Derive the package name from the class name and store it in the struct. + +*******************************************************************************/ + +void class_set_packagename(classinfo *c) +{ + char *p = UTF_END(c->name) - 1; + char *start = c->name->text; + + /* set the package name */ + /* classes in the unnamed package keep packagename == NULL */ + + if (c->name->text[0] == '[') { + /* set packagename of arrays to the element's package */ + + for (; *start == '['; start++); + + /* skip the 'L' in arrays of references */ + if (*start == 'L') + start++; + + for (; (p > start) && (*p != '/'); --p); + + c->packagename = utf_new(start, p - start); + + } else { + for (; (p > start) && (*p != '/'); --p); + + c->packagename = utf_new(start, p - start); + } +} + + +/* class_create_classinfo ****************************************************** + + Create a new classinfo struct. The class name is set to the given utf *, + most other fields are initialized to zero. + + Note: classname may be NULL. In this case a not-yet-named classinfo is + created. The name must be filled in later and class_set_packagename + must be called after that. + +*******************************************************************************/ + +classinfo *class_create_classinfo(utf *classname) +{ + classinfo *c; + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + size_classinfo += sizeof(classinfo); +#endif + + /* we use a safe name for temporarily unnamed classes */ + if (!classname) + classname = utf_not_named_yet; + +#if !defined(NDEBUG) + if (initverbose) + log_message_utf("Creating class: ", classname); +#endif + + /* GCNEW_UNCOLLECTABLE clears the allocated memory */ + + c = GCNEW_UNCOLLECTABLE(classinfo, 1); + /*c=NEW(classinfo);*/ + c->name = classname; + + /* Set the header.vftbl of all loaded classes to the one of + java.lang.Class, so Java code can use a class as object. */ + + if (class_java_lang_Class) + if (class_java_lang_Class->vftbl) + c->object.header.vftbl = class_java_lang_Class->vftbl; + + if (classname != utf_not_named_yet) + class_set_packagename(c); + +#if defined(ENABLE_THREADS) + lock_init_object_lock(&c->object.header); +#endif + + return c; +} + + +/* class_postset_header_vftbl ************************************************** + + Set the header.vftbl of all classes created before java.lang.Class + was linked. This is necessary that Java code can use a class as + object. + +*******************************************************************************/ + +void class_postset_header_vftbl(void) +{ + classinfo *c; + u4 slot; + classcache_name_entry *nmen; + classcache_class_entry *clsen; + + assert(class_java_lang_Class); + + for (slot = 0; slot < hashtable_classcache.size; slot++) { + nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot]; + + for (; nmen; nmen = nmen->hashlink) { + /* iterate over all class entries */ + + for (clsen = nmen->classes; clsen; clsen = clsen->next) { + c = clsen->classobj; + + /* now set the the vftbl */ + + if (c->object.header.vftbl == NULL) + c->object.header.vftbl = class_java_lang_Class->vftbl; + } + } + } +} + + +/* class_load_attribute_sourcefile ********************************************* + + SourceFile_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 sourcefile_index; + } + +*******************************************************************************/ + +static bool class_load_attribute_sourcefile(classbuffer *cb) +{ + classinfo *c; + u4 attribute_length; + u2 sourcefile_index; + utf *sourcefile; + + /* get classinfo */ + + c = cb->class; + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* check attribute length */ + + attribute_length = suck_u4(cb); + + if (attribute_length != 2) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* there can be no more than one SourceFile attribute */ + + if (c->sourcefile != NULL) { + exceptions_throw_classformaterror(c, "Multiple SourceFile attributes"); + return false; + } + + /* get sourcefile */ + + sourcefile_index = suck_u2(cb); + sourcefile = class_getconstant(c, sourcefile_index, CONSTANT_Utf8); + + if (sourcefile == NULL) + return false; + + /* store sourcefile */ + + c->sourcefile = sourcefile; + + return true; +} + + +/* class_load_attribute_enclosingmethod **************************************** + + EnclosingMethod_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 class_index; + u2 method_index; + } + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +static bool class_load_attribute_enclosingmethod(classbuffer *cb) +{ + classinfo *c; + u4 attribute_length; + u2 class_index; + u2 method_index; + classref_or_classinfo cr; + constant_nameandtype *cn; + + /* get classinfo */ + + c = cb->class; + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 4 + 2 + 2)) + return false; + + /* check attribute length */ + + attribute_length = suck_u4(cb); + + if (attribute_length != 4) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* there can be no more than one EnclosingMethod attribute */ + + if (c->enclosingmethod != NULL) { + exceptions_throw_classformaterror(c, "Multiple EnclosingMethod attributes"); + return false; + } + + /* get class index */ + + class_index = suck_u2(cb); + cr.ref = innerclass_getconstant(c, class_index, CONSTANT_Class); + + /* get method index */ + + method_index = suck_u2(cb); + cn = innerclass_getconstant(c, method_index, CONSTANT_NameAndType); + + /* store info in classinfo */ + + c->enclosingclass.any = cr.any; + c->enclosingmethod = cn; + + return true; +} +#endif /* defined(ENABLE_JAVASE) */ + + +/* class_load_attributes ******************************************************* + + Read attributes from ClassFile. + + attribute_info { + u2 attribute_name_index; + u4 attribute_length; + u1 info[attribute_length]; + } + + InnerClasses_attribute { + u2 attribute_name_index; + u4 attribute_length; + } + +*******************************************************************************/ + +bool class_load_attributes(classbuffer *cb) +{ + classinfo *c; + u4 i, j; + u2 attributes_count; + u2 attribute_name_index; + utf *attribute_name; + + c = cb->class; + + /* get attributes count */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + attributes_count = suck_u2(cb); + + for (i = 0; i < attributes_count; i++) { + /* get attribute name */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + 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_InnerClasses) { + /* InnerClasses */ + + if (c->innerclass != NULL) { + exceptions_throw_classformaterror(c, "Multiple InnerClasses attributes"); + return false; + } + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* skip attribute length */ + suck_u4(cb); + + /* number of records */ + c->innerclasscount = suck_u2(cb); + + if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) + return false; + + /* allocate memory for innerclass structure */ + c->innerclass = MNEW(innerclassinfo, c->innerclasscount); + + for (j = 0; j < c->innerclasscount; j++) { + /* The innerclass structure contains a class with an encoded + name, its defining scope, its simple name and a bitmask of + the access flags. If an inner class is not a member, its + outer_class is NULL, if a class is anonymous, its name is + NULL. */ + + innerclassinfo *info = c->innerclass + j; + + info->inner_class.ref = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + info->outer_class.ref = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + info->name = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + info->flags = suck_u2(cb); + } + } + else if (attribute_name == utf_SourceFile) { + /* SourceFile */ + + if (!class_load_attribute_sourcefile(cb)) + return false; + } +#if defined(ENABLE_JAVASE) + else if (attribute_name == utf_EnclosingMethod) { + /* EnclosingMethod */ + + if (!class_load_attribute_enclosingmethod(cb)) + return false; + } + else if (attribute_name == utf_Signature) { + /* Signature */ + + if (!loader_load_attribute_signature(cb, &(c->signature))) + return false; + } + else if (attribute_name == utf_RuntimeVisibleAnnotations) { + /* RuntimeVisibleAnnotations */ + + if (!annotation_load_attribute_runtimevisibleannotations(cb)) + return false; + } +#endif + else { + /* unknown attribute */ + + if (!loader_skip_attribute_body(cb)) + return false; + } + } + + return true; +} + + +/* class_freepool ************************************************************** + + Frees all resources used by this classes Constant Pool. + +*******************************************************************************/ + +static void class_freecpool(classinfo *c) +{ + u4 idx; + u4 tag; + voidptr info; + + if (c->cptags && c->cpinfos) { + for (idx = 0; idx < c->cpcount; idx++) { + tag = c->cptags[idx]; + info = c->cpinfos[idx]; + + if (info != NULL) { + switch (tag) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + FREE(info, constant_FMIref); + break; + case CONSTANT_Integer: + FREE(info, constant_integer); + break; + case CONSTANT_Float: + FREE(info, constant_float); + break; + case CONSTANT_Long: + FREE(info, constant_long); + break; + case CONSTANT_Double: + FREE(info, constant_double); + break; + case CONSTANT_NameAndType: + FREE(info, constant_nameandtype); + break; + } + } + } + } + + if (c->cptags) + MFREE(c->cptags, u1, c->cpcount); + + if (c->cpinfos) + MFREE(c->cpinfos, voidptr, c->cpcount); +} + + +/* class_getconstant *********************************************************** + + Retrieves the value at position 'pos' of the constantpool of a + class. If the type of the value is other than 'ctype', an error is + thrown. + +*******************************************************************************/ + +voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype) +{ + /* check index and type of constantpool entry */ + /* (pos == 0 is caught by type comparison) */ + + if ((pos >= c->cpcount) || (c->cptags[pos] != ctype)) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + return c->cpinfos[pos]; +} + + +/* innerclass_getconstant ****************************************************** + + Like class_getconstant, but if cptags is ZERO, null is returned. + +*******************************************************************************/ + +voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) +{ + /* invalid position in constantpool */ + + if (pos >= c->cpcount) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + /* constantpool entry of type 0 */ + + if (c->cptags[pos] == 0) + return NULL; + + /* check type of constantpool entry */ + + if (c->cptags[pos] != ctype) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + return c->cpinfos[pos]; +} + + +/* class_free ****************************************************************** + + Frees all resources used by the class. + +*******************************************************************************/ + +void class_free(classinfo *c) +{ + s4 i; + vftbl_t *v; + + class_freecpool(c); + + if (c->interfaces) + MFREE(c->interfaces, classinfo*, c->interfacescount); + + if (c->fields) { + for (i = 0; i < c->fieldscount; i++) + field_free(&(c->fields[i])); +#if defined(ENABLE_CACAO_GC) + MFREE(c->fields, fieldinfo, c->fieldscount); +#endif + } + + if (c->methods) { + for (i = 0; i < c->methodscount; i++) + method_free(&(c->methods[i])); + MFREE(c->methods, methodinfo, c->methodscount); + } + + if ((v = c->vftbl) != NULL) { + if (v->arraydesc) + mem_free(v->arraydesc,sizeof(arraydescriptor)); + + for (i = 0; i < v->interfacetablelength; i++) { + MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); + } + MFREE(v->interfacevftbllength, s4, v->interfacetablelength); + + i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) + + sizeof(methodptr*) * (v->interfacetablelength - + (v->interfacetablelength > 0)); + v = (vftbl_t*) (((methodptr*) v) - + (v->interfacetablelength - 1) * (v->interfacetablelength > 1)); + mem_free(v, i); + } + + if (c->innerclass) + MFREE(c->innerclass, innerclassinfo, c->innerclasscount); + + /* if (c->classvftbl) + mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */ + +/* GCFREE(c); */ +} + + +/* get_array_class ************************************************************* + + Returns the array class with the given name for the given + classloader, or NULL if an exception occurred. + + Note: This function does eager loading. + +*******************************************************************************/ + +static classinfo *get_array_class(utf *name,java_objectheader *initloader, + java_objectheader *defloader,bool link) +{ + classinfo *c; + + /* lookup this class in the classcache */ + c = classcache_lookup(initloader,name); + if (!c) + c = classcache_lookup_defined(defloader,name); + + if (!c) { + /* we have to create it */ + c = class_create_classinfo(name); + c = load_newly_created_array(c,initloader); + if (c == NULL) + return NULL; + } + + assert(c); + assert(c->state & CLASS_LOADED); + assert(c->classloader == defloader); + + if (link && !(c->state & CLASS_LINKED)) + if (!link_class(c)) + return NULL; + + assert(!link || (c->state & CLASS_LINKED)); + + return c; +} + + +/* class_array_of ************************************************************** + + Returns an array class with the given component class. The array + class is dynamically created if neccessary. + +*******************************************************************************/ + +classinfo *class_array_of(classinfo *component, bool link) +{ + s4 namelen; + char *namebuf; + s4 dumpsize; + classinfo *c; + + dumpsize = dump_size(); + + /* Assemble the array class name */ + namelen = component->name->blength; + + if (component->name->text[0] == '[') { + /* the component is itself an array */ + namebuf = DMNEW(char, namelen + 1); + namebuf[0] = '['; + MCOPY(namebuf + 1, component->name->text, char, namelen); + namelen++; + + } else { + /* the component is a non-array class */ + namebuf = DMNEW(char, namelen + 3); + namebuf[0] = '['; + namebuf[1] = 'L'; + MCOPY(namebuf + 2, component->name->text, char, namelen); + namebuf[2 + namelen] = ';'; + namelen += 3; + } + + c = get_array_class(utf_new(namebuf, namelen), + component->classloader, + component->classloader, + link); + + dump_release(dumpsize); + + return c; +} + + +/* class_multiarray_of ********************************************************* + + Returns an array class with the given dimension and element class. + The array class is dynamically created if neccessary. + +*******************************************************************************/ + +classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link) +{ + s4 namelen; + char *namebuf; + s4 dumpsize; + classinfo *c; + + dumpsize = dump_size(); + + if (dim < 1) { + log_text("Invalid array dimension requested"); + assert(0); + } + + /* Assemble the array class name */ + namelen = element->name->blength; + + if (element->name->text[0] == '[') { + /* the element is itself an array */ + namebuf = DMNEW(char, namelen + dim); + memcpy(namebuf + dim, element->name->text, namelen); + namelen += dim; + } + else { + /* the element is a non-array class */ + namebuf = DMNEW(char, namelen + 2 + dim); + namebuf[dim] = 'L'; + memcpy(namebuf + dim + 1, element->name->text, namelen); + namelen += (2 + dim); + namebuf[namelen - 1] = ';'; + } + memset(namebuf, '[', dim); + + c = get_array_class(utf_new(namebuf, namelen), + element->classloader, + element->classloader, + link); + + dump_release(dumpsize); + + return c; +} + + +/* class_lookup_classref ******************************************************* + + Looks up the constant_classref for a given classname in the classref + tables of a class. + + IN: + cls..............the class containing the reference + name.............the name of the class refered to + + RETURN VALUE: + a pointer to a constant_classref, or + NULL if the reference was not found + +*******************************************************************************/ + +constant_classref *class_lookup_classref(classinfo *cls, utf *name) +{ + constant_classref *ref; + extra_classref *xref; + int count; + + assert(cls); + assert(name); + assert(!cls->classrefcount || cls->classrefs); + + /* first search the main classref table */ + count = cls->classrefcount; + ref = cls->classrefs; + for (; count; --count, ++ref) + if (ref->name == name) + return ref; + + /* next try the list of extra classrefs */ + for (xref = cls->extclassrefs; xref; xref = xref->next) { + if (xref->classref.name == name) + return &(xref->classref); + } + + /* not found */ + return NULL; +} + + +/* class_get_classref ********************************************************** + + Returns the constant_classref for a given classname. + + IN: + cls..............the class containing the reference + name.............the name of the class refered to + + RETURN VALUE: + a pointer to a constant_classref (never NULL) + + NOTE: + The given name is not checked for validity! + +*******************************************************************************/ + +constant_classref *class_get_classref(classinfo *cls, utf *name) +{ + constant_classref *ref; + extra_classref *xref; + + assert(cls); + assert(name); + + ref = class_lookup_classref(cls,name); + if (ref) + return ref; + + xref = NEW(extra_classref); + CLASSREF_INIT(xref->classref,cls,name); + + xref->next = cls->extclassrefs; + cls->extclassrefs = xref; + + return &(xref->classref); +} + + +/* class_get_self_classref ***************************************************** + + Returns the constant_classref to the class itself. + + IN: + cls..............the class containing the reference + + RETURN VALUE: + a pointer to a constant_classref (never NULL) + +*******************************************************************************/ + +constant_classref *class_get_self_classref(classinfo *cls) +{ + /* XXX this should be done in a faster way. Maybe always make */ + /* the classref of index 0 a self reference. */ + return class_get_classref(cls,cls->name); +} + +/* class_get_classref_multiarray_of ******************************************** + + Returns an array type reference with the given dimension and element class + reference. + + IN: + dim..............the requested dimension + dim must be in [1;255]. This is NOT checked! + ref..............the component class reference + + RETURN VALUE: + a pointer to the class reference for the array type + + NOTE: + The referer of `ref` is used as the referer for the new classref. + +*******************************************************************************/ + +constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref) +{ + s4 namelen; + char *namebuf; + s4 dumpsize; + constant_classref *cr; + + assert(ref); + assert(dim >= 1 && dim <= 255); + + dumpsize = dump_size(); + + /* Assemble the array class name */ + namelen = ref->name->blength; + + if (ref->name->text[0] == '[') { + /* the element is itself an array */ + namebuf = DMNEW(char, namelen + dim); + memcpy(namebuf + dim, ref->name->text, namelen); + namelen += dim; + } + else { + /* the element is a non-array class */ + namebuf = DMNEW(char, namelen + 2 + dim); + namebuf[dim] = 'L'; + memcpy(namebuf + dim + 1, ref->name->text, namelen); + namelen += (2 + dim); + namebuf[namelen - 1] = ';'; + } + memset(namebuf, '[', dim); + + cr = class_get_classref(ref->referer,utf_new(namebuf, namelen)); + + dump_release(dumpsize); + + return cr; +} + + +/* class_get_classref_component_of ********************************************* + + Returns the component classref of a given array type reference + + IN: + ref..............the array type reference + + RETURN VALUE: + a reference to the component class, or + NULL if `ref` is not an object array type reference + + NOTE: + The referer of `ref` is used as the referer for the new classref. + +*******************************************************************************/ + +constant_classref *class_get_classref_component_of(constant_classref *ref) +{ + s4 namelen; + char *name; + + assert(ref); + + name = ref->name->text; + if (*name++ != '[') + return NULL; + + namelen = ref->name->blength - 1; + if (*name == 'L') { + name++; + namelen -= 2; + } + else if (*name != '[') { + return NULL; + } + + return class_get_classref(ref->referer, utf_new(name, namelen)); +} + + +/* class_findmethod ************************************************************ + + Searches a 'classinfo' structure for a method having the given name + and descriptor. If descriptor is NULL, it is ignored. + +*******************************************************************************/ + +methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) +{ + methodinfo *m; + s4 i; + + for (i = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc))) + return m; + } + + return NULL; +} + + +/* class_resolvemethod ********************************************************* + + Searches a class and it's super classes for a method. + + Superinterfaces are *not* searched. + +*******************************************************************************/ + +methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) +{ + methodinfo *m; + + while (c) { + m = class_findmethod(c, name, desc); + + if (m) + return m; + + /* JVM Specification bug: + + It is important NOT to resolve special and + methods to super classes or interfaces; yet, this is not + explicited in the specification. Section 5.4.3.3 should be + updated appropriately. */ + + if (name == utf_init || name == utf_clinit) + return NULL; + + c = c->super.cls; + } + + return NULL; +} + + +/* class_resolveinterfacemethod_intern ***************************************** + + Internally used helper function. Do not use this directly. + +*******************************************************************************/ + +static methodinfo *class_resolveinterfacemethod_intern(classinfo *c, + utf *name, utf *desc) +{ + methodinfo *m; + s4 i; + + /* try to find the method in the class */ + + m = class_findmethod(c, name, desc); + + if (m != NULL) + return m; + + /* no method found? try the superinterfaces */ + + for (i = 0; i < c->interfacescount; i++) { + m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, + name, desc); + + if (m != NULL) + return m; + } + + /* no method found */ + + return NULL; +} + + +/* class_resolveclassmethod **************************************************** + + Resolves a reference from REFERER to a method with NAME and DESC in + class C. + + If the method cannot be resolved the return value is NULL. If + EXCEPT is true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool throwexception) +{ + classinfo *cls; + methodinfo *m; + s4 i; + +/* if (c->flags & ACC_INTERFACE) { */ +/* if (throwexception) */ +/* *exceptionptr = */ +/* new_exception(string_java_lang_IncompatibleClassChangeError); */ +/* return NULL; */ +/* } */ + + /* try class c and its superclasses */ + + cls = c; + + m = class_resolvemethod(cls, name, desc); + + if (m != NULL) + goto found; + + /* try the superinterfaces */ + + for (i = 0; i < c->interfacescount; i++) { + m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, + name, desc); + + if (m != NULL) + goto found; + } + + if (throwexception) { +#if defined(ENABLE_JAVASE) + exceptions_throw_nosuchmethoderror(c, name, desc); +#else + exceptions_throw_virtualmachineerror(); +#endif + } + + return NULL; + + found: + if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { + if (throwexception) { +#if defined(ENABLE_JAVASE) + exceptions_throw_abstractmethoderror(); +#else + exceptions_throw_virtualmachineerror(); +#endif + } + + return NULL; + } + + /* XXX check access rights */ + + return m; +} + + +/* class_resolveinterfacemethod ************************************************ + + Resolves a reference from REFERER to a method with NAME and DESC in + interface C. + + If the method cannot be resolved the return value is NULL. If + EXCEPT is true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool throwexception) +{ + methodinfo *mi; + + if (!(c->flags & ACC_INTERFACE)) { + if (throwexception) + exceptions_throw_incompatibleclasschangeerror(c, "Not an interface"); + + return NULL; + } + + mi = class_resolveinterfacemethod_intern(c, name, desc); + + if (mi != NULL) + return mi; + + /* try class java.lang.Object */ + + mi = class_findmethod(class_java_lang_Object, name, desc); + + if (mi != NULL) + return mi; + + if (throwexception) { +#if defined(ENABLE_JAVASE) + exceptions_throw_nosuchmethoderror(c, name, desc); +#else + exceptions_throw_virtualmachineerror(); +#endif + } + + return NULL; +} + + +/* class_findfield ************************************************************* + + Searches for field with specified name and type in a classinfo + structure. If no such field is found NULL is returned. + +*******************************************************************************/ + +fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) +{ + s4 i; + + for (i = 0; i < c->fieldscount; i++) + if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) + return &(c->fields[i]); + + if (c->super.cls) + return class_findfield(c->super.cls, name, desc); + + return NULL; +} + + +/* class_findfield_approx ****************************************************** + + Searches in 'classinfo'-structure for a field with the specified + name. + +*******************************************************************************/ + +fieldinfo *class_findfield_by_name(classinfo *c, utf *name) +{ + s4 i; + + /* get field index */ + + i = class_findfield_index_by_name(c, name); + + /* field was not found, return */ + + if (i == -1) + return NULL; + + /* return field address */ + + return &(c->fields[i]); +} + + +s4 class_findfield_index_by_name(classinfo *c, utf *name) +{ + s4 i; + + for (i = 0; i < c->fieldscount; i++) { + /* compare field names */ + + if ((c->fields[i].name == name)) + return i; + } + + /* field was not found, raise exception */ + + exceptions_throw_nosuchfielderror(c, name); + + return -1; +} + + +/****************** Function: class_resolvefield_int *************************** + + This is an internally used helper function. Do not use this directly. + + Tries to resolve a field having the given name and type. + If the field cannot be resolved, NULL is returned. + +*******************************************************************************/ + +static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) +{ + fieldinfo *fi; + s4 i; + + /* search for field in class c */ + + for (i = 0; i < c->fieldscount; i++) { + if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { + return &(c->fields[i]); + } + } + + /* try superinterfaces recursively */ + + for (i = 0; i < c->interfacescount; i++) { + fi = class_resolvefield_int(c->interfaces[i].cls, name, desc); + if (fi) + return fi; + } + + /* try superclass */ + + if (c->super.cls) + return class_resolvefield_int(c->super.cls, name, desc); + + /* not found */ + + return NULL; +} + + +/********************* Function: class_resolvefield *************************** + + Resolves a reference from REFERER to a field with NAME and DESC in class C. + + If the field cannot be resolved the return value is NULL. If EXCEPT is + true *exceptionptr is set, too. + +*******************************************************************************/ + +fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool throwexception) +{ + fieldinfo *fi; + + fi = class_resolvefield_int(c, name, desc); + + if (!fi) { + if (throwexception) + exceptions_throw_nosuchfielderror(c, name); + + return NULL; + } + + /* XXX check access rights */ + + return fi; +} + + +/* class_issubclass ************************************************************ + + Checks if sub is a descendant of super. + +*******************************************************************************/ + +bool class_issubclass(classinfo *sub, classinfo *super) +{ + for (;;) { + if (!sub) + return false; + + if (sub == super) + return true; + + sub = sub->super.cls; + } +} + + +/* class_printflags ************************************************************ + + Prints flags of a class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_printflags(classinfo *c) +{ + if (c == NULL) { + printf("NULL"); + return; + } + + if (c->flags & ACC_PUBLIC) printf(" PUBLIC"); + if (c->flags & ACC_PRIVATE) printf(" PRIVATE"); + if (c->flags & ACC_PROTECTED) printf(" PROTECTED"); + if (c->flags & ACC_STATIC) printf(" STATIC"); + if (c->flags & ACC_FINAL) printf(" FINAL"); + if (c->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED"); + if (c->flags & ACC_VOLATILE) printf(" VOLATILE"); + if (c->flags & ACC_TRANSIENT) printf(" TRANSIENT"); + if (c->flags & ACC_NATIVE) printf(" NATIVE"); + if (c->flags & ACC_INTERFACE) printf(" INTERFACE"); + if (c->flags & ACC_ABSTRACT) printf(" ABSTRACT"); +} +#endif + + +/* class_print ***************************************************************** + + Prints classname plus flags. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_print(classinfo *c) +{ + if (c == NULL) { + printf("NULL"); + return; + } + + utf_display_printable_ascii(c->name); + class_printflags(c); +} +#endif + + +/* class_classref_print ******************************************************** + + Prints classname plus referer class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_print(constant_classref *cr) +{ + if (cr == NULL) { + printf("NULL"); + return; + } + + utf_display_printable_ascii(cr->name); + printf("(ref.by "); + if (cr->referer) + class_print(cr->referer); + else + printf("NULL"); + printf(")"); +} +#endif + + +/* class_println *************************************************************** + + Prints classname plus flags and new line. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_println(classinfo *c) +{ + class_print(c); + printf("\n"); +} +#endif + + +/* class_classref_println ****************************************************** + + Prints classname plus referer class and new line. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_println(constant_classref *cr) +{ + class_classref_print(cr); + printf("\n"); +} +#endif + + +/* class_classref_or_classinfo_print ******************************************* + + Prints classname plus referer class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_or_classinfo_print(classref_or_classinfo c) +{ + if (c.any == NULL) { + printf("(classref_or_classinfo) NULL"); + return; + } + if (IS_CLASSREF(c)) + class_classref_print(c.ref); + else + class_print(c.cls); +} +#endif + + +/* class_classref_or_classinfo_println ***************************************** + + Prints classname plus referer class and a newline. + +*******************************************************************************/ + +void class_classref_or_classinfo_println(classref_or_classinfo c) +{ + class_classref_or_classinfo_println(c); + printf("\n"); +} + + +/* class_showconstantpool ****************************************************** + + Dump the constant pool of the given class to stdout. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_showconstantpool (classinfo *c) +{ + u4 i; + voidptr e; + + printf ("---- dump of constant pool ----\n"); + + for (i=0; icpcount; i++) { + printf ("#%d: ", (int) i); + + e = c -> cpinfos [i]; + if (e) { + + switch (c -> cptags [i]) { + case CONSTANT_Class: + printf ("Classreference -> "); + utf_display_printable_ascii ( ((constant_classref*)e) -> name ); + break; + case CONSTANT_Fieldref: + printf ("Fieldref -> "); + field_fieldref_print((constant_FMIref *) e); + break; + case CONSTANT_Methodref: + printf ("Methodref -> "); + method_methodref_print((constant_FMIref *) e); + break; + case CONSTANT_InterfaceMethodref: + printf ("InterfaceMethod -> "); + method_methodref_print((constant_FMIref *) e); + break; + case CONSTANT_String: + printf ("String -> "); + utf_display_printable_ascii (e); + break; + case CONSTANT_Integer: + printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); + break; + case CONSTANT_Float: + printf ("Float -> %f", ((constant_float*)e) -> value); + break; + case CONSTANT_Double: + printf ("Double -> %f", ((constant_double*)e) -> value); + break; + case CONSTANT_Long: + { + u8 v = ((constant_long*)e) -> value; +#if U8_AVAILABLE + printf ("Long -> %ld", (long int) v); +#else + printf ("Long -> HI: %ld, LO: %ld\n", + (long int) v.high, (long int) v.low); +#endif + } + break; + case CONSTANT_NameAndType: + { + constant_nameandtype *cnt = e; + printf ("NameAndType: "); + utf_display_printable_ascii (cnt->name); + printf (" "); + utf_display_printable_ascii (cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf ("Utf8 -> "); + utf_display_printable_ascii (e); + break; + default: + log_text("Invalid type of ConstantPool-Entry"); + assert(0); + } + } + + printf ("\n"); + } +} +#endif /* !defined(NDEBUG) */ + + +/* class_showmethods *********************************************************** + + Dump info about the fields and methods of the given class to stdout. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_showmethods (classinfo *c) +{ + s4 i; + + printf("--------- Fields and Methods ----------------\n"); + printf("Flags: "); + class_printflags(c); + printf("\n"); + + printf("This: "); + utf_display_printable_ascii(c->name); + printf("\n"); + + if (c->super.cls) { + printf("Super: "); + utf_display_printable_ascii(c->super.cls->name); + printf ("\n"); + } + + printf("Index: %d\n", c->index); + + printf("Interfaces:\n"); + for (i = 0; i < c->interfacescount; i++) { + printf(" "); + utf_display_printable_ascii(c->interfaces[i].cls->name); + printf (" (%d)\n", c->interfaces[i].cls->index); + } + + printf("Fields:\n"); + for (i = 0; i < c->fieldscount; i++) + field_println(&(c->fields[i])); + + printf("Methods:\n"); + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (!(m->flags & ACC_STATIC)) + printf("vftblindex: %d ", m->vftblindex); + + method_println(m); + } + + printf ("Virtual function table:\n"); + for (i = 0; i < c->vftbl->vftbllength; i++) + printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i])); +} +#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: + */ diff --git a/src/vmcore/class.h b/src/vmcore/class.h new file mode 100644 index 000000000..4f51a5f42 --- /dev/null +++ b/src/vmcore/class.h @@ -0,0 +1,356 @@ +/* src/vmcore/class.h - class related functions header + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: class.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _CLASS_H +#define _CLASS_H + +/* forward typedefs ***********************************************************/ + +typedef struct classinfo classinfo; +typedef struct innerclassinfo innerclassinfo; +typedef struct extra_classref extra_classref; + + +#include "config.h" +#include "vm/types.h" + +#include "toolbox/list.h" + +#include "vm/global.h" + +#if defined(ENABLE_JAVASE) +# include "vmcore/annotation.h" +#endif + +#include "vmcore/field.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/method.h" +#include "vmcore/references.h" +#include "vmcore/utf8.h" + + +/* class state defines ********************************************************/ + +#define CLASS_LOADING 0x0001 +#define CLASS_LOADED 0x0002 +#define CLASS_LINKING 0x0004 +#define CLASS_LINKED 0x0008 +#define CLASS_INITIALIZING 0x0010 +#define CLASS_INITIALIZED 0x0020 +#define CLASS_ERROR 0x0040 + + +/* some macros ****************************************************************/ + +#define CLASS_IS_OR_ALMOST_INITIALIZED(c) \ + (((c)->state & CLASS_INITIALIZING) || ((c)->state & CLASS_INITIALIZED)) + + +/* classinfo ******************************************************************/ + +struct classinfo { /* class structure */ + struct { + java_objectheader header; + ptrint padding[4]; + } object; + + s4 flags; /* ACC flags */ + utf *name; /* class name */ + + s4 cpcount; /* number of entries in constant pool */ + u1 *cptags; /* constant pool tags */ + voidptr *cpinfos; /* pointer to constant pool info structures */ + + s4 classrefcount; /* number of symbolic class references */ + constant_classref *classrefs; /* table of symbolic class references */ + extra_classref *extclassrefs; /* additional classrefs */ + s4 parseddescsize; /* size of the parsed descriptors block */ + u1 *parseddescs; /* parsed descriptors */ + + classref_or_classinfo super; /* super class */ + classinfo *sub; /* sub class pointer */ + classinfo *nextsub; /* pointer to next class in sub class list */ + + s4 interfacescount; /* number of interfaces */ + classref_or_classinfo *interfaces; /* superinterfaces */ + + s4 fieldscount; /* number of fields */ + fieldinfo *fields; /* field table */ + + s4 methodscount; /* number of methods */ + methodinfo *methods; /* method table */ + + listnode listnode; /* linkage */ + + s4 state; /* current class state */ + s4 index; /* hierarchy depth (classes) or index */ + /* (interfaces) */ + s4 instancesize; /* size of an instance of this class */ + + vftbl_t *vftbl; /* pointer to virtual function table */ + + methodinfo *finalizer; /* finalizer method */ + + u2 innerclasscount; /* number of inner classes */ + innerclassinfo *innerclass; + +#if defined(ENABLE_JAVASE) + classref_or_classinfo enclosingclass; /* enclosing class */ + constant_nameandtype *enclosingmethod; /* enclosing method */ +#endif + + utf *packagename; /* full name of the package */ + utf *sourcefile; /* SourceFile attribute */ +#if defined(ENABLE_JAVASE) + utf *signature; /* Signature attribute */ + s4 runtimevisibleannotationscount; + annotation_t *runtimevisibleannotations; +#endif + java_objectheader *classloader; /* NULL for bootstrap classloader */ +}; + + +/* innerclassinfo *************************************************************/ + +struct innerclassinfo { + classref_or_classinfo inner_class; /* inner class pointer */ + classref_or_classinfo outer_class; /* outer class pointer */ + utf *name; /* innerclass name */ + s4 flags; /* ACC flags */ +}; + + +/* extra_classref ************************************************************** + + for classrefs not occurring within descriptors + +*******************************************************************************/ + +struct extra_classref { + extra_classref *next; + constant_classref classref; +}; + + +/* global variables ***********************************************************/ + +extern list unlinkedclasses; /* this is only used for eager class loading */ + + +/* frequently used classes ****************************************************/ + +/* important system classes */ + +extern classinfo *class_java_lang_Object; +extern classinfo *class_java_lang_Class; +extern classinfo *class_java_lang_ClassLoader; +extern classinfo *class_java_lang_Cloneable; +extern classinfo *class_java_lang_SecurityManager; +extern classinfo *class_java_lang_String; +extern classinfo *class_java_lang_System; +extern classinfo *class_java_lang_Thread; +extern classinfo *class_java_lang_ThreadGroup; +extern classinfo *class_java_lang_VMSystem; +extern classinfo *class_java_lang_VMThread; +extern classinfo *class_java_io_Serializable; + + +/* system exception classes required in cacao */ + +extern classinfo *class_java_lang_Throwable; +extern classinfo *class_java_lang_Error; +extern classinfo *class_java_lang_LinkageError; +extern classinfo *class_java_lang_NoClassDefFoundError; +extern classinfo *class_java_lang_OutOfMemoryError; +extern classinfo *class_java_lang_VirtualMachineError; + +#if defined(WITH_CLASSPATH_GNU) +extern classinfo *class_java_lang_VMThrowable; +#endif + +extern classinfo *class_java_lang_Exception; +extern classinfo *class_java_lang_ClassCastException; +extern classinfo *class_java_lang_ClassNotFoundException; + +#if defined(ENABLE_JAVASE) +extern classinfo *class_java_lang_Void; +#endif + +extern classinfo *class_java_lang_Boolean; +extern classinfo *class_java_lang_Byte; +extern classinfo *class_java_lang_Character; +extern classinfo *class_java_lang_Short; +extern classinfo *class_java_lang_Integer; +extern classinfo *class_java_lang_Long; +extern classinfo *class_java_lang_Float; +extern classinfo *class_java_lang_Double; + + +/* some runtime exception */ + +extern classinfo *class_java_lang_NullPointerException; + + +/* some classes which may be used more often */ + +#if defined(ENABLE_JAVASE) +extern classinfo *class_java_lang_StackTraceElement; +extern classinfo *class_java_lang_reflect_Constructor; +extern classinfo *class_java_lang_reflect_Field; +extern classinfo *class_java_lang_reflect_Method; +extern classinfo *class_java_security_PrivilegedAction; +extern classinfo *class_java_util_Vector; + +extern classinfo *arrayclass_java_lang_Object; +#endif + + +/* pseudo classes for the type checker ****************************************/ + +/* + * pseudo_class_Arraystub + * (extends Object implements Cloneable, java.io.Serializable) + * + * If two arrays of incompatible component types are merged, + * the resulting reference has no accessible components. + * The result does, however, implement the interfaces Cloneable + * and java.io.Serializable. This pseudo class is used internally + * to represent such results. (They are *not* considered arrays!) + * + * pseudo_class_Null + * + * This pseudo class is used internally to represent the + * null type. + * + * pseudo_class_New + * + * This pseudo class is used internally to represent the + * the 'uninitialized object' type. + */ + +extern classinfo *pseudo_class_Arraystub; +extern classinfo *pseudo_class_Null; +extern classinfo *pseudo_class_New; + + +/* function prototypes ********************************************************/ + +/* create a new classinfo struct */ +classinfo *class_create_classinfo(utf *u); + +/* postset's the header.vftbl */ +void class_postset_header_vftbl(void); + +/* set the package name after the name has been set */ +void class_set_packagename(classinfo *c); + +bool class_load_attributes(classbuffer *cb); + +/* retrieve constantpool element */ +voidptr class_getconstant(classinfo *class, u4 pos, u4 ctype); +voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype); + +/* frees all resources used by the class */ +void class_free(classinfo *); + +/* return an array class with the given component class */ +classinfo *class_array_of(classinfo *component,bool link); + +/* return an array class with the given dimension and element class */ +classinfo *class_multiarray_of(s4 dim, classinfo *element,bool link); + +/* return a classref for the given class name */ +/* (does a linear search!) */ +constant_classref *class_lookup_classref(classinfo *cls,utf *name); + +/* return a classref for the given class name */ +/* (does a linear search!) */ +constant_classref *class_get_classref(classinfo *cls,utf *name); + +/* return a classref to the class itself */ +/* (does a linear search!) */ +constant_classref *class_get_self_classref(classinfo *cls); + +/* return a classref for an array with the given dimension of with the */ +/* given component type */ +constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref); + +/* return a classref for the component type of the given array type */ +constant_classref *class_get_classref_component_of(constant_classref *ref); + +/* get a class' field by name and descriptor */ +fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc); + +/* search 'classinfo'-structure for a field with the specified name */ +fieldinfo *class_findfield_by_name(classinfo *c, utf *name); +s4 class_findfield_index_by_name(classinfo *c, utf *name); + +/* search class for a field */ +fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, classinfo *referer, bool throwexception); + +/* search for a method with a specified name and descriptor */ +methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc); +methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *dest); +methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); +methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *dest, classinfo *referer, bool throwexception); + +bool class_issubclass(classinfo *sub, classinfo *super); + +/* some debugging functions */ + +#if !defined(NDEBUG) +void class_printflags(classinfo *c); +void class_print(classinfo *c); +void class_println(classinfo *c); +void class_classref_print(constant_classref *cr); +void class_classref_println(constant_classref *cr); +void class_classref_or_classinfo_print(classref_or_classinfo c); +void class_classref_or_classinfo_println(classref_or_classinfo c); +#endif + +/* debug purposes */ +void class_showmethods(classinfo *c); +void class_showconstantpool(classinfo *c); + +#endif /* _CLASS_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: + */ diff --git a/src/vmcore/classcache.c b/src/vmcore/classcache.c new file mode 100644 index 000000000..c2d53ed45 --- /dev/null +++ b/src/vmcore/classcache.c @@ -0,0 +1,1583 @@ +/* src/vmcore/classcache.c - loaded class cache and loading constraints + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: classcache.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "toolbox/hashtable.h" + +#include "vm/exceptions.h" + +#include "vmcore/classcache.h" +#include "vmcore/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() LOCK_MONITOR_ENTER(lock_hashtable_classcache) +# define CLASSCACHE_UNLOCK() LOCK_MONITOR_EXIT(lock_hashtable_classcache) +#else +# define CLASSCACHE_LOCK() +# define CLASSCACHE_UNLOCK() +#endif + +/*============================================================================*/ +/* GLOBAL VARIABLES */ +/*============================================================================*/ + +hashtable hashtable_classcache; + +#if defined(ENABLE_THREADS) +static java_objectheader *lock_hashtable_classcache; +#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) +{ + /* create the hashtable */ + + hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE); + +#if defined(ENABLE_THREADS) + /* create utf hashtable lock object */ + + lock_hashtable_classcache = NEW(java_objectheader); + + lock_init_object_lock(lock_hashtable_classcache); +#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 * 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_text(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 *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 *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 *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 *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_text(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 + dolog("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(stderr,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_text(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 + dolog("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(stderr,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 * 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, voidptr, 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 * a, + classloader * b, + utf * classname) +{ + classcache_name_entry *en; + classcache_class_entry *clsenA; + classcache_class_entry *clsenB; + + assert(classname); + +#ifdef CLASSCACHE_VERBOSE + fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b); + utf_fprint_printable_ascii_classname(stderr, classname); + fprintf(stderr, ")\n"); +#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 * a, + classloader * 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(); + + fprintf(file, "\n=== [loaded class cache] =====================================\n\n"); + fprintf(file, "hash size : %d\n", (int) hashtable_classcache.size); + fprintf(file, "hash entries: %d\n", (int) hashtable_classcache.entries); + fprintf(file, "\n"); + + 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) { + fprintf(file, " loaded %p\n", (void *) clsen->classobj); + } + else { + fprintf(file, " unresolved\n"); + } + fprintf(file, " loaders:"); + for (lden = clsen->loaders; lden; lden = lden->next) { + fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader); + } + fprintf(file, "\n constraints:"); + for (lden = clsen->constraints; lden; lden = lden->next) { + fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader); + } + fprintf(file, "\n"); + } + } + + 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: + */ diff --git a/src/vmcore/classcache.h b/src/vmcore/classcache.h new file mode 100644 index 000000000..4fcb86801 --- /dev/null +++ b/src/vmcore/classcache.h @@ -0,0 +1,178 @@ +/* src/vmcore/classcache.h - loaded class cache and loading constraints + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: classcache.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _CLASSCACHE_H +#define _CLASSCACHE_H + +#include "config.h" +#include "vm/types.h" + +#include /* for FILE */ + +#if defined(ENABLE_JVMTI) +# include "native/jni.h" +#endif + +#include "toolbox/hashtable.h" + +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/references.h" + + +/* 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; + +typedef java_objectheader classloader; + +/* 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 *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 *initloader,utf *classname); +classinfo * classcache_lookup_defined(classloader *defloader,utf *classname); +classinfo * classcache_lookup_defined_or_initiated(classloader *loader,utf *classname); + +bool classcache_store_unique(classinfo *cls); +classinfo * classcache_store(classloader *initloader,classinfo *cls,bool mayfree); +classinfo * classcache_store_defined(classinfo *cls); + +#if defined(ENABLE_VERIFIER) +bool classcache_add_constraint(classloader *a,classloader *b,utf *classname); +bool classcache_add_constraints_for_params(classloader *a,classloader *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 + +#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: + */ + diff --git a/src/vmcore/descriptor.c b/src/vmcore/descriptor.c new file mode 100644 index 000000000..4b1c0e815 --- /dev/null +++ b/src/vmcore/descriptor.c @@ -0,0 +1,1361 @@ +/* src/vmcore/descriptor.c - checking and parsing of field / method descriptors + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: descriptor.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "mm/memory.h" + +#include "vm/exceptions.h" + +#include "vmcore/descriptor.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + + +/* constants (private to descriptor.c) ****************************************/ + +/* initial number of entries for the classrefhash of a descriptor_pool */ +/* (currently the hash is never grown!) */ +#define CLASSREFHASH_INIT_SIZE 64 + +/* initial number of entries for the descriptorhash of a descriptor_pool */ +/* (currently the hash is never grown!) */ +#define DESCRIPTORHASH_INIT_SIZE 128 + +/* data structures (private to descriptor.c) **********************************/ + +typedef struct classref_hash_entry classref_hash_entry; +typedef struct descriptor_hash_entry descriptor_hash_entry; + +/* entry struct for the classrefhash of descriptor_pool */ +struct classref_hash_entry { + classref_hash_entry *hashlink; /* for hash chaining */ + utf *name; /* name of the class refered to */ + u2 index; /* index into classref table */ +}; + +/* entry struct for the descriptorhash of descriptor_pool */ +struct descriptor_hash_entry { + descriptor_hash_entry *hashlink; + utf *desc; + parseddesc parseddesc; + s2 paramslots; /* number of params, LONG/DOUBLE counted as 2 */ +}; + + +/****************************************************************************/ +/* MACROS FOR DESCRIPTOR PARSING (private to descriptor.c) */ +/****************************************************************************/ + +/* SKIP_FIELDDESCRIPTOR: + * utf_ptr must point to the first character of a field descriptor. + * After the macro call utf_ptr points to the first character after + * the field descriptor. + * + * CAUTION: This macro does not check for an unexpected end of the + * descriptor. Better use SKIP_FIELDDESCRIPTOR_SAFE. + */ +#define SKIP_FIELDDESCRIPTOR(utf_ptr) \ + do { while (*(utf_ptr)=='[') (utf_ptr)++; \ + if (*(utf_ptr)++=='L') \ + while(*(utf_ptr)++ != ';') /* skip */; } while(0) + +/* SKIP_FIELDDESCRIPTOR_SAFE: + * utf_ptr must point to the first character of a field descriptor. + * After the macro call utf_ptr points to the first character after + * the field descriptor. + * + * Input: + * utf_ptr....points to first char of descriptor + * end_ptr....points to first char after the end of the string + * errorflag..must be initialized (to false) by the caller! + * Output: + * utf_ptr....points to first char after the descriptor + * errorflag..set to true if the string ended unexpectedly + */ +#define SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,errorflag) \ + do { while ((utf_ptr) != (end_ptr) && *(utf_ptr)=='[') (utf_ptr)++; \ + if ((utf_ptr) == (end_ptr)) \ + (errorflag) = true; \ + else \ + if (*(utf_ptr)++=='L') { \ + while((utf_ptr) != (end_ptr) && *(utf_ptr)++ != ';') \ + /* skip */; \ + if ((utf_ptr)[-1] != ';') \ + (errorflag) = true; }} while(0) + + +/****************************************************************************/ +/* DEBUG HELPERS */ +/****************************************************************************/ + +/*#define DESCRIPTOR_VERBOSE*/ + +/****************************************************************************/ +/* FUNCTIONS */ +/****************************************************************************/ + +/* descriptor_to_basic_type **************************************************** + + Return the basic type to use for a value with this descriptor. + + IN: + utf..............descriptor utf string + + OUT: + A TYPE_* constant. + + PRECONDITIONS: + This function assumes that the descriptor has passed + descriptor_pool_add checks and that it does not start with '('. + +*******************************************************************************/ + +u2 descriptor_to_basic_type(utf *descriptor) +{ + assert(descriptor->blength >= 1); + + switch (descriptor->text[0]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': return TYPE_INT; + case 'D': return TYPE_DBL; + case 'F': return TYPE_FLT; + case 'J': return TYPE_LNG; + case 'L': + case '[': return TYPE_ADR; + } + + assert(0); + + return 0; /* keep the compiler happy */ +} + +/* descriptor_typesize**** **************************************************** + + Return the size in bytes needed for the given type. + + IN: + td..............typedesc describing the type + + OUT: + The number of bytes + +*******************************************************************************/ + +u2 descriptor_typesize(typedesc *td) +{ + assert(td); + + switch (td->type) { + case TYPE_INT: return 4; + case TYPE_LNG: return 8; + case TYPE_FLT: return 4; + case TYPE_DBL: return 8; + case TYPE_ADR: return sizeof(voidptr); + } + + assert(0); + + return 0; /* keep the compiler happy */ +} + +/* name_from_descriptor ******************************************************** + + Return the class name indicated by the given descriptor + (Internally used helper function) + + IN: + c................class containing the descriptor + utf_ptr..........first character of descriptor + end_ptr..........first character after the end of the string + mode.............a combination (binary or) of the following flags: + + (Flags marked with * are the default settings.) + + How to handle "V" descriptors: + + * DESCRIPTOR_VOID.....handle it like other primitive types + DESCRIPTOR_NOVOID...treat it as an error + + How to deal with extra characters after the end of the + descriptor: + + * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists) + DESCRIPTOR_CHECKEND.....treat them as an error + + OUT: + *next............if non-NULL, *next is set to the first character after + the descriptor. (Undefined if an error occurs.) + *name............set to the utf name of the class + + RETURN VALUE: + true.............descriptor parsed successfully + false............an exception has been thrown + +*******************************************************************************/ + +#define DESCRIPTOR_VOID 0 /* default */ +#define DESCRIPTOR_NOVOID 0x0040 +#define DESCRIPTOR_NOCHECKEND 0 /* default */ +#define DESCRIPTOR_CHECKEND 0x1000 + +static bool +name_from_descriptor(classinfo *c, + char *utf_ptr, char *end_ptr, + char **next, int mode, utf **name) +{ + char *start = utf_ptr; + bool error = false; + + assert(c); + assert(utf_ptr); + assert(end_ptr); + assert(name); + + *name = NULL; + SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); + + if (mode & DESCRIPTOR_CHECKEND) + error |= (utf_ptr != end_ptr); + + if (!error) { + if (next) *next = utf_ptr; + + switch (*start) { + case 'V': + if (mode & DESCRIPTOR_NOVOID) + break; + /* FALLTHROUGH! */ + case 'I': + case 'J': + case 'F': + case 'D': + case 'B': + case 'C': + case 'S': + case 'Z': + return true; + + case 'L': + start++; + utf_ptr--; + /* FALLTHROUGH! */ + case '[': + *name = utf_new(start, utf_ptr - start); + return true; + } + } + + exceptions_throw_classformaterror(c, "Invalid descriptor"); + return false; +} + + +/* descriptor_to_typedesc ****************************************************** + + Parse the given type descriptor and fill a typedesc struct + (Internally used helper function) + + IN: + pool.............the descriptor pool + utf_ptr..........points to first character of type descriptor + end_pos..........points after last character of the whole descriptor + + OUT: + *next............set to next character after type descriptor + *d...............filled with parsed information + + RETURN VALUE: + true.............parsing succeeded + false............an exception has been thrown + +*******************************************************************************/ + +static bool +descriptor_to_typedesc(descriptor_pool *pool, char *utf_ptr, char *end_pos, + char **next, typedesc *td) +{ + utf *name; + + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name)) + return false; + + if (name) { + /* a reference type */ + td->type = TYPE_ADR; + td->decltype = TYPE_ADR; + td->arraydim = 0; + for (utf_ptr = name->text; *utf_ptr == '['; ++utf_ptr) + td->arraydim++; + td->classref = descriptor_pool_lookup_classref(pool, name); + + } else { + /* a primitive type */ + switch (*utf_ptr) { + case 'B': + td->decltype = PRIMITIVETYPE_BYTE; + td->type = TYPE_INT; + break; + case 'C': + td->decltype = PRIMITIVETYPE_CHAR; + td->type = TYPE_INT; + break; + case 'S': + td->decltype = PRIMITIVETYPE_SHORT; + td->type = TYPE_INT; + break; + case 'Z': + td->decltype = PRIMITIVETYPE_BOOLEAN; + td->type = TYPE_INT; + break; + case 'I': + td->decltype = PRIMITIVETYPE_INT; + td->type = TYPE_INT; + break; + case 'D': + td->decltype = PRIMITIVETYPE_DOUBLE; + td->type = TYPE_DBL; + break; + case 'F': + td->decltype = PRIMITIVETYPE_FLOAT; + td->type = TYPE_FLT; + break; + case 'J': + td->decltype = PRIMITIVETYPE_LONG; + td->type = TYPE_LNG; + break; + case 'V': + td->decltype = PRIMITIVETYPE_VOID; + td->type = TYPE_VOID; + break; + default: + assert(false); + } + + td->arraydim = 0; + td->classref = NULL; + } + + return true; +} + + +/* descriptor_pool_new ********************************************************* + + Allocate a new descriptor_pool + + IN: + referer..........class for which to create the pool + + RETURN VALUE: + a pointer to the new descriptor_pool + +*******************************************************************************/ + +descriptor_pool * +descriptor_pool_new(classinfo *referer) +{ + descriptor_pool *pool; + u4 hashsize; + u4 slot; + + pool = DNEW(descriptor_pool); + assert(pool); + + pool->referer = referer; + pool->fieldcount = 0; + pool->methodcount = 0; + pool->paramcount = 0; + pool->descriptorsize = 0; + pool->descriptors = NULL; + pool->descriptors_next = NULL; + pool->classrefs = NULL; + pool->descriptor_kind = NULL; + pool->descriptor_kind_next = NULL; + + hashsize = CLASSREFHASH_INIT_SIZE; + pool->classrefhash.size = hashsize; + pool->classrefhash.entries = 0; + pool->classrefhash.ptr = DMNEW(voidptr,hashsize); + for (slot=0; slotclassrefhash.ptr[slot] = NULL; + + hashsize = DESCRIPTORHASH_INIT_SIZE; + pool->descriptorhash.size = hashsize; + pool->descriptorhash.entries = 0; + pool->descriptorhash.ptr = DMNEW(voidptr,hashsize); + for (slot=0; slotdescriptorhash.ptr[slot] = NULL; + + return pool; +} + + +/* descriptor_pool_add_class *************************************************** + + Add the given class reference to the pool + + IN: + pool.............the descriptor_pool + name.............the class reference to add + + RETURN VALUE: + true.............reference has been added + false............an exception has been thrown + +*******************************************************************************/ + +bool +descriptor_pool_add_class(descriptor_pool *pool, utf *name) +{ + u4 key,slot; + classref_hash_entry *c; + + assert(pool); + assert(name); + +#ifdef DESCRIPTOR_VERBOSE + fprintf(stderr,"descriptor_pool_add_class(%p,",(void*)pool); + utf_fprint_printable_ascii(stderr,name);fprintf(stderr,")\n"); +#endif + + /* find a place in the hashtable */ + + key = utf_hashkey(name->text, name->blength); + slot = key & (pool->classrefhash.size - 1); + c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; + + while (c) { + if (c->name == name) + return true; /* already stored */ + c = c->hashlink; + } + + /* check if the name is a valid classname */ + + if (!is_valid_name(name->text,UTF_END(name))) { + exceptions_throw_classformaterror(pool->referer, "Invalid class name"); + return false; /* exception */ + } + + /* XXX check maximum array dimension */ + + c = DNEW(classref_hash_entry); + c->name = name; + c->index = pool->classrefhash.entries++; + c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot]; + pool->classrefhash.ptr[slot] = c; + + return true; +} + + +/* descriptor_pool_add ********************************************************* + + Check the given descriptor and add it to the pool + + IN: + pool.............the descriptor_pool + desc.............the descriptor to add. Maybe a field or method desc. + + OUT: + *paramslots......if non-NULL, set to the number of parameters. + LONG and DOUBLE are counted twice + + RETURN VALUE: + true.............descriptor has been added + false............an exception has been thrown + +*******************************************************************************/ + +bool +descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots) +{ + u4 key,slot; + descriptor_hash_entry *d; + char *utf_ptr; + char *end_pos; + utf *name; + s4 argcount = 0; + +#ifdef DESCRIPTOR_VERBOSE + fprintf(stderr,"descriptor_pool_add(%p,",(void*)pool); + utf_fprint_printable_ascii(stderr,desc);fprintf(stderr,")\n"); +#endif + + assert(pool); + assert(desc); + + /* find a place in the hashtable */ + + key = utf_hashkey(desc->text, desc->blength); + slot = key & (pool->descriptorhash.size - 1); + d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + + /* Save all method descriptors in the hashtable, since the parsed */ + /* descriptor may vary between differenf methods (static vs. non-static). */ + + utf_ptr = desc->text; + + if (*utf_ptr != '(') { + while (d) { + if (d->desc == desc) { + if (paramslots) + *paramslots = d->paramslots; + return true; /* already stored */ + } + d = d->hashlink; + } + } + + /* add the descriptor to the pool */ + + d = DNEW(descriptor_hash_entry); + d->desc = desc; + d->parseddesc.any = NULL; + d->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + pool->descriptorhash.ptr[slot] = d; + + /* now check the descriptor */ + + end_pos = UTF_END(desc); + + if (*utf_ptr == '(') { + /* a method descriptor */ + + pool->methodcount++; + utf_ptr++; + + /* check arguments */ + + while ((utf_ptr != end_pos) && (*utf_ptr != ')')) { + pool->paramcount++; + + /* We cannot count the `this' argument here because + * we don't know if the method is static. */ + + if (*utf_ptr == 'J' || *utf_ptr == 'D') + argcount += 2; + else + argcount++; + + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr, + DESCRIPTOR_NOVOID, &name)) + return false; + + if (name) + if (!descriptor_pool_add_class(pool, name)) + return false; + } + + if (utf_ptr == end_pos) { + exceptions_throw_classformaterror(pool->referer, + "Missing ')' in method descriptor"); + return false; + } + + utf_ptr++; /* skip ')' */ + + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, + DESCRIPTOR_CHECKEND, &name)) + return false; + + if (name) + if (!descriptor_pool_add_class(pool,name)) + return false; + + if (argcount > 255) { + exceptions_throw_classformaterror(pool->referer, + "Too many arguments in signature"); + return false; + } + + } else { + /* a field descriptor */ + + pool->fieldcount++; + + if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL, + DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND, + &name)) + return false; + + if (name) + if (!descriptor_pool_add_class(pool,name)) + return false; + } + + d->paramslots = argcount; + + if (paramslots) + *paramslots = argcount; + + return true; +} + + +/* descriptor_pool_create_classrefs ******************************************** + + Create a table containing all the classrefs which were added to the pool + + IN: + pool.............the descriptor_pool + + OUT: + *count...........if count is non-NULL, this is set to the number + of classrefs in the table + + RETURN VALUE: + a pointer to the constant_classref table + +*******************************************************************************/ + +constant_classref * +descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count) +{ + u4 nclasses; + u4 slot; + classref_hash_entry *c; + constant_classref *ref; + + assert(pool); + + nclasses = pool->classrefhash.entries; + pool->classrefs = MNEW(constant_classref,nclasses); + + /* fill the constant_classref structs */ + + for (slot = 0; slot < pool->classrefhash.size; ++slot) { + c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; + while (c) { + ref = pool->classrefs + c->index; + CLASSREF_INIT(*ref, pool->referer, c->name); + c = c->hashlink; + } + } + + if (count) + *count = nclasses; + + return pool->classrefs; +} + + +/* descriptor_pool_lookup_classref ********************************************* + + Return the constant_classref for the given class name + + IN: + pool.............the descriptor_pool + classname........name of the class to look up + + RETURN VALUE: + a pointer to the constant_classref, or + NULL if an exception has been thrown + +*******************************************************************************/ + +constant_classref * +descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname) +{ + u4 key,slot; + classref_hash_entry *c; + + assert(pool); + assert(pool->classrefs); + assert(classname); + + key = utf_hashkey(classname->text, classname->blength); + slot = key & (pool->classrefhash.size - 1); + c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; + + while (c) { + if (c->name == classname) + return pool->classrefs + c->index; + c = c->hashlink; + } + + exceptions_throw_internalerror("Class reference not found in descriptor pool"); + return NULL; +} + + +/* descriptor_pool_alloc_parsed_descriptors ************************************ + + Allocate space for the parsed descriptors + + IN: + pool.............the descriptor_pool + + NOTE: + This function must be called after all descriptors have been added + with descriptor_pool_add. + +*******************************************************************************/ + +void +descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool) +{ + u4 size; + + assert(pool); + + /* TWISTI: paramcount + 1: we don't know if the method is static or */ + /* not, i have no better solution yet. */ + + size = + pool->fieldcount * sizeof(typedesc) + + pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) + + pool->paramcount * sizeof(typedesc) + + pool->methodcount * sizeof(typedesc); /* possible `this' pointer */ + + pool->descriptorsize = size; + if (size) { + pool->descriptors = MNEW(u1, size); + pool->descriptors_next = pool->descriptors; + } + + size = pool->fieldcount + pool->methodcount; + if (size) { + pool->descriptor_kind = DMNEW(u1, size); + pool->descriptor_kind_next = pool->descriptor_kind; + } +} + + +/* descriptor_pool_parse_field_descriptor ************************************** + + Parse the given field descriptor + + IN: + pool.............the descriptor_pool + desc.............the field descriptor + + RETURN VALUE: + a pointer to the parsed field descriptor, or + NULL if an exception has been thrown + + NOTE: + descriptor_pool_alloc_parsed_descriptors must be called (once) + before this function is used. + +*******************************************************************************/ + +typedesc * +descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc) +{ + u4 key,slot; + descriptor_hash_entry *d; + typedesc *td; + + assert(pool); + assert(pool->descriptors); + assert(pool->descriptors_next); + + /* lookup the descriptor in the hashtable */ + + key = utf_hashkey(desc->text, desc->blength); + slot = key & (pool->descriptorhash.size - 1); + d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + + while (d) { + if (d->desc == desc) { + /* found */ + if (d->parseddesc.fd) + return d->parseddesc.fd; + break; + } + d = d->hashlink; + } + + assert(d); + + if (desc->text[0] == '(') { + exceptions_throw_classformaterror(pool->referer, + "Method descriptor used in field reference"); + return NULL; + } + + td = (typedesc *) pool->descriptors_next; + pool->descriptors_next += sizeof(typedesc); + + if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td)) + return NULL; + + *(pool->descriptor_kind_next++) = 'f'; + + d->parseddesc.fd = td; + + return td; +} + + +/* descriptor_pool_parse_method_descriptor ************************************* + + Parse the given method descriptor + + IN: + pool.............the descriptor_pool + desc.............the method descriptor + mflags...........the method flags + thisclass........classref to the class containing the method. + This is ignored if mflags contains ACC_STATIC. + The classref is stored for inserting the 'this' argument. + + RETURN VALUE: + a pointer to the parsed method descriptor, or + NULL if an exception has been thrown + + NOTE: + descriptor_pool_alloc_parsed_descriptors must be called + (once) before this function is used. + +*******************************************************************************/ + +methoddesc * +descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, + s4 mflags,constant_classref *thisclass) +{ + u4 key, slot; + descriptor_hash_entry *d; + methoddesc *md; + typedesc *td; + char *utf_ptr; + char *end_pos; + s2 paramcount = 0; + s2 paramslots = 0; + +#ifdef DESCRIPTOR_VERBOSE + fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,", + (void*)pool,(int)mflags,(void*)thisclass); + utf_fprint_printable_ascii(stderr,desc); fprintf(stderr,")\n"); +#endif + + assert(pool); + assert(pool->descriptors); + assert(pool->descriptors_next); + + /* check that it is a method descriptor */ + + if (desc->text[0] != '(') { + exceptions_throw_classformaterror(pool->referer, + "Field descriptor used in method reference"); + return NULL; + } + + /* lookup the descriptor in the hashtable */ + + key = utf_hashkey(desc->text, desc->blength); + slot = key & (pool->descriptorhash.size - 1); + d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + + /* find an un-parsed descriptor */ + + while (d) { + if (d->desc == desc) + if (!d->parseddesc.md) + break; + d = d->hashlink; + } + + assert(d); + + md = (methoddesc *) pool->descriptors_next; + pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc); + + utf_ptr = desc->text + 1; /* skip '(' */ + end_pos = UTF_END(desc); + + td = md->paramtypes; + + /* count the `this' pointer */ + + if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) { + td->type = TYPE_ADR; + td->decltype = TYPE_ADR; + td->arraydim = 0; + td->classref = thisclass; + + td++; + pool->descriptors_next += sizeof(typedesc); + paramcount++; + paramslots++; + } + + while (*utf_ptr != ')') { + /* parse a parameter type */ + + if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td)) + return NULL; + + if (IS_2_WORD_TYPE(td->type)) + paramslots++; + + td++; + pool->descriptors_next += sizeof(typedesc); + paramcount++; + paramslots++; + } + utf_ptr++; /* skip ')' */ + + /* Skip possible `this' pointer in paramtypes array to allow a possible */ + /* memory move later in parse. */ + /* We store the thisclass reference, so we can later correctly fill in */ + /* the parameter slot of the 'this' argument. */ + + if (mflags == ACC_UNDEF) { + td->classref = thisclass; + td++; + pool->descriptors_next += sizeof(typedesc); + } + + /* parse return type */ + + if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL, + &(md->returntype))) + return NULL; + + md->paramcount = paramcount; + md->paramslots = paramslots; + + /* If m != ACC_UNDEF we parse a real loaded method, so do param prealloc. */ + /* Otherwise we do this in stack analysis. */ + + if (mflags != ACC_UNDEF) { + if (md->paramcount > 0) { + /* allocate memory for params */ + + md->params = MNEW(paramdesc, md->paramcount); + } + else { + md->params = METHODDESC_NOPARAMS; + } + + /* fill the paramdesc */ + /* md_param_alloc has to be called if md->paramcount == 0, + too, so it can make the reservation for the Linkage Area, + Return Register... */ + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (!opt_intrp) +# endif + md_param_alloc(md); +#endif + + } else { + /* params will be allocated later by + descriptor_params_from_paramtypes if necessary */ + + md->params = NULL; + } + + *(pool->descriptor_kind_next++) = 'm'; + + d->parseddesc.md = md; + + return md; +} + +/* descriptor_params_from_paramtypes ******************************************* + + Create the paramdescs for a method descriptor. This function is called + when we know whether the method is static or not. This function may only + be called once for each methoddesc, and only if md->params == NULL. + + IN: + md...............the parsed method descriptor + md->params MUST be NULL. + mflags...........the ACC_* access flags of the method. Only the + ACC_STATIC bit is checked. + The value ACC_UNDEF is NOT allowed. + + RETURN VALUE: + true.............the paramdescs were created successfully + false............an exception has been thrown + + POSTCONDITION: + md->parms != NULL + +*******************************************************************************/ + +bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags) +{ + typedesc *td; + + assert(md); + assert(md->params == NULL); + assert(mflags != ACC_UNDEF); + + td = md->paramtypes; + + /* check for `this' pointer */ + + if (!(mflags & ACC_STATIC)) { + constant_classref *thisclass; + + /* fetch class reference from reserved param slot */ + thisclass = td[md->paramcount].classref; + assert(thisclass); + + if (md->paramcount > 0) { + /* shift param types by 1 argument */ + MMOVE(td + 1, td, typedesc, md->paramcount); + } + + /* fill in first argument `this' */ + + td->type = TYPE_ADR; + td->decltype = TYPE_ADR; + td->arraydim = 0; + td->classref = thisclass; + + md->paramcount++; + md->paramslots++; + } + + /* if the method has params, process them */ + + if (md->paramcount > 0) { + /* allocate memory for params */ + + md->params = MNEW(paramdesc, md->paramcount); + + } else { + md->params = METHODDESC_NOPARAMS; + } + + /* fill the paramdesc */ + /* md_param_alloc has to be called if md->paramcount == 0, too, so + it can make the reservation for the Linkage Area, Return + Register.. */ + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (!opt_intrp) +# endif + md_param_alloc(md); +#endif + + return true; +} + + +/* descriptor_pool_get_parsed_descriptors ************************************** + + Return a pointer to the block of parsed descriptors + + IN: + pool.............the descriptor_pool + + OUT: + *size............if size is non-NULL, this is set to the size of the + parsed descriptor block (in u1) + + RETURN VALUE: + a pointer to the block of parsed descriptors + + NOTE: + descriptor_pool_alloc_parsed_descriptors must be called (once) + before this function is used. + +*******************************************************************************/ + +void * +descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size) +{ + assert(pool); + assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); + + if (size) + *size = pool->descriptorsize; + + return pool->descriptors; +} + + +/* descriptor_pool_get_sizes *************************************************** + + Get the sizes of the class reference table and the parsed descriptors + + IN: + pool.............the descriptor_pool + + OUT: + *classrefsize....set to size of the class reference table + *descsize........set to size of the parsed descriptors + + NOTE: + This function may only be called after both + descriptor_pool_create_classrefs, and + descriptor_pool_alloc_parsed_descriptors + have been called. + +*******************************************************************************/ + +void +descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize) +{ + assert(pool); + assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors); + assert(pool->classrefs); + assert(classrefsize); + assert(descsize); + + *classrefsize = pool->classrefhash.entries * sizeof(constant_classref); + *descsize = pool->descriptorsize; +} + + +/****************************************************************************/ +/* DEBUG HELPERS */ +/****************************************************************************/ + +#ifndef NDEBUG +/* descriptor_debug_print_typedesc ********************************************* + + Print the given typedesc to the given stream + + IN: + file.............stream to print to + d................the parsed descriptor + +*******************************************************************************/ + +void +descriptor_debug_print_typedesc(FILE *file,typedesc *d) +{ + int ch; + + if (!d) { + fprintf(file,"(typedesc *)NULL"); + return; + } + + if (d->type == TYPE_ADR) { + if (d->classref) + utf_fprint_printable_ascii(file,d->classref->name); + else + fprintf(file,""); + } + else { + switch (d->decltype) { + case PRIMITIVETYPE_INT : ch='I'; break; + case PRIMITIVETYPE_CHAR : ch='C'; break; + case PRIMITIVETYPE_BYTE : ch='B'; break; + case PRIMITIVETYPE_SHORT : ch='S'; break; + case PRIMITIVETYPE_BOOLEAN: ch='Z'; break; + case PRIMITIVETYPE_LONG : ch='J'; break; + case PRIMITIVETYPE_FLOAT : ch='F'; break; + case PRIMITIVETYPE_DOUBLE : ch='D'; break; + case PRIMITIVETYPE_VOID : ch='V'; break; + default : ch='!'; + } + fputc(ch,file); + } + if (d->arraydim) + fprintf(file,"[%d]",d->arraydim); +} + +/* descriptor_debug_print_paramdesc ******************************************** + + Print the given paramdesc to the given stream + + IN: + file.............stream to print to + d................the parameter descriptor + +*******************************************************************************/ + +void +descriptor_debug_print_paramdesc(FILE *file,paramdesc *d) +{ + if (!d) { + fprintf(file,"(paramdesc *)NULL"); + return; + } + + if (d->inmemory) { + fprintf(file,"",d->regoff); + } + else { + fprintf(file,"",d->regoff); + } +} + +/* descriptor_debug_print_methoddesc ******************************************* + + Print the given methoddesc to the given stream + + IN: + file.............stream to print to + d................the parsed descriptor + +*******************************************************************************/ + +void +descriptor_debug_print_methoddesc(FILE *file,methoddesc *d) +{ + int i; + + if (!d) { + fprintf(file,"(methoddesc *)NULL"); + return; + } + + fputc('(',file); + for (i=0; iparamcount; ++i) { + if (i) + fputc(',',file); + descriptor_debug_print_typedesc(file,d->paramtypes + i); + if (d->params) { + descriptor_debug_print_paramdesc(file,d->params + i); + } + } + if (d->params == METHODDESC_NOPARAMS) + fputs("",file); + fputc(')',file); + descriptor_debug_print_typedesc(file,&(d->returntype)); +} + +/* descriptor_pool_debug_dump ************************************************** + + Print the state of the descriptor_pool to the given stream + + IN: + pool.............the descriptor_pool + file.............stream to print to + +*******************************************************************************/ + +void +descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file) +{ + u4 slot; + u1 *pos; + u1 *kind; + u4 size; + + fprintf(file,"======[descriptor_pool for "); + utf_fprint_printable_ascii(file,pool->referer->name); + fprintf(file,"]======\n"); + + fprintf(file,"fieldcount: %d\n",pool->fieldcount); + fprintf(file,"methodcount: %d\n",pool->methodcount); + fprintf(file,"paramcount: %d\n",pool->paramcount); + fprintf(file,"classrefcount: %d\n",pool->classrefhash.entries); + fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize); + fprintf(file,"classrefsize: %d bytes\n", + (int)(pool->classrefhash.entries * sizeof(constant_classref))); + + fprintf(file,"class references:\n"); + for (slot=0; slotclassrefhash.size; ++slot) { + classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot]; + while (c) { + fprintf(file," %4d: ",c->index); + utf_fprint_printable_ascii(file,c->name); + fprintf(file,"\n"); + c = c->hashlink; + } + } + + fprintf(file,"hashed descriptors:\n"); + for (slot=0; slotdescriptorhash.size; ++slot) { + descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot]; + while (c) { + fprintf(file," %p: ",c->parseddesc.any); + utf_fprint_printable_ascii(file,c->desc); + fprintf(file,"\n"); + c = c->hashlink; + } + } + + fprintf(file,"descriptors:\n"); + if (pool->descriptors) { + pos = pool->descriptors; + size = pool->descriptors_next - pool->descriptors; + fprintf(file," size: %d bytes\n",size); + + if (pool->descriptor_kind) { + kind = pool->descriptor_kind; + + while (pos < (pool->descriptors + size)) { + fprintf(file," %p: ",pos); + switch (*kind++) { + case 'f': + descriptor_debug_print_typedesc(file,(typedesc*)pos); + pos += sizeof(typedesc); + break; + case 'm': + descriptor_debug_print_methoddesc(file,(methoddesc*)pos); + pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc); + pos += sizeof(methoddesc) - sizeof(typedesc); + break; + default: + fprintf(file,"INVALID KIND"); + } + fputc('\n',file); + } + } + else { + while (size >= sizeof(voidptr)) { + fprintf(file," %p\n",*((voidptr*)pos)); + pos += sizeof(voidptr); + size -= sizeof(voidptr); + } + } + } + + fprintf(file,"==========================================================\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: + */ + diff --git a/src/vmcore/descriptor.h b/src/vmcore/descriptor.h new file mode 100644 index 000000000..5ea3e2e3d --- /dev/null +++ b/src/vmcore/descriptor.h @@ -0,0 +1,199 @@ +/* src/vmcore/descriptor.h - checking and parsing of field / method descriptors + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: descriptor.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _DESCRIPTOR_H +#define _DESCRIPTOR_H + +/* forward typedefs ***********************************************************/ + +typedef struct descriptor_pool descriptor_pool; +typedef struct typedesc typedesc; +typedef struct paramdesc paramdesc; +typedef struct methoddesc methoddesc; + + +#include "config.h" +#include "vm/types.h" + +#include "toolbox/hashtable.h" + +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/references.h" +#include "vmcore/utf8.h" + + +/* data structures ************************************************************/ + +/*----------------------------------------------------------------------------*/ +/* Descriptor Pools */ +/* */ +/* A descriptor_pool is a temporary data structure used during loading of */ +/* a class. The descriptor_pool is used to allocate the table of */ +/* constant_classrefs the class uses, and for parsing the field and method */ +/* descriptors which occurr within the class. The inner workings of */ +/* descriptor_pool are not important for outside code. */ +/* */ +/* You use a descriptor_pool as follows: */ +/* */ +/* 1. create one with descriptor_pool_new */ +/* 2. add all explicit class references with descriptor_pool_add_class */ +/* 3. add all field/method descriptors with descriptor_pool_add */ +/* 4. call descriptor_pool_create_classrefs */ +/* You can now lookup classrefs with descriptor_pool_lookup_classref */ +/* 5. call descriptor_pool_alloc_parsed_descriptors */ +/* 6. for each field descriptor call descriptor_pool_parse_field_descriptor */ +/* for each method descriptor call descriptor_pool_parse_method_descriptor */ +/* 7. call descriptor_pool_get_parsed_descriptors */ +/* */ +/* IMPORTANT: The descriptor_pool functions use DNEW and DMNEW for allocating */ +/* memory which can be thrown away when the steps above have been */ +/* done. */ +/*----------------------------------------------------------------------------*/ + +struct descriptor_pool { + classinfo *referer; + u4 fieldcount; + u4 methodcount; + u4 paramcount; + u4 descriptorsize; + u1 *descriptors; + u1 *descriptors_next; + hashtable descriptorhash; + constant_classref *classrefs; + hashtable classrefhash; + u1 *descriptor_kind; /* useful for debugging */ + u1 *descriptor_kind_next; /* useful for debugging */ +}; + + +/* data structures for parsed field/method descriptors ************************/ + +struct typedesc { + constant_classref *classref; /* class reference for TYPE_ADR types */ + u1 type; /* TYPE_??? constant [1] */ + u1 decltype; /* (PRIMITIVE)TYPE_??? constant [2] */ + u1 arraydim; /* array dimension (0 if no array) */ +}; + +/* [1]...the type field contains the basic type used within the VM. So ints, */ +/* shorts, chars, bytes, booleans all have TYPE_INT. */ +/* [2]...the decltype field contains the declared type. */ +/* So short is PRIMITIVETYPE_SHORT, char is PRIMITIVETYPE_CHAR. */ +/* For non-primitive types decltype is TYPE_ADR. */ + +struct paramdesc { +#if defined(__MIPS__) + u1 type; /* TYPE_??? of the register allocated */ +#endif + bool inmemory; /* argument in register or on stack */ + s4 regoff; /* register index or stack offset */ +}; + +struct methoddesc { + s2 paramcount; /* number of parameters */ + s2 paramslots; /* like above but LONG,DOUBLE count twice */ + s4 argintreguse; /* number of used integer argument registers */ + s4 argfltreguse; /* number of used float argument registers */ + s4 memuse; /* number of stack slots used */ + paramdesc *params; /* allocated parameter descriptions [3] */ + typedesc returntype; /* parsed descriptor of the return type */ + typedesc paramtypes[1]; /* parameter types, variable length! */ +}; + +/* [3]...If params is NULL, the parameter descriptions have not yet been */ +/* allocated. In this case ___the possible 'this' pointer of the method */ +/* is NOT counted in paramcount/paramslots and it is NOT included in */ +/* the paramtypes array___. */ +/* If params != NULL, the parameter descriptions have been */ +/* allocated, and the 'this' pointer of the method, if any, IS included.*/ +/* In case the method has no parameters at all, the special value */ +/* METHODDESC_NO_PARAMS is used (see below). */ + +/* METHODDESC_NO_PARAMS is a special value for the methoddesc.params field */ +/* indicating that the method is a static method without any parameters. */ +/* This special value must be != NULL and it may only be set if */ +/* md->paramcount == 0. */ + +#define METHODDESC_NOPARAMS ((paramdesc*)1) + +/* function prototypes ********************************************************/ + +descriptor_pool * descriptor_pool_new(classinfo *referer); + +bool descriptor_pool_add_class(descriptor_pool *pool,utf *name); +bool descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots); + +u2 descriptor_to_basic_type(utf *desc); +u2 descriptor_typesize(typedesc *td); + +constant_classref * descriptor_pool_create_classrefs(descriptor_pool *pool, + s4 *count); +constant_classref * descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname); + +void descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool); + +typedesc *descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc); +methoddesc *descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, s4 mflags, + constant_classref *thisclass); + +bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags); + +void *descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size); +void descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, + u4 *descsize); + +#ifndef NDEBUG +void descriptor_debug_print_typedesc(FILE *file,typedesc *d); +void descriptor_debug_print_methoddesc(FILE *file,methoddesc *d); +void descriptor_debug_print_paramdesc(FILE *file,paramdesc *d); +void descriptor_pool_debug_dump(descriptor_pool *pool, FILE *file); +#endif /* !defined(NDEBUG) */ + +/* machine dependent descriptor function */ +void md_param_alloc(methoddesc *md); + +#endif /* _DESCRIPTOR_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: + */ diff --git a/src/vmcore/field.c b/src/vmcore/field.c new file mode 100644 index 000000000..01b5f72b8 --- /dev/null +++ b/src/vmcore/field.c @@ -0,0 +1,175 @@ +/* src/vmcore/field.c - field functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: field.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "vmcore/field.h" +#include "vmcore/references.h" +#include "vmcore/utf8.h" + + +/* field_free ****************************************************************** + + Frees a fields' resources. + +*******************************************************************************/ + +void field_free(fieldinfo *f) +{ + /* empty */ +} + + +/* field_printflags ************************************************************ + + (debugging only) + +*******************************************************************************/ + +#if !defined(NDEBUG) +void field_printflags(fieldinfo *f) +{ + if (f == NULL) { + printf("NULL"); + return; + } + + if (f->flags & ACC_PUBLIC) printf(" PUBLIC"); + if (f->flags & ACC_PRIVATE) printf(" PRIVATE"); + if (f->flags & ACC_PROTECTED) printf(" PROTECTED"); + if (f->flags & ACC_STATIC) printf(" STATIC"); + if (f->flags & ACC_FINAL) printf(" FINAL"); + if (f->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED"); + if (f->flags & ACC_VOLATILE) printf(" VOLATILE"); + if (f->flags & ACC_TRANSIENT) printf(" TRANSIENT"); + if (f->flags & ACC_NATIVE) printf(" NATIVE"); + if (f->flags & ACC_INTERFACE) printf(" INTERFACE"); + if (f->flags & ACC_ABSTRACT) printf(" ABSTRACT"); +} +#endif + + +/* field_print ***************************************************************** + + (debugging only) + +*******************************************************************************/ + +#if !defined(NDEBUG) +void field_print(fieldinfo *f) +{ + if (f == NULL) { + printf("(fieldinfo*)NULL"); + return; + } + + utf_display_printable_ascii_classname(f->class->name); + printf("."); + utf_display_printable_ascii(f->name); + printf(" "); + utf_display_printable_ascii(f->descriptor); + + field_printflags(f); +} +#endif + + +/* field_println *************************************************************** + + (debugging only) + +*******************************************************************************/ + +#if !defined(NDEBUG) +void field_println(fieldinfo *f) +{ + field_print(f); + printf("\n"); +} +#endif + +/* field_fieldref_print ******************************************************** + + (debugging only) + +*******************************************************************************/ + +#if !defined(NDEBUG) +void field_fieldref_print(constant_FMIref *fr) +{ + if (fr == NULL) { + printf("(constant_FMIref *)NULL"); + return; + } + + if (IS_FMIREF_RESOLVED(fr)) { + printf(" "); + field_print(fr->p.field); + } + else { + printf(" "); + utf_display_printable_ascii_classname(fr->p.classref->name); + printf("."); + utf_display_printable_ascii(fr->name); + printf(" "); + utf_display_printable_ascii(fr->descriptor); + } +} +#endif + +/* field_fieldref_println ****************************************************** + + (debugging only) + +*******************************************************************************/ + +#if !defined(NDEBUG) +void field_fieldref_println(constant_FMIref *fr) +{ + field_fieldref_print(fr); + printf("\n"); +} +#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: + */ diff --git a/src/vmcore/field.h b/src/vmcore/field.h new file mode 100644 index 000000000..dcbd1eec8 --- /dev/null +++ b/src/vmcore/field.h @@ -0,0 +1,99 @@ +/* src/vmcore/field.h - field functions header + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: field.h 7246 2007-01-29 18:49:05Z twisti $ +*/ + + +#ifndef _FIELD_H +#define _FIELD_H + +/* forward typedefs ***********************************************************/ + +typedef struct fieldinfo fieldinfo; + + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vmcore/descriptor.h" +#include "vmcore/class.h" +#include "vmcore/references.h" +#include "vmcore/utf8.h" + + +/* fieldinfo ******************************************************************/ + +struct fieldinfo { /* field of a class */ + + /* CAUTION: The first field must be a pointer that is never the same */ + /* value as CLASSREF_PSEUDO_VFTBL! This is used to check whether */ + /* a constant_FMIref has been resolved. */ + + classinfo *class; /* needed by typechecker. Could be optimized */ + /* away by using constant_FMIref instead of */ + /* fieldinfo throughout the compiler. */ + + s4 flags; /* ACC flags */ + s4 type; /* basic data type */ + utf *name; /* name of field */ + utf *descriptor;/* JavaVM descriptor string of field */ + utf *signature; /* Signature attribute string */ + typedesc *parseddesc;/* parsed descriptor */ + + s4 offset; /* offset from start of object (instance variables) */ + + imm_union value; /* storage for static values (class variables) */ +}; + + +/* function prototypes ********************************************************/ + +void field_free(fieldinfo *f); + +#if !defined(NDEBUG) +void field_printflags(fieldinfo *f); +void field_print(fieldinfo *f); +void field_println(fieldinfo *f); +void field_fieldref_print(constant_FMIref *fr); +void field_fieldref_println(constant_FMIref *fr); +#endif + +#endif /* _FIELD_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: + */ diff --git a/src/vmcore/linker.c b/src/vmcore/linker.c new file mode 100644 index 000000000..91ea0d774 --- /dev/null +++ b/src/vmcore/linker.c @@ -0,0 +1,1399 @@ +/* src/vmcore/linker.c - class linker functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: linker.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "mm/memory.h" +#include "native/native.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#else +# include "threads/none/lock.h" +#endif + +#include "toolbox/logging.h" + +#include "vm/access.h" +#include "vm/exceptions.h" +#include "vm/stringlocal.h" +#include "vm/vm.h" + +#include "vm/jit/asmpart.h" + +#include "vmcore/class.h" +#include "vmcore/classcache.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" +#include "vmcore/rt-timing.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#if !defined(NDEBUG) && defined(ENABLE_INLINING) +extern bool inline_debug_log; +#define INLINELOG(code) do { if (inline_debug_log) { code } } while (0) +#else +#define INLINELOG(code) +#endif + + +/* global variables ***********************************************************/ + +static s4 interfaceindex; /* sequential numbering of interfaces */ +static s4 classvalue; + + +/* primitivetype_table ********************************************************* + + Structure for primitive classes: contains the class for wrapping + the primitive type, the primitive class, the name of the class for + wrapping, the one character type signature and the name of the + primitive class. + + CAUTION: Don't change the order of the types. This table is indexed + by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT). + +*******************************************************************************/ + +primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { + { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL }, + { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL }, + { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL }, + { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL }, + { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, + { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL }, + { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL }, + { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL }, + { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL }, + { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, +#if defined(ENABLE_JAVASE) + { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL } +#else + { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, +#endif +}; + + +/* private functions **********************************************************/ + +static bool link_primitivetype_table(void); +static classinfo *link_class_intern(classinfo *c); +static arraydescriptor *link_array(classinfo *c); +static void linker_compute_class_values(classinfo *c); +static void linker_compute_subclasses(classinfo *c); +static bool linker_addinterface(classinfo *c, classinfo *ic); +static s4 class_highestinterface(classinfo *c); + + +/* linker_init ***************************************************************** + + Initializes the linker subsystem. + +*******************************************************************************/ + +bool linker_init(void) +{ + /* reset interface index */ + + interfaceindex = 0; + + /* link java.lang.Class as first class of the system, because we + need it's vftbl for all other classes so we can use a class as + object */ + + if (!link_class(class_java_lang_Class)) + return false; + + /* now set the header.vftbl of all classes which were created + before java.lang.Class was linked */ + + class_postset_header_vftbl(); + + + /* link important system classes */ + + if (!link_class(class_java_lang_Object)) + return false; + + if (!link_class(class_java_lang_String)) + return false; + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_Cloneable)) + return false; + + if (!link_class(class_java_io_Serializable)) + return false; +#endif + + + /* link classes for wrapping primitive types */ + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_Void)) + return false; +#endif + + if (!link_class(class_java_lang_Boolean)) + return false; + + if (!link_class(class_java_lang_Byte)) + return false; + + if (!link_class(class_java_lang_Character)) + return false; + + if (!link_class(class_java_lang_Short)) + return false; + + if (!link_class(class_java_lang_Integer)) + return false; + + if (!link_class(class_java_lang_Long)) + return false; + + if (!link_class(class_java_lang_Float)) + return false; + + if (!link_class(class_java_lang_Double)) + return false; + + + /* load some other important classes */ + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_ClassLoader)) + return false; + + if (!link_class(class_java_lang_SecurityManager)) + return false; +#endif + + if (!link_class(class_java_lang_System)) + return false; + + if (!link_class(class_java_lang_Thread)) + return false; + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_ThreadGroup)) + return false; +#endif + +#if defined(WITH_CLASSPATH_GNU) + if (!link_class(class_java_lang_VMSystem)) + return false; + + if (!link_class(class_java_lang_VMThread)) + return false; +#endif + + + /* some classes which may be used more often */ + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_StackTraceElement)) + return false; + + if (!link_class(class_java_lang_reflect_Constructor)) + return false; + + if (!link_class(class_java_lang_reflect_Field)) + return false; + + if (!link_class(class_java_lang_reflect_Method)) + return false; + + if (!link_class(class_java_security_PrivilegedAction)) + return false; + + if (!link_class(class_java_util_Vector)) + return false; + + if (!link_class(arrayclass_java_lang_Object)) + return false; +#endif + + + /* create pseudo classes used by the typechecker */ + + /* pseudo class for Arraystubs (extends java.lang.Object) */ + + pseudo_class_Arraystub = + class_create_classinfo(utf_new_char("$ARRAYSTUB$")); + pseudo_class_Arraystub->state |= CLASS_LOADED; + pseudo_class_Arraystub->super.cls = class_java_lang_Object; + +#if defined(ENABLE_JAVASE) + pseudo_class_Arraystub->interfacescount = 2; + pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2); + pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable; + pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable; +#elif defined(ENABLE_JAVAME_CLDC1_1) + pseudo_class_Arraystub->interfacescount = 0; + pseudo_class_Arraystub->interfaces = NULL; +#endif + + if (!classcache_store_unique(pseudo_class_Arraystub)) { + log_text("could not cache pseudo_class_Arraystub"); + assert(0); + } + + if (!link_class(pseudo_class_Arraystub)) + return false; + + /* pseudo class representing the null type */ + + pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); + pseudo_class_Null->state |= CLASS_LOADED; + pseudo_class_Null->super.cls = class_java_lang_Object; + + if (!classcache_store_unique(pseudo_class_Null)) + vm_abort("linker_init: could not cache pseudo_class_Null"); + + if (!link_class(pseudo_class_Null)) + return false; + + /* pseudo class representing new uninitialized objects */ + + pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); + pseudo_class_New->state |= CLASS_LOADED; + pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */ + pseudo_class_New->super.cls = class_java_lang_Object; + + if (!classcache_store_unique(pseudo_class_New)) + vm_abort("linker_init: could not cache pseudo_class_New"); + + /* create classes representing primitive types */ + + if (!link_primitivetype_table()) + return false; + + + /* Correct vftbl-entries (retarded loading and linking of class + java/lang/String). */ + + stringtable_update(); + + return true; +} + + +/* link_primitivetype_table **************************************************** + + Create classes representing primitive types. + +*******************************************************************************/ + +static bool link_primitivetype_table(void) +{ + classinfo *c; + utf *u; + s4 i; + + for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { + /* skip dummies */ + + if (!primitivetype_table[i].name) + continue; + + /* create primitive class */ + + c = class_create_classinfo(utf_new_char(primitivetype_table[i].name)); + + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + + /* prevent loader from loading primitive class */ + + c->state |= CLASS_LOADED; + + /* INFO: don't put primitive classes into the classcache */ + + if (!link_class(c)) + return false; + + primitivetype_table[i].class_primitive = c; + + /* create class for wrapping the primitive type */ + + u = utf_new_char(primitivetype_table[i].wrapname); + + if (!(c = load_class_bootstrap(u))) + return false; + + primitivetype_table[i].class_wrap = c; + + /* create the primitive array class */ + + if (primitivetype_table[i].arrayname) { + u = utf_new_char(primitivetype_table[i].arrayname); + c = class_create_classinfo(u); + c = load_newly_created_array(c, NULL); + if (c == NULL) + return false; + + primitivetype_table[i].arrayclass = c; + + assert(c->state & CLASS_LOADED); + + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + return false; + + primitivetype_table[i].arrayvftbl = c->vftbl; + } + } + + return true; +} + + +/* link_class ****************************************************************** + + Wrapper function for link_class_intern to ease monitor enter/exit + and exception handling. + +*******************************************************************************/ + +classinfo *link_class(classinfo *c) +{ + classinfo *r; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_end; +#endif + + RT_TIMING_GET_TIME(time_start); + + if (c == NULL) { + exceptions_throw_nullpointerexception(); + return NULL; + } + + LOCK_MONITOR_ENTER(c); + + /* maybe the class is already linked */ + + if (c->state & CLASS_LINKED) { + LOCK_MONITOR_EXIT(c); + + return c; + } + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_stop(); + + if (opt_getloadingtime) + loadingtime_start(); +#endif + + /* call the internal function */ + + r = link_class_intern(c); + + /* if return value is NULL, we had a problem and the class is not linked */ + + if (!r) + c->state &= ~CLASS_LINKING; + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getloadingtime) + loadingtime_stop(); + + if (opt_getcompilingtime) + compilingtime_start(); +#endif + + LOCK_MONITOR_EXIT(c); + + RT_TIMING_GET_TIME(time_end); + + RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL); + + return r; +} + + +/* linker_overwrite_method ***************************************************** + + Overwrite a method with another one, update method flags and check + assumptions. + + IN: + mg................the general method being overwritten + ms................the overwriting (more specialized) method + wl................worklist where to add invalidated methods + + RETURN VALUE: + true..............everything ok + false.............an exception has been thrown + +*******************************************************************************/ + +static bool linker_overwrite_method(methodinfo *mg, + methodinfo *ms, + method_worklist **wl) +{ + classinfo *cg; + classinfo *cs; + + cg = mg->class; + cs = ms->class; + + /* overriding a final method is illegal */ + + if (mg->flags & ACC_FINAL) { + exceptions_throw_verifyerror(mg, "Overriding final method"); + return false; + } + + /* method ms overwrites method mg */ + +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more general types of method mg). */ + /* Not for , as it is not invoked virtually. */ + + if ((ms->name != utf_init) + && !classcache_add_constraints_for_params( + cs->classloader, cg->classloader, mg)) + { + return false; + } +#endif + + /* inherit the vftbl index, and record the overwriting */ + + ms->vftblindex = mg->vftblindex; + ms->overwrites = mg; + + /* update flags and check assumptions */ + /* methods are a special case, as they are never dispatched dynamically */ + + if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) { + do { + if (mg->flags & ACC_METHOD_IMPLEMENTED) { + /* this adds another implementation */ + + mg->flags &= ~ACC_METHOD_MONOMORPHIC; + + INLINELOG( printf("becomes polymorphic: "); method_println(mg); ); + + method_break_assumption_monomorphic(mg, wl); + } + else { + /* this is the first implementation */ + + mg->flags |= ACC_METHOD_IMPLEMENTED; + + INLINELOG( printf("becomes implemented: "); method_println(mg); ); + } + + ms = mg; + mg = mg->overwrites; + } while (mg != NULL); + } + + return true; +} + + +/* link_class_intern *********************************************************** + + Tries to link a class. The function calculates the length in bytes + that an instance of this class requires as well as the VTBL for + methods and interface methods. + +*******************************************************************************/ + +static classinfo *link_class_intern(classinfo *c) +{ + classinfo *super; /* super class */ + classinfo *tc; /* temporary class variable */ + s4 supervftbllength; /* vftbllegnth of super class */ + s4 vftbllength; /* vftbllength of current class */ + s4 interfacetablelength; /* interface table length */ + vftbl_t *v; /* vftbl of current class */ + s4 i; /* interface/method/field counter */ + arraydescriptor *arraydesc; /* descriptor for array classes */ + method_worklist *worklist; /* worklist for recompilation */ +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_resolving, time_compute_vftbl, + time_abstract, time_compute_iftbl, time_fill_vftbl, + time_offsets, time_fill_iftbl, time_finalizer, + time_subclasses; +#endif + + RT_TIMING_GET_TIME(time_start); + + /* the class is already linked */ + + if (c->state & CLASS_LINKED) + return c; + +#if !defined(NDEBUG) + if (linkverbose) + log_message_class("Linking class: ", c); +#endif + + /* the class must be loaded */ + + /* XXX should this be a specific exception? */ + assert(c->state & CLASS_LOADED); + + /* cache the self-reference of this class */ + /* we do this for cases where the defining loader of the class */ + /* has not yet been recorded as an initiating loader for the class */ + /* this is needed so subsequent code can assume that self-refs */ + /* will always resolve lazily */ + /* No need to do it for the bootloader - it is always registered */ + /* as initiating loader for the classes it loads. */ + if (c->classloader) + classcache_store(c->classloader,c,false); + + /* this class is currently linking */ + + c->state |= CLASS_LINKING; + + arraydesc = NULL; + worklist = NULL; + + /* check interfaces */ + + for (i = 0; i < c->interfacescount; i++) { + /* resolve this super interface */ + + if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager, + true, false, &tc)) + return NULL; + + c->interfaces[i].cls = tc; + + /* detect circularity */ + + if (tc == c) { + exceptions_throw_classcircularityerror(c); + return NULL; + } + + assert(tc->state & CLASS_LOADED); + + if (!(tc->flags & ACC_INTERFACE)) { + exceptions_throw_incompatibleclasschangeerror(tc, + "Implementing class"); + return NULL; + } + + if (!(tc->state & CLASS_LINKED)) + if (!link_class(tc)) + return NULL; + } + + /* check super class */ + + super = NULL; + + if (c->super.any == NULL) { /* class java.lang.Object */ + c->index = 0; + c->instancesize = sizeof(java_objectheader); + + vftbllength = supervftbllength = 0; + + c->finalizer = NULL; + + } else { + /* resolve super class */ + + if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false, + &super)) + return NULL; + c->super.cls = super; + + /* detect circularity */ + + if (super == c) { + exceptions_throw_classcircularityerror(c); + return NULL; + } + + assert(super->state & CLASS_LOADED); + + if (super->flags & ACC_INTERFACE) { + /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */ + log_text("Interface specified as super class"); + assert(0); + } + + /* Don't allow extending final classes */ + + if (super->flags & ACC_FINAL) { + exceptions_throw_verifyerror(NULL, + "Cannot inherit from final class"); + return NULL; + } + + /* link the superclass if necessary */ + + if (!(super->state & CLASS_LINKED)) + if (!link_class(super)) + return NULL; + + /* OR the ACC_CLASS_HAS_POINTERS flag */ + + c->flags |= (super->flags & ACC_CLASS_HAS_POINTERS); + + /* handle array classes */ + + if (c->name->text[0] == '[') + if (!(arraydesc = link_array(c))) + return NULL; + + if (c->flags & ACC_INTERFACE) + c->index = interfaceindex++; + else + c->index = super->index + 1; + + c->instancesize = super->instancesize; + + vftbllength = supervftbllength = super->vftbl->vftbllength; + + c->finalizer = super->finalizer; + } + RT_TIMING_GET_TIME(time_resolving); + + + /* compute vftbl length */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (!(m->flags & ACC_STATIC)) { /* is instance method */ + tc = super; + + while (tc) { + s4 j; + + for (j = 0; j < tc->methodscount; j++) { + if (method_canoverwrite(m, &(tc->methods[j]))) { + if (tc->methods[j].flags & ACC_PRIVATE) + goto notfoundvftblindex; + + /* package-private methods in other packages */ + /* must not be overridden */ + /* (see Java Language Specification 8.4.8.1) */ + if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) + && !SAME_PACKAGE(c,tc) ) + { + goto notfoundvftblindex; + } + + if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist)) + return NULL; + + goto foundvftblindex; + } + } + + tc = tc->super.cls; + } + + notfoundvftblindex: + m->vftblindex = (vftbllength++); + foundvftblindex: + ; + } + } + RT_TIMING_GET_TIME(time_compute_vftbl); + + + /* Check all interfaces of an abstract class (maybe be an + interface too) for unimplemented methods. Such methods are + called miranda-methods and are marked with the ACC_MIRANDA + flag. VMClass.getDeclaredMethods does not return such + methods. */ + + if (c->flags & ACC_ABSTRACT) { + classinfo *ic; + methodinfo *im; + s4 abstractmethodscount; + s4 j; + s4 k; + + abstractmethodscount = 0; + + /* check all interfaces of the abstract class */ + + for (i = 0; i < c->interfacescount; i++) { + ic = c->interfaces[i].cls; + + for (j = 0; j < ic->methodscount; j++) { + im = &(ic->methods[j]); + + /* skip `' and `' */ + + if ((im->name == utf_clinit) || (im->name == utf_init)) + continue; + + for (tc = c; tc != NULL; tc = tc->super.cls) { + for (k = 0; k < tc->methodscount; k++) { + if (method_canoverwrite(im, &(tc->methods[k]))) + goto noabstractmethod; + } + } + + abstractmethodscount++; + + noabstractmethod: + ; + } + } + + if (abstractmethodscount > 0) { + methodinfo *am; + + /* reallocate methods memory */ + + c->methods = MREALLOC(c->methods, methodinfo, c->methodscount, + c->methodscount + abstractmethodscount); + + for (i = 0; i < c->interfacescount; i++) { + ic = c->interfaces[i].cls; + + for (j = 0; j < ic->methodscount; j++) { + im = &(ic->methods[j]); + + /* skip `' and `' */ + + if ((im->name == utf_clinit) || (im->name == utf_init)) + continue; + + for (tc = c; tc != NULL; tc = tc->super.cls) { + for (k = 0; k < tc->methodscount; k++) { + if (method_canoverwrite(im, &(tc->methods[k]))) + goto noabstractmethod2; + } + } + + /* Copy the method found into the new c->methods + array and tag it as miranda-method. */ + + am = &(c->methods[c->methodscount]); + c->methodscount++; + + MCOPY(am, im, methodinfo, 1); + + am->vftblindex = (vftbllength++); + am->class = c; + am->flags |= ACC_MIRANDA; + + noabstractmethod2: + ; + } + } + } + } + RT_TIMING_GET_TIME(time_abstract); + + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += + sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); +#endif + + /* compute interfacetable length */ + + interfacetablelength = 0; + + for (tc = c; tc != NULL; tc = tc->super.cls) { + for (i = 0; i < tc->interfacescount; i++) { + s4 h = class_highestinterface(tc->interfaces[i].cls) + 1; + + if (h > interfacetablelength) + interfacetablelength = h; + } + } + RT_TIMING_GET_TIME(time_compute_iftbl); + + /* allocate virtual function table */ + + v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) + + sizeof(methodptr) * (vftbllength - 1) + + sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); + v = (vftbl_t *) (((methodptr *) v) + + (interfacetablelength - 1) * (interfacetablelength > 1)); + + c->vftbl = v; + v->class = c; + v->vftbllength = vftbllength; + v->interfacetablelength = interfacetablelength; + v->arraydesc = arraydesc; + + /* store interface index in vftbl */ + + if (c->flags & ACC_INTERFACE) + v->baseval = -(c->index); + + /* copy virtual function table of super class */ + + for (i = 0; i < supervftbllength; i++) + v->table[i] = super->vftbl->table[i]; + + /* Fill the remaining vftbl slots with the AbstractMethodError + stub (all after the super class slots, because they are already + initialized). */ + + for (; i < vftbllength; i++) { +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + } + + /* add method stubs into virtual function table */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + assert(m->stubroutine == NULL); + + /* Don't create a compiler stub for abstract methods as they + throw an AbstractMethodError with the default stub in the + vftbl. This entry is simply copied by sub-classes. */ + + if (m->flags & ACC_ABSTRACT) + continue; + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + m->stubroutine = intrp_createcompilerstub(m); + else +#endif + m->stubroutine = createcompilerstub(m); +#else + m->stubroutine = intrp_createcompilerstub(m); +#endif + + /* static methods are not in the vftbl */ + + if (m->flags & ACC_STATIC) + continue; + + /* insert the stubroutine into the vftbl */ + + v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; + } + RT_TIMING_GET_TIME(time_fill_vftbl); + + /* compute instance size and offset of each field */ + + for (i = 0; i < c->fieldscount; i++) { + s4 dsize; + fieldinfo *f = &(c->fields[i]); + + if (!(f->flags & ACC_STATIC)) { + dsize = descriptor_typesize(f->parseddesc); + + /* On i386 we only align to 4 bytes even for double and s8. */ + /* This matches what gcc does for struct members. We must */ + /* do the same as gcc here because the offsets in native */ + /* header structs like java_lang_Double must match the offsets */ + /* of the Java fields (eg. java.lang.Double.value). */ +#if defined(__I386__) + c->instancesize = MEMORY_ALIGN(c->instancesize, 4); +#else + c->instancesize = MEMORY_ALIGN(c->instancesize, dsize); +#endif + + f->offset = c->instancesize; + c->instancesize += dsize; + } + } + RT_TIMING_GET_TIME(time_offsets); + + /* initialize interfacetable and interfacevftbllength */ + + v->interfacevftbllength = MNEW(s4, interfacetablelength); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; +#endif + + for (i = 0; i < interfacetablelength; i++) { + v->interfacevftbllength[i] = 0; + v->interfacetable[-i] = NULL; + } + + /* add interfaces */ + + for (tc = c; tc != NULL; tc = tc->super.cls) + for (i = 0; i < tc->interfacescount; i++) + if (!linker_addinterface(c, tc->interfaces[i].cls)) + return NULL; + + RT_TIMING_GET_TIME(time_fill_iftbl); + + /* add finalizer method (not for java.lang.Object) */ + + if (super) { + methodinfo *fi; + + fi = class_findmethod(c, utf_finalize, utf_void__void); + + if (fi) + if (!(fi->flags & ACC_STATIC)) + c->finalizer = fi; + } + RT_TIMING_GET_TIME(time_finalizer); + + /* final tasks */ + + linker_compute_subclasses(c); + + RT_TIMING_GET_TIME(time_subclasses); + + /* revert the linking state and class is linked */ + + c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED; + + /* check worklist */ + + /* XXX must this also be done in case of exception? */ + + while (worklist != NULL) { + method_worklist *wi = worklist; + + worklist = worklist->next; + + INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); ); + jit_invalidate_code(wi->m); + + /* XXX put worklist into dump memory? */ + FREE(wi, method_worklist); + } + +#if !defined(NDEBUG) + if (linkverbose) + log_message_class("Linking done class: ", c); +#endif + + RT_TIMING_TIME_DIFF(time_start ,time_resolving ,RT_TIMING_LINK_RESOLVE); + RT_TIMING_TIME_DIFF(time_resolving ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL); + RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract ,RT_TIMING_LINK_ABSTRACT); + RT_TIMING_TIME_DIFF(time_abstract ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL); + RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl ,RT_TIMING_LINK_F_VFTBL); + RT_TIMING_TIME_DIFF(time_fill_vftbl ,time_offsets ,RT_TIMING_LINK_OFFSETS); + RT_TIMING_TIME_DIFF(time_offsets ,time_fill_iftbl ,RT_TIMING_LINK_F_IFTBL); + RT_TIMING_TIME_DIFF(time_fill_iftbl ,time_finalizer ,RT_TIMING_LINK_FINALIZER); + RT_TIMING_TIME_DIFF(time_finalizer ,time_subclasses ,RT_TIMING_LINK_SUBCLASS); + + /* just return c to show that we didn't had a problem */ + + return c; +} + + +/* link_array ****************************************************************** + + This function is called by link_class to create the arraydescriptor + for an array class. + + This function returns NULL if the array cannot be linked because + the component type has not been linked yet. + +*******************************************************************************/ + +static arraydescriptor *link_array(classinfo *c) +{ + classinfo *comp; + s4 namelen; + arraydescriptor *desc; + vftbl_t *compvftbl; + utf *u; + + comp = NULL; + namelen = c->name->blength; + + /* Check the component type */ + + switch (c->name->text[1]) { + case '[': + /* c is an array of arrays. */ + u = utf_new(c->name->text + 1, namelen - 1); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; + break; + + case 'L': + /* c is an array of objects. */ + u = utf_new(c->name->text + 2, namelen - 3); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; + break; + } + + /* If the component type has not been linked, link it now */ + + assert(!comp || (comp->state & CLASS_LOADED)); + + if (comp && !(comp->state & CLASS_LINKED)) + if (!link_class(comp)) + return NULL; + + /* Allocate the arraydescriptor */ + + desc = NEW(arraydescriptor); + + if (comp) { + /* c is an array of references */ + desc->arraytype = ARRAYTYPE_OBJECT; + desc->componentsize = sizeof(void*); + desc->dataoffset = OFFSET(java_objectarray, data); + + compvftbl = comp->vftbl; + + if (!compvftbl) { + log_text("Component class has no vftbl"); + assert(0); + } + + desc->componentvftbl = compvftbl; + + if (compvftbl->arraydesc) { + desc->elementvftbl = compvftbl->arraydesc->elementvftbl; + + if (compvftbl->arraydesc->dimension >= 255) { + log_text("Creating array of dimension >255"); + assert(0); + } + + desc->dimension = compvftbl->arraydesc->dimension + 1; + desc->elementtype = compvftbl->arraydesc->elementtype; + + } else { + desc->elementvftbl = compvftbl; + desc->dimension = 1; + desc->elementtype = ARRAYTYPE_OBJECT; + } + + } else { + /* c is an array of a primitive type */ + switch (c->name->text[1]) { + case 'Z': + desc->arraytype = ARRAYTYPE_BOOLEAN; + desc->dataoffset = OFFSET(java_booleanarray,data); + desc->componentsize = sizeof(u1); + break; + + case 'B': + desc->arraytype = ARRAYTYPE_BYTE; + desc->dataoffset = OFFSET(java_bytearray,data); + desc->componentsize = sizeof(u1); + break; + + case 'C': + desc->arraytype = ARRAYTYPE_CHAR; + desc->dataoffset = OFFSET(java_chararray,data); + desc->componentsize = sizeof(u2); + break; + + case 'D': + desc->arraytype = ARRAYTYPE_DOUBLE; + desc->dataoffset = OFFSET(java_doublearray,data); + desc->componentsize = sizeof(double); + break; + + case 'F': + desc->arraytype = ARRAYTYPE_FLOAT; + desc->dataoffset = OFFSET(java_floatarray,data); + desc->componentsize = sizeof(float); + break; + + case 'I': + desc->arraytype = ARRAYTYPE_INT; + desc->dataoffset = OFFSET(java_intarray,data); + desc->componentsize = sizeof(s4); + break; + + case 'J': + desc->arraytype = ARRAYTYPE_LONG; + desc->dataoffset = OFFSET(java_longarray,data); + desc->componentsize = sizeof(s8); + break; + + case 'S': + desc->arraytype = ARRAYTYPE_SHORT; + desc->dataoffset = OFFSET(java_shortarray,data); + desc->componentsize = sizeof(s2); + break; + + default: + exceptions_throw_noclassdeffounderror(c->name); + return NULL; + } + + desc->componentvftbl = NULL; + desc->elementvftbl = NULL; + desc->dimension = 1; + desc->elementtype = desc->arraytype; + } + + return desc; +} + + +/* linker_compute_subclasses *************************************************** + + XXX + +*******************************************************************************/ + +static void linker_compute_subclasses(classinfo *c) +{ +#if defined(ENABLE_THREADS) + compiler_lock(); +#endif + + if (!(c->flags & ACC_INTERFACE)) { + c->nextsub = 0; + c->sub = 0; + } + + if (!(c->flags & ACC_INTERFACE) && (c->super.any != NULL)) { + c->nextsub = c->super.cls->sub; + c->super.cls->sub = c; + } + + classvalue = 0; + + /* compute class values */ + + linker_compute_class_values(class_java_lang_Object); + +#if defined(ENABLE_THREADS) + compiler_unlock(); +#endif +} + + +/* linker_compute_class_values ************************************************* + + XXX + +*******************************************************************************/ + +static void linker_compute_class_values(classinfo *c) +{ + classinfo *subs; + + c->vftbl->baseval = ++classvalue; + + subs = c->sub; + + while (subs) { + linker_compute_class_values(subs); + + subs = subs->nextsub; + } + + c->vftbl->diffval = classvalue - c->vftbl->baseval; +} + + +/* linker_addinterface ********************************************************* + + Is needed by link_class for adding a VTBL to a class. All + interfaces implemented by ic are added as well. + + RETURN VALUE: + true.........everything ok + false........an exception has been thrown + +*******************************************************************************/ + +static bool linker_addinterface(classinfo *c, classinfo *ic) +{ + s4 j, k; + vftbl_t *v; + s4 i; + classinfo *sc; + methodinfo *m; + + v = c->vftbl; + i = ic->index; + + if (i >= v->interfacetablelength) + vm_abort("Internal error: interfacetable overflow"); + + /* if this interface has already been added, return immediately */ + + if (v->interfacetable[-i] != NULL) + return true; + + if (ic->methodscount == 0) { /* fake entry needed for subtype test */ + v->interfacevftbllength[i] = 1; + v->interfacetable[-i] = MNEW(methodptr, 1); + v->interfacetable[-i][0] = NULL; + } + else { + v->interfacevftbllength[i] = ic->methodscount; + v->interfacetable[-i] = MNEW(methodptr, ic->methodscount); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += sizeof(methodptr) * + (ic->methodscount + (ic->methodscount == 0)); +#endif + + for (j = 0; j < ic->methodscount; j++) { + for (sc = c; sc != NULL; sc = sc->super.cls) { + for (k = 0; k < sc->methodscount; k++) { + m = &(sc->methods[k]); + + if (method_canoverwrite(m, &(ic->methods[j]))) { + /* method m overwrites the (abstract) method */ +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more + general types of the method + ic->methods[j]). */ + if (!classcache_add_constraints_for_params( + c->classloader, ic->classloader, + &(ic->methods[j]))) + { + return false; + } +#endif + + /* XXX taken from gcj */ + /* check for ACC_STATIC: IncompatibleClassChangeError */ + + /* check for !ACC_PUBLIC: IllegalAccessError */ + + /* check for ACC_ABSTRACT: AbstracMethodError, + not sure about that one */ + + v->interfacetable[-i][j] = v->table[m->vftblindex]; + goto foundmethod; + } + } + } + + /* If no method was found, insert the AbstractMethodError + stub. */ + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->interfacetable[-i][j] = + (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + + foundmethod: + ; + } + } + + /* add superinterfaces of this interface */ + + for (j = 0; j < ic->interfacescount; j++) + if (!linker_addinterface(c, ic->interfaces[j].cls)) + return false; + + /* everything ok */ + + return true; +} + + +/* class_highestinterface ****************************************************** + + Used by the function link_class to determine the amount of memory + needed for the interface table. + +*******************************************************************************/ + +static s4 class_highestinterface(classinfo *c) +{ + s4 h; + s4 h2; + s4 i; + + /* check for ACC_INTERFACE bit already done in link_class_intern */ + + h = c->index; + + for (i = 0; i < c->interfacescount; i++) { + h2 = class_highestinterface(c->interfaces[i].cls); + + if (h2 > h) + h = h2; + } + + return 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: + */ diff --git a/src/vmcore/linker.h b/src/vmcore/linker.h new file mode 100644 index 000000000..efd6b2ed2 --- /dev/null +++ b/src/vmcore/linker.h @@ -0,0 +1,181 @@ +/* src/vmcore/linker.h - class linker header + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: linker.h 7246 2007-01-29 18:49:05Z twisti $ +*/ + + +#ifndef _LINKER_H +#define _LINKER_H + +/* forward typedefs ***********************************************************/ + +typedef struct _vftbl vftbl_t; +typedef struct arraydescriptor arraydescriptor; +typedef struct primitivetypeinfo primitivetypeinfo; + + +#include "config.h" +#include "vm/types.h" + +#include "vmcore/class.h" +#include "vmcore/references.h" + + +/* virtual function table ****************************************************** + + The vtbl has a bidirectional layout with open ends at both sides. + interfacetablelength gives the number of entries of the interface + table at the start of the vftbl. The vftbl pointer points to + &interfacetable[0]. vftbllength gives the number of entries of + table at the end of the vftbl. + + runtime type check (checkcast): + + Different methods are used for runtime type check depending on the + argument of checkcast/instanceof. + + A check against a class is implemented via relative numbering on + the class hierachy tree. The tree is numbered in a depth first + traversal setting the base field and the diff field. The diff field + gets the result of (high - base) so that a range check can be + implemented by an unsigned compare. A sub type test is done by + checking the inclusion of base of the sub class in the range of the + superclass. + + A check against an interface is implemented via the + interfacevftbl. If the interfacevftbl contains a nonnull value a + class is a subclass of this interface. + + interfacetable: + + Like standard virtual methods interface methods are called using + virtual function tables. All interfaces are numbered sequentially + (starting with zero). For each class there exist an interface table + of virtual function tables for each implemented interface. The + length of the interface table is determined by the highest number + of an implemented interface. + + The following example assumes a class which implements interface 0 and 3: + + interfacetablelength = 4 + + | ... | +----------+ + +-----------+ | method 2 |---> method z + | class | | method 1 |---> method y + +-----------+ | method 0 |---> method x + | ivftbl 0 |----------> +----------+ + vftblptr ---> +-----------+ + | ivftbl -1 |--> NULL +----------+ + | ivftbl -2 |--> NULL | method 1 |---> method x + | ivftbl -3 |-----+ | method 0 |---> method a + +-----------+ +----> +----------+ + + +---------------+ + | length 3 = 2 | + | length 2 = 0 | + | length 1 = 0 | + | length 0 = 3 | + interfacevftbllength ---> +---------------+ + +*******************************************************************************/ + +struct _vftbl { + methodptr *interfacetable[1]; /* interface table (access via macro) */ + classinfo *class; /* class, the vtbl belongs to */ + arraydescriptor *arraydesc; /* for array classes, otherwise NULL */ + s4 vftbllength; /* virtual function table length */ + s4 interfacetablelength; /* interface table length */ + s4 baseval; /* base for runtime type check */ + /* (-index for interfaces) */ + s4 diffval; /* high - base for runtime type check */ + s4 *interfacevftbllength; /* length of interface vftbls */ + methodptr table[1]; /* class vftbl */ +}; + + +/* arraydescriptor ************************************************************* + + For every array class an arraydescriptor is allocated which + describes the array class. The arraydescriptor is referenced from + the vftbl of the array class. + +*******************************************************************************/ + +struct arraydescriptor { + vftbl_t *componentvftbl; /* vftbl of the component type, NULL for primit. */ + vftbl_t *elementvftbl; /* vftbl of the element type, NULL for primitive */ + s2 arraytype; /* ARRAYTYPE_* constant */ + s2 dimension; /* dimension of the array (always >= 1) */ + s4 dataoffset; /* offset of the array data from object pointer */ + s4 componentsize; /* size of a component in bytes */ + s2 elementtype; /* ARRAYTYPE_* constant */ +}; + + +/* primitivetypeinfo **********************************************************/ + +struct primitivetypeinfo { + classinfo *class_wrap; /* class for wrapping primitive type */ + classinfo *class_primitive; /* primitive class */ + char *wrapname; /* name of class for wrapping */ + char typesig; /* one character type signature */ + char *name; /* name of primitive class */ + char *arrayname; /* name of primitive array class */ + classinfo *arrayclass; /* primitive array class */ + vftbl_t *arrayvftbl; /* vftbl of primitive array class */ +}; + + +/* global variables ***********************************************************/ + +/* This array can be indexed by the PRIMITIVETYPE_ and ARRAYTYPE_ constants */ +/* (except ARRAYTYPE_OBJECT). */ + +extern primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT]; + + +/* function prototypes ********************************************************/ + +/* initialize the linker subsystem */ +bool linker_init(void); + +/* link a class */ +classinfo *link_class(classinfo *c); + +#endif /* _LINKER_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: + */ diff --git a/src/vmcore/loader.c b/src/vmcore/loader.c new file mode 100644 index 000000000..c1bf1f706 --- /dev/null +++ b/src/vmcore/loader.c @@ -0,0 +1,2614 @@ +/* src/vmcore/loader.c - class loader functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: loader.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "toolbox/logging.h" + +#include "vm/builtin.h" +#include "vm/exceptions.h" +#include "vm/global.h" +#include "vm/stringlocal.h" +#include "vm/vm.h" + +#include "vm/jit/asmpart.h" +#include "vm/jit/codegen-common.h" + +#if defined(ENABLE_JAVASE) +# include "vmcore/annotation.h" +# include "vmcore/stackmap.h" +#endif + +#include "vmcore/classcache.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/rt-timing.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#include "vmcore/suck.h" + +#if defined(ENABLE_ZLIB) +# include "vmcore/zip.h" +#endif + +#if defined(ENABLE_JVMTI) +# include "native/jvmti/cacaodbg.h" +#endif + + +/* loader_init ***************************************************************** + + Initializes all lists and loads all classes required for the system + or the compiler. + +*******************************************************************************/ + +bool loader_init(void) +{ +#if defined(ENABLE_THREADS) + list_classpath_entry *lce; + + /* Initialize the monitor pointer for zip/jar file locking. */ + + for (lce = list_first(list_classpath_entries); lce != NULL; + lce = list_next(list_classpath_entries, lce)) + if (lce->type == CLASSPATH_ARCHIVE) + lock_init_object_lock((java_objectheader *) lce); +#endif + + /* load some important classes */ + + if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object))) + return false; + + if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String))) + return false; + +#if defined(ENABLE_JAVASE) + if (!(class_java_lang_Cloneable = + load_class_bootstrap(utf_java_lang_Cloneable))) + return false; + + if (!(class_java_io_Serializable = + load_class_bootstrap(utf_java_io_Serializable))) + return false; +#endif + + /* load classes for wrapping primitive types */ + +#if defined(ENABLE_JAVASE) + if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void))) + return false; +#endif + + if (!(class_java_lang_Boolean = + load_class_bootstrap(utf_java_lang_Boolean))) + return false; + + if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte))) + return false; + + if (!(class_java_lang_Character = + load_class_bootstrap(utf_java_lang_Character))) + return false; + + if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short))) + return false; + + if (!(class_java_lang_Integer = + load_class_bootstrap(utf_java_lang_Integer))) + return false; + + if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long))) + return false; + + if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float))) + return false; + + if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double))) + return false; + + + /* load some other important classes */ + + if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class))) + return false; + +#if defined(ENABLE_JAVASE) + if (!(class_java_lang_ClassLoader = + load_class_bootstrap(utf_java_lang_ClassLoader))) + return false; + + if (!(class_java_lang_SecurityManager = + load_class_bootstrap(utf_java_lang_SecurityManager))) + return false; +#endif + + if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System))) + return false; + + if (!(class_java_lang_Thread = + load_class_bootstrap(utf_new_char("java/lang/Thread")))) + return false; + +#if defined(ENABLE_JAVASE) + if (!(class_java_lang_ThreadGroup = + load_class_bootstrap(utf_java_lang_ThreadGroup))) + return false; +#endif + +#if defined(WITH_CLASSPATH_GNU) + if (!(class_java_lang_VMSystem = + load_class_bootstrap(utf_new_char("java/lang/VMSystem")))) + + return false; + + if (!(class_java_lang_VMThread = + load_class_bootstrap(utf_new_char("java/lang/VMThread")))) + return false; +#endif + + + /* some classes which may be used more often */ + +#if defined(ENABLE_JAVASE) + if (!(class_java_lang_StackTraceElement = + load_class_bootstrap(utf_java_lang_StackTraceElement))) + return false; + + if (!(class_java_lang_reflect_Constructor = + load_class_bootstrap(utf_java_lang_reflect_Constructor))) + return false; + + if (!(class_java_lang_reflect_Field = + load_class_bootstrap(utf_java_lang_reflect_Field))) + return false; + + if (!(class_java_lang_reflect_Method = + load_class_bootstrap(utf_java_lang_reflect_Method))) + return false; + + if (!(class_java_security_PrivilegedAction = + load_class_bootstrap(utf_new_char("java/security/PrivilegedAction")))) + return false; + + if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector))) + return false; + + if (!(arrayclass_java_lang_Object = + load_class_bootstrap(utf_new_char("[Ljava/lang/Object;")))) + return false; +#endif + + return true; +} + + +/* loader_load_all_classes ***************************************************** + + Loads all classes specified in the BOOTCLASSPATH. + +*******************************************************************************/ + +void loader_load_all_classes(void) +{ + list_classpath_entry *lce; +#if defined(ENABLE_ZLIB) + hashtable *ht; + s4 slot; + hashtable_zipfile_entry *htzfe; + utf *u; +#endif + + for (lce = list_first(list_classpath_entries); lce != NULL; + lce = list_next(list_classpath_entries, lce)) { +#if defined(ENABLE_ZLIB) + if (lce->type == CLASSPATH_ARCHIVE) { + /* get the classes hashtable */ + + ht = lce->htclasses; + + for (slot = 0; slot < ht->size; slot++) { + htzfe = (hashtable_zipfile_entry *) ht->ptr[slot]; + + for (; htzfe; htzfe = htzfe->hashlink) { + u = htzfe->filename; + + /* skip all entries in META-INF and .properties, + .png files */ + + if (!strncmp(u->text, "META-INF", strlen("META-INF")) || + strstr(u->text, ".properties") || + strstr(u->text, ".png")) + continue; + + /* load class from bootstrap classloader */ + + if (!load_class_bootstrap(u)) { + fprintf(stderr, "Error loading: "); + utf_fprint_printable_ascii_classname(stderr, u); + fprintf(stderr, "\n"); + +#if !defined(NDEBUG) + /* print out exception and cause */ + + exceptions_print_current_exception(); +#endif + } + } + } + + } else { +#endif +#if defined(ENABLE_ZLIB) + } +#endif + } +} + + +/* loader_skip_attribute_body ************************************************** + + Skips an attribute the attribute_name_index has already been read. + + attribute_info { + u2 attribute_name_index; + u4 attribute_length; + u1 info[attribute_length]; + } + +*******************************************************************************/ + +bool loader_skip_attribute_body(classbuffer *cb) +{ + u4 attribute_length; + + if (!suck_check_classbuffer_size(cb, 4)) + return false; + + attribute_length = suck_u4(cb); + + if (!suck_check_classbuffer_size(cb, attribute_length)) + return false; + + suck_skip_nbytes(cb, attribute_length); + + return true; +} + + +/* load_constantpool *********************************************************** + + Loads the constantpool of a class, the entries are transformed into + a simpler format by resolving references (a detailed overview of + the compact structures can be found in global.h). + +*******************************************************************************/ + +static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool) +{ + + /* The following structures are used to save information which cannot be + processed during the first pass. After the complete constantpool has + been traversed the references can be resolved. + (only in specific order) */ + + /* CONSTANT_Class entries */ + typedef struct forward_class { + struct forward_class *next; + u2 thisindex; + u2 name_index; + } forward_class; + + /* CONSTANT_String */ + typedef struct forward_string { + struct forward_string *next; + u2 thisindex; + u2 string_index; + } forward_string; + + /* CONSTANT_NameAndType */ + typedef struct forward_nameandtype { + struct forward_nameandtype *next; + u2 thisindex; + u2 name_index; + u2 sig_index; + } forward_nameandtype; + + /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */ + typedef struct forward_fieldmethint { + struct forward_fieldmethint *next; + u2 thisindex; + u1 tag; + u2 class_index; + u2 nameandtype_index; + } forward_fieldmethint; + + + classinfo *c; + u4 idx; + + forward_class *forward_classes = NULL; + forward_string *forward_strings = NULL; + forward_nameandtype *forward_nameandtypes = NULL; + forward_fieldmethint *forward_fieldmethints = NULL; + + forward_class *nfc; + forward_string *nfs; + forward_nameandtype *nfn; + forward_fieldmethint *nff; + + u4 cpcount; + u1 *cptags; + voidptr *cpinfos; + + c = cb->class; + + /* number of entries in the constant_pool table plus one */ + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + cpcount = c->cpcount = suck_u2(cb); + + /* allocate memory */ + cptags = c->cptags = MNEW(u1, cpcount); + cpinfos = c->cpinfos = MNEW(voidptr, cpcount); + + if (cpcount < 1) { + exceptions_throw_classformaterror(c, "Illegal constant pool size"); + return false; + } + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += (sizeof(u1) + sizeof(voidptr)) * cpcount; +#endif + + /* initialize constantpool */ + for (idx = 0; idx < cpcount; idx++) { + cptags[idx] = CONSTANT_UNUSED; + cpinfos[idx] = NULL; + } + + + /******* first pass *******/ + /* entries which cannot be resolved now are written into + temporary structures and traversed again later */ + + idx = 1; + while (idx < cpcount) { + u4 t; + + /* get constant type */ + if (!suck_check_classbuffer_size(cb, 1)) + return false; + + t = suck_u1(cb); + + switch (t) { + case CONSTANT_Class: + nfc = DNEW(forward_class); + + nfc->next = forward_classes; + forward_classes = nfc; + + nfc->thisindex = idx; + /* reference to CONSTANT_NameAndType */ + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + nfc->name_index = suck_u2(cb); + + idx++; + break; + + case CONSTANT_String: + nfs = DNEW(forward_string); + + nfs->next = forward_strings; + forward_strings = nfs; + + nfs->thisindex = idx; + + /* reference to CONSTANT_Utf8_info with string characters */ + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + nfs->string_index = suck_u2(cb); + + idx++; + break; + + case CONSTANT_NameAndType: + nfn = DNEW(forward_nameandtype); + + nfn->next = forward_nameandtypes; + forward_nameandtypes = nfn; + + nfn->thisindex = idx; + + if (!suck_check_classbuffer_size(cb, 2 + 2)) + return false; + + /* reference to CONSTANT_Utf8_info containing simple name */ + nfn->name_index = suck_u2(cb); + + /* reference to CONSTANT_Utf8_info containing field or method + descriptor */ + nfn->sig_index = suck_u2(cb); + + idx++; + break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + nff = DNEW(forward_fieldmethint); + + nff->next = forward_fieldmethints; + forward_fieldmethints = nff; + + nff->thisindex = idx; + /* constant type */ + nff->tag = t; + + if (!suck_check_classbuffer_size(cb, 2 + 2)) + return false; + + /* class or interface type that contains the declaration of the + field or method */ + nff->class_index = suck_u2(cb); + + /* name and descriptor of the field or method */ + nff->nameandtype_index = suck_u2(cb); + + idx++; + break; + + case CONSTANT_Integer: { + constant_integer *ci = NEW(constant_integer); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_integer); +#endif + + if (!suck_check_classbuffer_size(cb, 4)) + return false; + + ci->value = suck_s4(cb); + cptags[idx] = CONSTANT_Integer; + cpinfos[idx] = ci; + + idx++; + break; + } + + case CONSTANT_Float: { + constant_float *cf = NEW(constant_float); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_float); +#endif + + if (!suck_check_classbuffer_size(cb, 4)) + return false; + + cf->value = suck_float(cb); + cptags[idx] = CONSTANT_Float; + cpinfos[idx] = cf; + + idx++; + break; + } + + case CONSTANT_Long: { + constant_long *cl = NEW(constant_long); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_long); +#endif + + if (!suck_check_classbuffer_size(cb, 8)) + return false; + + cl->value = suck_s8(cb); + cptags[idx] = CONSTANT_Long; + cpinfos[idx] = cl; + idx += 2; + if (idx > cpcount) { + exceptions_throw_classformaterror(c, "Invalid constant pool entry"); + return false; + } + break; + } + + case CONSTANT_Double: { + constant_double *cd = NEW(constant_double); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_double); +#endif + + if (!suck_check_classbuffer_size(cb, 8)) + return false; + + cd->value = suck_double(cb); + cptags[idx] = CONSTANT_Double; + cpinfos[idx] = cd; + idx += 2; + if (idx > cpcount) { + exceptions_throw_classformaterror(c, "Invalid constant pool entry"); + return false; + } + break; + } + + case CONSTANT_Utf8: { + u4 length; + + /* number of bytes in the bytes array (not string-length) */ + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + length = suck_u2(cb); + cptags[idx] = CONSTANT_Utf8; + + /* validate the string */ + if (!suck_check_classbuffer_size(cb, length)) + return false; + +#ifdef ENABLE_VERIFIER + if (opt_verify && + !is_valid_utf((char *) cb->pos, (char *) (cb->pos + length))) + { + exceptions_throw_classformaterror(c, "Invalid UTF-8 string"); + return false; + } +#endif /* ENABLE_VERIFIER */ + /* insert utf-string into the utf-symboltable */ + cpinfos[idx] = utf_new((char *) cb->pos, length); + + /* skip bytes of the string (buffer size check above) */ + suck_skip_nbytes(cb, length); + idx++; + break; + } + + default: + exceptions_throw_classformaterror(c, "Illegal constant pool type"); + return false; + } /* end switch */ + } /* end while */ + + + /* resolve entries in temporary structures */ + + while (forward_classes) { + utf *name = + class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); + if (!name) + return false; + +#ifdef ENABLE_VERIFIER + if (opt_verify && !is_valid_name_utf(name)) { + exceptions_throw_classformaterror(c, "Class reference with invalid name"); + return false; + } +#endif /* ENABLE_VERIFIER */ + + /* add all class references to the descriptor_pool */ + + if (!descriptor_pool_add_class(descpool, name)) + return false; + + cptags[forward_classes->thisindex] = CONSTANT_Class; + + if (opt_eager) { + classinfo *tc; + + if (!(tc = load_class_bootstrap(name))) + return false; + + /* link the class later, because we cannot link the class currently + loading */ + list_add_first(&unlinkedclasses, tc); + } + + /* the classref is created later */ + cpinfos[forward_classes->thisindex] = name; + + nfc = forward_classes; + forward_classes = forward_classes->next; + } + + while (forward_strings) { + utf *text = + class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); + if (!text) + return false; + + /* resolve utf-string */ + cptags[forward_strings->thisindex] = CONSTANT_String; + cpinfos[forward_strings->thisindex] = text; + + nfs = forward_strings; + forward_strings = forward_strings->next; + } + + while (forward_nameandtypes) { + constant_nameandtype *cn = NEW(constant_nameandtype); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_nameandtype); +#endif + + /* resolve simple name and descriptor */ + cn->name = class_getconstant(c, + forward_nameandtypes->name_index, + CONSTANT_Utf8); + if (!cn->name) + return false; + + cn->descriptor = class_getconstant(c, + forward_nameandtypes->sig_index, + CONSTANT_Utf8); + if (!cn->descriptor) + return false; + +#ifdef ENABLE_VERIFIER + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(cn->name)) { + exceptions_throw_classformaterror(c, + "Illegal Field name \"%s\"", + cn->name->text); + + return false; + } + + /* disallow referencing among others */ + if (cn->name->text[0] == '<' && cn->name != utf_init) { + exceptions_throw_classformaterror(c, "Illegal reference to special method"); + return false; + } + } +#endif /* ENABLE_VERIFIER */ + + cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; + cpinfos[forward_nameandtypes->thisindex] = cn; + + nfn = forward_nameandtypes; + forward_nameandtypes = forward_nameandtypes->next; + } + + while (forward_fieldmethints) { + constant_nameandtype *nat; + constant_FMIref *fmi = NEW(constant_FMIref); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_FMIref); +#endif + /* resolve simple name and descriptor */ + + nat = class_getconstant(c, + forward_fieldmethints->nameandtype_index, + CONSTANT_NameAndType); + if (!nat) + return false; + + /* add all descriptors in {Field,Method}ref to the descriptor_pool */ + + if (!descriptor_pool_add(descpool, nat->descriptor, NULL)) + return false; + + /* the classref is created later */ + + fmi->p.index = forward_fieldmethints->class_index; + fmi->name = nat->name; + fmi->descriptor = nat->descriptor; + + cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag; + cpinfos[forward_fieldmethints->thisindex] = fmi; + + nff = forward_fieldmethints; + forward_fieldmethints = forward_fieldmethints->next; + } + + /* everything was ok */ + + return true; +} + + +/* loader_load_attribute_signature ********************************************* + + Signature_attribute { + u2 attribute_name_index; + u4 atrribute_length; + u2 signature_index; + } + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +bool loader_load_attribute_signature(classbuffer *cb, utf **signature) +{ + classinfo *c; + u4 attribute_length; + u2 signature_index; + + /* get classinfo */ + + c = cb->class; + + /* check remaining bytecode */ + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* check attribute length */ + + attribute_length = suck_u4(cb); + + if (attribute_length != 2) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + if (*signature != NULL) { + exceptions_throw_classformaterror(c, "Multiple Signature attributes"); + return false; + } + + /* get signature */ + + signature_index = suck_u2(cb); + + if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8))) + return false; + + return true; +} +#endif /* defined(ENABLE_JAVASE) */ + + +/* load_field ****************************************************************** + + Load everything about a class field from the class file and fill a + 'fieldinfo' structure. For static fields, space in the data segment + is allocated. + +*******************************************************************************/ + +#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ + +static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool) +{ + classinfo *c; + u4 attrnum, i; + u4 jtype; + u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + utf *u; + + c = cb->class; + + if (!suck_check_classbuffer_size(cb, 2 + 2 + 2)) + return false; + + f->flags = suck_u2(cb); + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + + f->name = u; + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + + f->descriptor = u; + f->parseddesc = NULL; + + if (!descriptor_pool_add(descpool, u, NULL)) + return false; + + /* descriptor_pool_add accepts method descriptors, so we have to check */ + /* against them here before the call of descriptor_to_basic_type below. */ + if (u->text[0] == '(') { + exceptions_throw_classformaterror(c, "Method descriptor used for field"); + return false; + } + +#ifdef ENABLE_VERIFIER + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') { + exceptions_throw_classformaterror(c, + "Illegal Field name \"%s\"", + f->name->text); + return false; + } + + /* check flag consistency */ + i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED); + + if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) || + ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) { + exceptions_throw_classformaterror(c, + "Illegal field modifiers: 0x%X", + f->flags); + return false; + } + + if (c->flags & ACC_INTERFACE) { + if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) + != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) || + f->flags & ACC_TRANSIENT) { + exceptions_throw_classformaterror(c, + "Illegal field modifiers: 0x%X", + f->flags); + return false; + } + } + } +#endif /* ENABLE_VERIFIER */ + + f->type = jtype = descriptor_to_basic_type(f->descriptor); /* data type */ + f->offset = 0; /* offset from start of object */ + f->class = c; + + switch (f->type) { + case TYPE_INT: + f->value.i = 0; + break; + + case TYPE_FLT: + f->value.f = 0.0; + break; + + case TYPE_DBL: + f->value.d = 0.0; + break; + + case TYPE_ADR: + f->value.a = NULL; + if (!(f->flags & ACC_STATIC)) + c->flags |= ACC_CLASS_HAS_POINTERS; + break; + + case TYPE_LNG: +#if U8_AVAILABLE + f->value.l = 0; +#else + f->value.l.low = 0; + f->value.l.high = 0; +#endif + break; + } + + /* read attributes */ + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + attrnum = suck_u2(cb); + for (i = 0; i < attrnum; i++) { + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + + if (u == utf_ConstantValue) { + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* check attribute length */ + + if (suck_u4(cb) != 2) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* constant value attribute */ + + if (pindex != field_load_NOVALUE) { + exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes"); + return false; + } + + /* index of value in constantpool */ + + pindex = suck_u2(cb); + + /* initialize field with value from constantpool */ + switch (jtype) { + case TYPE_INT: { + constant_integer *ci; + + if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer))) + return false; + + f->value.i = ci->value; + } + break; + + case TYPE_LNG: { + constant_long *cl; + + if (!(cl = class_getconstant(c, pindex, CONSTANT_Long))) + return false; + + f->value.l = cl->value; + } + break; + + case TYPE_FLT: { + constant_float *cf; + + if (!(cf = class_getconstant(c, pindex, CONSTANT_Float))) + return false; + + f->value.f = cf->value; + } + break; + + case TYPE_DBL: { + constant_double *cd; + + if (!(cd = class_getconstant(c, pindex, CONSTANT_Double))) + return false; + + f->value.d = cd->value; + } + break; + + case TYPE_ADR: + if (!(u = class_getconstant(c, pindex, CONSTANT_String))) + return false; + + /* create javastring from compressed utf8-string */ + f->value.a = literalstring_new(u); + break; + + default: + log_text("Invalid Constant - Type"); + } + } +#if defined(ENABLE_JAVASE) + else if (u == utf_Signature) { + /* Signature */ + + if (!loader_load_attribute_signature(cb, &(f->signature))) + return false; + } +#endif + else { + /* unknown attribute */ + + if (!loader_skip_attribute_body(cb)) + return false; + } + } + + /* everything was ok */ + + return true; +} + + +/* loader_load_method ********************************************************** + + Loads a method from the class file and fills an existing + 'methodinfo' structure. For native methods, the function pointer + field is set to the real function pointer, for JavaVM methods a + pointer to the compiler is used preliminarily. + + 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]; + } + +*******************************************************************************/ + +static bool loader_load_method(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->class; + +#if defined(ENABLE_THREADS) + lock_init_object_lock(&m->header); +#endif + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_all_methods++; +#endif + + /* all fields of m have been zeroed in load_class_from_classbuffer */ + + m->class = 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); + + if (!(attribute_name = class_getconstant(c, attribute_name_index, CONSTANT_Utf8))) + 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); + + if (!(code_attribute_name = class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8))) + 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; + } +#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; + } + + /* everything was ok */ + + return true; +} + + +/* load_class_from_sysloader *************************************************** + + Load the class with the given name using the system class loader + + IN: + name.............the classname + + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown + +*******************************************************************************/ + +classinfo *load_class_from_sysloader(utf *name) +{ + methodinfo *m; + java_objectheader *cl; + classinfo *c; + + assert(class_java_lang_Object); + assert(class_java_lang_ClassLoader); + assert(class_java_lang_ClassLoader->state & CLASS_LINKED); + + m = class_resolveclassmethod(class_java_lang_ClassLoader, + utf_getSystemClassLoader, + utf_void__java_lang_ClassLoader, + class_java_lang_Object, + false); + + if (!m) + return false; + + cl = vm_call_method(m, NULL); + + if (!cl) + return false; + + c = load_class_from_classloader(name, cl); + + return c; +} + + +/* load_class_from_classloader ************************************************* + + Load the class with the given name using the given user-defined class loader. + + IN: + name.............the classname + cl...............user-defined class loader + + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown + +*******************************************************************************/ + +classinfo *load_class_from_classloader(utf *name, java_objectheader *cl) +{ + java_objectheader *o; + classinfo *c; + classinfo *tmpc; + java_objectheader *string; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_lookup, time_prepare, time_java, + time_cache; +#endif + + RT_TIMING_GET_TIME(time_start); + + assert(name); + + /* lookup if this class has already been loaded */ + + c = classcache_lookup(cl, name); + + RT_TIMING_GET_TIME(time_lookup); + RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_CL_LOOKUP); + + if (c != NULL) + return c; + + /* if other class loader than bootstrap, call it */ + + if (cl != NULL) { + methodinfo *lc; + char *text; + s4 namelen; + + text = name->text; + namelen = name->blength; + + /* handle array classes */ + if (text[0] == '[') { + classinfo *comp; + utf *u; + + switch (text[1]) { + case 'L': + /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ + if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') { + exceptions_throw_noclassdeffounderror(name); + return false; + } + + u = utf_new(text + 2, namelen - 3); + + if (!(comp = load_class_from_classloader(u, cl))) + return false; + + /* create the array class */ + + c = class_array_of(comp, false); + + tmpc = classcache_store(cl, c, true); + + if (tmpc == NULL) { + /* exception, free the loaded class */ + c->state &= ~CLASS_LOADING; + class_free(c); + } + + return tmpc; + + case '[': + /* load the component class */ + + u = utf_new(text + 1, namelen - 1); + + if (!(comp = load_class_from_classloader(u, cl))) + return false; + + /* create the array class */ + + c = class_array_of(comp, false); + + tmpc = classcache_store(cl, c, true); + + if (tmpc == NULL) { + /* exception, free the loaded class */ + c->state &= ~CLASS_LOADING; + class_free(c); + } + + return tmpc; + + default: + /* primitive array classes are loaded by the bootstrap loader */ + + c = load_class_bootstrap(name); + + return c; + } + } + + assert(class_java_lang_Object); + + lc = class_resolveclassmethod(cl->vftbl->class, + utf_loadClass, + utf_java_lang_String__java_lang_Class, + class_java_lang_Object, + true); + + if (!lc) + return false; /* exception */ + + /* move return value into `o' and cast it afterwards to a classinfo* */ + + string = javastring_new_slash_to_dot(name); + + RT_TIMING_GET_TIME(time_prepare); + + o = vm_call_method(lc, cl, string); + + RT_TIMING_GET_TIME(time_java); + + c = (classinfo *) o; + + if (c != NULL) { + /* Store this class in the loaded class cache. If another + class with the same (initloader,name) pair has been + stored earlier it will be returned by classcache_store + In this case classcache_store may not free the class + because it has already been exposed to Java code which + may have kept references to that class. */ + + tmpc = classcache_store(cl, c, false); + + if (tmpc == NULL) { + /* exception, free the loaded class */ + c->state &= ~CLASS_LOADING; + class_free(c); + } + + c = tmpc; + + } else { + /* loadClass has thrown an exception. We must convert + ClassNotFoundException into + NoClassDefFoundException. */ + + /* XXX Maybe we should have a flag that avoids this + conversion for calling load_class_from_classloader from + Class.forName. Currently we do a double conversion in + these cases. */ + + classnotfoundexception_to_noclassdeffounderror(); + } + + RT_TIMING_GET_TIME(time_cache); + + RT_TIMING_TIME_DIFF(time_lookup , time_prepare, RT_TIMING_LOAD_CL_PREPARE); + RT_TIMING_TIME_DIFF(time_prepare, time_java , RT_TIMING_LOAD_CL_JAVA); + RT_TIMING_TIME_DIFF(time_java , time_cache , RT_TIMING_LOAD_CL_CACHE); + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass && (c != NULL) && (c->classloader == cl)) { + printf("[Loaded "); + utf_display_printable_ascii_classname(name); + printf("]\n"); + } + +#if defined(ENABLE_JVMTI) + /* fire Class Load JVMTI event */ + if (jvmti) jvmti_ClassLoadPrepare(false, c); +#endif + + + return c; + } + + c = load_class_bootstrap(name); + + return c; +} + + +/* load_class_bootstrap ******************************************************** + + Load the class with the given name using the bootstrap class loader. + + IN: + name.............the classname + + RETURN VALUE: + loaded classinfo, or + NULL if an exception has been thrown + + SYNCHRONIZATION: + load_class_bootstrap is synchronized. It can be treated as an + atomic operation. + +*******************************************************************************/ + +classinfo *load_class_bootstrap(utf *name) +{ + classbuffer *cb; + classinfo *c; + classinfo *r; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_lookup, time_array, time_suck, + time_load, time_cache; +#endif + + RT_TIMING_GET_TIME(time_start); + + /* for debugging */ + + assert(name); + + /* lookup if this class has already been loaded */ + + if ((r = classcache_lookup(NULL, name))) { + + RT_TIMING_GET_TIME(time_lookup); + RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP); + + return r; + } + + RT_TIMING_GET_TIME(time_lookup); + RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP); + + /* create the classinfo */ + + c = class_create_classinfo(name); + + /* handle array classes */ + + if (name->text[0] == '[') { + c = load_newly_created_array(c, NULL); + if (c == NULL) + return NULL; + assert(c->state & CLASS_LOADED); + + RT_TIMING_GET_TIME(time_array); + RT_TIMING_TIME_DIFF(time_start,time_array,RT_TIMING_LOAD_BOOT_ARRAY); + + return c; + } + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_stop(); + + if (opt_getloadingtime) + loadingtime_start(); +#endif + + /* load classdata, throw exception on error */ + + cb = suck_start(c); + + if (cb == NULL) { + /* this normally means, the classpath was not set properly */ + + if (name == utf_java_lang_Object) + vm_abort("java/lang/NoClassDefFoundError: java/lang/Object"); + + exceptions_throw_noclassdeffounderror(name); + + return NULL; + } + + RT_TIMING_GET_TIME(time_suck); + + /* load the class from the buffer */ + + r = load_class_from_classbuffer(cb); + + RT_TIMING_GET_TIME(time_load); + + if (!r) { + /* the class could not be loaded, free the classinfo struct */ + + class_free(c); + + } else { + /* Store this class in the loaded class cache this step also + checks the loading constraints. If the class has been loaded + before, the earlier loaded class is returned. */ + + classinfo *res = classcache_store(NULL, c, true); + + if (!res) { + /* exception */ + class_free(c); + } + + r = res; + } + + RT_TIMING_GET_TIME(time_cache); + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass && r) { + printf("[Loaded "); + utf_display_printable_ascii_classname(name); + printf(" from %s]\n", cb->path); + } + + /* free memory */ + + suck_stop(cb); + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getloadingtime) + loadingtime_stop(); + + if (opt_getcompilingtime) + compilingtime_start(); +#endif + + RT_TIMING_TIME_DIFF(time_lookup, time_suck , RT_TIMING_LOAD_BOOT_SUCK); + RT_TIMING_TIME_DIFF(time_suck , time_load , RT_TIMING_LOAD_BOOT_LOAD); + RT_TIMING_TIME_DIFF(time_load , time_cache, RT_TIMING_LOAD_BOOT_CACHE); + RT_TIMING_TIME_DIFF(time_lookup, time_cache, RT_TIMING_LOAD_BOOT_TOTAL); + + return r; +} + + +/* load_class_from_classbuffer ************************************************* + + Loads everything interesting about a class from the class file. The + 'classinfo' structure must have been allocated previously. + + The super class and the interfaces implemented by this class need + not be loaded. The link is set later by the function 'class_link'. + + The loaded class is removed from the list 'unloadedclasses' and + added to the list 'unlinkedclasses'. + + SYNCHRONIZATION: + This function is NOT synchronized! + +*******************************************************************************/ + +classinfo *load_class_from_classbuffer(classbuffer *cb) +{ + classinfo *c; + utf *name; + utf *supername; + u4 i,j; + u4 ma, mi; + s4 dumpsize; + descriptor_pool *descpool; +#if defined(ENABLE_STATISTICS) + u4 classrefsize; + u4 descsize; +#endif +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_checks, time_ndpool, time_cpool, + time_setup, time_fields, time_methods, time_classrefs, + time_descs, time_setrefs, time_parsefds, time_parsemds, + time_parsecpool, time_verify, time_attrs; +#endif + + RT_TIMING_GET_TIME(time_start); + + /* get the classbuffer's class */ + + c = cb->class; + + /* the class is already loaded */ + + if (c->state & CLASS_LOADED) + return c; + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_class_loads++; +#endif + +#if !defined(NDEBUG) + /* output for debugging purposes */ + + if (loadverbose) + log_message_class("Loading class: ", c); +#endif + + /* mark start of dump memory area */ + + dumpsize = dump_size(); + + /* class is currently loading */ + + c->state |= CLASS_LOADING; + + if (!suck_check_classbuffer_size(cb, 4 + 2 + 2)) + goto return_exception; + + /* check signature */ + + if (suck_u4(cb) != MAGIC) { + exceptions_throw_classformaterror(c, "Bad magic number"); + + goto return_exception; + } + + /* check version */ + + mi = suck_u2(cb); + ma = suck_u2(cb); + + if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { + exceptions_throw_unsupportedclassversionerror(c, ma, mi); + goto return_exception; + } + + RT_TIMING_GET_TIME(time_checks); + + /* create a new descriptor pool */ + + descpool = descriptor_pool_new(c); + + RT_TIMING_GET_TIME(time_ndpool); + + /* load the constant pool */ + + if (!load_constantpool(cb, descpool)) + goto return_exception; + + RT_TIMING_GET_TIME(time_cpool); + + /* ACC flags */ + + if (!suck_check_classbuffer_size(cb, 2)) + goto return_exception; + + c->flags = suck_u2(cb); + + /* check ACC flags consistency */ + + if (c->flags & ACC_INTERFACE) { + if (!(c->flags & ACC_ABSTRACT)) { + /* We work around this because interfaces in JDK 1.1 are + * not declared abstract. */ + + c->flags |= ACC_ABSTRACT; + } + + if (c->flags & ACC_FINAL) { + exceptions_throw_classformaterror(c, + "Illegal class modifiers: 0x%X", + c->flags); + goto return_exception; + } + + if (c->flags & ACC_SUPER) { + c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */ + } + } + + if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { + exceptions_throw_classformaterror(c, + "Illegal class modifiers: 0x%X", + c->flags); + goto return_exception; + } + + if (!suck_check_classbuffer_size(cb, 2 + 2)) + goto return_exception; + + /* this class */ + + i = suck_u2(cb); + if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class))) + goto return_exception; + + if (c->name == utf_not_named_yet) { + /* we finally have a name for this class */ + c->name = name; + class_set_packagename(c); + + } else if (name != c->name) { + /* TODO: i want to be an exceptions-function! */ + char *msg; + s4 msglen; + + msglen = utf_bytes(c->name) + strlen(" (wrong name: ") + + utf_bytes(name) + strlen(")") + strlen("0"); + + msg = MNEW(char, msglen); + + utf_copy_classname(msg, c->name); + strcat(msg, " (wrong name: "); + utf_cat_classname(msg, name); + strcat(msg, ")"); + +#warning FIX ME! +/* *exceptionptr = */ +/* new_exception_message("java/lang/NoClassDefFoundError", msg); */ + exceptions_throw_noclassdeffounderror(c->name); + + MFREE(msg, char, msglen); + + goto return_exception; + } + + /* retrieve superclass */ + + c->super.any = NULL; + if ((i = suck_u2(cb))) { + if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class))) + goto return_exception; + + /* java.lang.Object may not have a super class. */ + + if (c->name == utf_java_lang_Object) { + exceptions_throw_classformaterror(NULL, "java.lang.Object with superclass"); + goto return_exception; + } + + /* Interfaces must have java.lang.Object as super class. */ + + if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) { + exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass"); + goto return_exception; + } + + } else { + supername = NULL; + + /* This is only allowed for java.lang.Object. */ + + if (c->name != utf_java_lang_Object) { + exceptions_throw_classformaterror(c, "Bad superclass index"); + goto return_exception; + } + } + + /* retrieve interfaces */ + + if (!suck_check_classbuffer_size(cb, 2)) + goto return_exception; + + c->interfacescount = suck_u2(cb); + + if (!suck_check_classbuffer_size(cb, 2 * c->interfacescount)) + goto return_exception; + + c->interfaces = MNEW(classref_or_classinfo, c->interfacescount); + for (i = 0; i < c->interfacescount; i++) { + /* the classrefs are created later */ + if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + goto return_exception; + } + + RT_TIMING_GET_TIME(time_setup); + + /* load fields */ + if (!suck_check_classbuffer_size(cb, 2)) + goto return_exception; + + c->fieldscount = suck_u2(cb); +#if defined(ENABLE_GC_CACAO) + c->fields = MNEW(fieldinfo, c->fieldscount); + MZERO(c->fields, fieldinfo, c->fieldscount); +#else + c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount); +#endif + + for (i = 0; i < c->fieldscount; i++) { + if (!load_field(cb, &(c->fields[i]),descpool)) + goto return_exception; + } + + RT_TIMING_GET_TIME(time_fields); + + /* load methods */ + if (!suck_check_classbuffer_size(cb, 2)) + goto return_exception; + + c->methodscount = suck_u2(cb); + c->methods = MNEW(methodinfo, c->methodscount); + + MZERO(c->methods, methodinfo, c->methodscount); + + for (i = 0; i < c->methodscount; i++) { + if (!loader_load_method(cb, &(c->methods[i]), descpool)) + goto return_exception; + } + + RT_TIMING_GET_TIME(time_methods); + + /* create the class reference table */ + + c->classrefs = + descriptor_pool_create_classrefs(descpool, &(c->classrefcount)); + + RT_TIMING_GET_TIME(time_classrefs); + + /* allocate space for the parsed descriptors */ + + descriptor_pool_alloc_parsed_descriptors(descpool); + c->parseddescs = + descriptor_pool_get_parsed_descriptors(descpool, &(c->parseddescsize)); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) { + descriptor_pool_get_sizes(descpool, &classrefsize, &descsize); + count_classref_len += classrefsize; + count_parsed_desc_len += descsize; + } +#endif + + RT_TIMING_GET_TIME(time_descs); + + /* put the classrefs in the constant pool */ + for (i = 0; i < c->cpcount; i++) { + if (c->cptags[i] == CONSTANT_Class) { + utf *name = (utf *) c->cpinfos[i]; + c->cpinfos[i] = descriptor_pool_lookup_classref(descpool, name); + } + } + + /* set the super class reference */ + + if (supername) { + c->super.ref = descriptor_pool_lookup_classref(descpool, supername); + if (!c->super.ref) + goto return_exception; + } + + /* set the super interfaces references */ + + for (i = 0; i < c->interfacescount; i++) { + c->interfaces[i].ref = + descriptor_pool_lookup_classref(descpool, + (utf *) c->interfaces[i].any); + if (!c->interfaces[i].ref) + goto return_exception; + } + + RT_TIMING_GET_TIME(time_setrefs); + + /* parse field descriptors */ + + for (i = 0; i < c->fieldscount; i++) { + c->fields[i].parseddesc = + descriptor_pool_parse_field_descriptor(descpool, + c->fields[i].descriptor); + if (!c->fields[i].parseddesc) + goto return_exception; + } + + RT_TIMING_GET_TIME(time_parsefds); + + /* parse method descriptors */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &c->methods[i]; + m->parseddesc = + descriptor_pool_parse_method_descriptor(descpool, m->descriptor, + m->flags, class_get_self_classref(m->class)); + if (!m->parseddesc) + goto return_exception; + + for (j = 0; j < m->rawexceptiontablelength; j++) { + if (!m->rawexceptiontable[j].catchtype.any) + continue; + if ((m->rawexceptiontable[j].catchtype.ref = + descriptor_pool_lookup_classref(descpool, + (utf *) m->rawexceptiontable[j].catchtype.any)) == NULL) + goto return_exception; + } + + for (j = 0; j < m->thrownexceptionscount; j++) { + if (!m->thrownexceptions[j].any) + continue; + if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool, + (utf *) m->thrownexceptions[j].any)) == NULL) + goto return_exception; + } + } + + RT_TIMING_GET_TIME(time_parsemds); + + /* parse the loaded descriptors */ + + for (i = 0; i < c->cpcount; i++) { + constant_FMIref *fmi; + s4 index; + + switch (c->cptags[i]) { + case CONSTANT_Fieldref: + fmi = (constant_FMIref *) c->cpinfos[i]; + fmi->parseddesc.fd = + descriptor_pool_parse_field_descriptor(descpool, + fmi->descriptor); + if (!fmi->parseddesc.fd) + goto return_exception; + index = fmi->p.index; + fmi->p.classref = + (constant_classref *) class_getconstant(c, index, + CONSTANT_Class); + if (!fmi->p.classref) + goto return_exception; + break; + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + fmi = (constant_FMIref *) c->cpinfos[i]; + index = fmi->p.index; + fmi->p.classref = + (constant_classref *) class_getconstant(c, index, + CONSTANT_Class); + if (!fmi->p.classref) + goto return_exception; + fmi->parseddesc.md = + descriptor_pool_parse_method_descriptor(descpool, + fmi->descriptor, + ACC_UNDEF, + fmi->p.classref); + if (!fmi->parseddesc.md) + goto return_exception; + break; + } + } + + RT_TIMING_GET_TIME(time_parsecpool); + +#ifdef ENABLE_VERIFIER + /* Check if all fields and methods can be uniquely + * identified by (name,descriptor). */ + + if (opt_verify) { + /* We use a hash table here to avoid making the + * average case quadratic in # of methods, fields. + */ + static int shift = 0; + u2 *hashtab; + u2 *next; /* for chaining colliding hash entries */ + size_t len; + size_t hashlen; + u2 index; + u2 old; + + /* Allocate hashtable */ + len = c->methodscount; + if (len < c->fieldscount) len = c->fieldscount; + hashlen = 5 * len; + hashtab = MNEW(u2,(hashlen + len)); + next = hashtab + hashlen; + + /* Determine bitshift (to get good hash values) */ + if (!shift) { + len = sizeof(utf); + while (len) { + len >>= 1; + shift++; + } + } + + /* Check fields */ + memset(hashtab, 0, sizeof(u2) * (hashlen + len)); + + for (i = 0; i < c->fieldscount; ++i) { + fieldinfo *fi = c->fields + i; + + /* It's ok if we lose bits here */ + index = ((((size_t) fi->name) + + ((size_t) fi->descriptor)) >> shift) % hashlen; + + if ((old = hashtab[index])) { + old--; + next[i] = old; + do { + if (c->fields[old].name == fi->name && + c->fields[old].descriptor == fi->descriptor) { + exceptions_throw_classformaterror(c, "Repetitive field name/signature"); + goto return_exception; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + /* Check methods */ + memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5)); + + for (i = 0; i < c->methodscount; ++i) { + methodinfo *mi = c->methods + i; + + /* It's ok if we lose bits here */ + index = ((((size_t) mi->name) + + ((size_t) mi->descriptor)) >> shift) % hashlen; + + /*{ JOWENN + int dbg; + for (dbg=0;dbgmethods[old].name == mi->name && + c->methods[old].descriptor == mi->descriptor) { + exceptions_throw_classformaterror(c, "Repetitive method name/signature"); + goto return_exception; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + MFREE(hashtab, u2, (hashlen + len)); + } +#endif /* ENABLE_VERIFIER */ + + RT_TIMING_GET_TIME(time_verify); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) { + size_classinfo += sizeof(classinfo*) * c->interfacescount; + size_fieldinfo += sizeof(fieldinfo) * c->fieldscount; + size_methodinfo += sizeof(methodinfo) * c->methodscount; + } +#endif + + /* load attribute structures */ + + if (!class_load_attributes(cb)) + goto return_exception; + + /* Pre Java 1.5 version don't check this. This implementation is like + Java 1.5 do it: for class file version 45.3 we don't check it, older + versions are checked. + */ + + if (((ma == 45) && (mi > 3)) || (ma > 45)) { + /* check if all data has been read */ + s4 classdata_left = ((cb->data + cb->size) - cb->pos); + + if (classdata_left > 0) { + exceptions_throw_classformaterror(c, "Extra bytes at the end of class file"); + goto return_exception; + } + } + + RT_TIMING_GET_TIME(time_attrs); + + /* release dump area */ + + dump_release(dumpsize); + + /* revert loading state and class is loaded */ + + c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED; + +#if defined(ENABLE_JVMTI) + /* fire Class Prepare JVMTI event */ + + if (jvmti) + jvmti_ClassLoadPrepare(true, c); +#endif + +#if !defined(NDEBUG) + if (loadverbose) + log_message_class("Loading done class: ", c); +#endif + + RT_TIMING_TIME_DIFF(time_start , time_checks , RT_TIMING_LOAD_CHECKS); + RT_TIMING_TIME_DIFF(time_checks , time_ndpool , RT_TIMING_LOAD_NDPOOL); + RT_TIMING_TIME_DIFF(time_ndpool , time_cpool , RT_TIMING_LOAD_CPOOL); + RT_TIMING_TIME_DIFF(time_cpool , time_setup , RT_TIMING_LOAD_SETUP); + RT_TIMING_TIME_DIFF(time_setup , time_fields , RT_TIMING_LOAD_FIELDS); + RT_TIMING_TIME_DIFF(time_fields , time_methods , RT_TIMING_LOAD_METHODS); + RT_TIMING_TIME_DIFF(time_methods , time_classrefs , RT_TIMING_LOAD_CLASSREFS); + RT_TIMING_TIME_DIFF(time_classrefs , time_descs , RT_TIMING_LOAD_DESCS); + RT_TIMING_TIME_DIFF(time_descs , time_setrefs , RT_TIMING_LOAD_SETREFS); + RT_TIMING_TIME_DIFF(time_setrefs , time_parsefds , RT_TIMING_LOAD_PARSEFDS); + RT_TIMING_TIME_DIFF(time_parsefds , time_parsemds , RT_TIMING_LOAD_PARSEMDS); + RT_TIMING_TIME_DIFF(time_parsemds , time_parsecpool, RT_TIMING_LOAD_PARSECP); + RT_TIMING_TIME_DIFF(time_parsecpool, time_verify , RT_TIMING_LOAD_VERIFY); + RT_TIMING_TIME_DIFF(time_verify , time_attrs , RT_TIMING_LOAD_ATTRS); + RT_TIMING_TIME_DIFF(time_start , time_attrs , RT_TIMING_LOAD_TOTAL); + + return c; + +return_exception: + /* release dump area */ + + dump_release(dumpsize); + + /* an exception has been thrown */ + + return NULL; +} + + +/* load_newly_created_array **************************************************** + + Load a newly created array class. + + RETURN VALUE: + c....................the array class C has been loaded + other classinfo......the array class was found in the class cache, + C has been freed + NULL.................an exception has been thrown + + Note: + This is an internal function. Do not use it unless you know exactly + what you are doing! + + Use one of the load_class_... functions for general array class loading. + +*******************************************************************************/ + +classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader) +{ + classinfo *comp = NULL; + methodinfo *clone; + methoddesc *clonedesc; + constant_classref *classrefs; + char *text; + s4 namelen; + utf *u; + + text = c->name->text; + namelen = c->name->blength; + + /* Check array class name */ + + if ((namelen < 2) || (text[0] != '[')) { + exceptions_throw_noclassdeffounderror(c->name); + return NULL; + } + + /* Check the element type */ + + switch (text[1]) { + case '[': + /* c is an array of arrays. We have to create the component class. */ + + u = utf_new(text + 1, namelen - 1); + if (!(comp = load_class_from_classloader(u, loader))) + return NULL; + + assert(comp->state & CLASS_LOADED); + + if (opt_eager) + if (!link_class(c)) + return NULL; + + /* the array's flags are that of the component class */ + c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; + c->classloader = comp->classloader; + break; + + case 'L': + /* c is an array of objects. */ + + /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ + if ((namelen < 4) || (text[2] == '[') || (text[namelen - 1] != ';')) { + exceptions_throw_noclassdeffounderror(c->name); + return NULL; + } + + u = utf_new(text + 2, namelen - 3); + + if (!(comp = load_class_from_classloader(u, loader))) + return NULL; + + assert(comp->state & CLASS_LOADED); + + if (opt_eager) + if (!link_class(c)) + return NULL; + + /* the array's flags are that of the component class */ + c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; + c->classloader = comp->classloader; + break; + + default: + /* c is an array of a primitive type */ + + /* check for cases like `[II' */ + if (namelen > 2) { + exceptions_throw_noclassdeffounderror(c->name); + return NULL; + } + + /* the accessibility of the array class is public (VM Spec 5.3.3) */ + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + c->classloader = NULL; + } + + assert(class_java_lang_Object); +#if defined(ENABLE_JAVASE) + assert(class_java_lang_Cloneable); + assert(class_java_io_Serializable); +#endif + + /* setup the array class */ + + c->super.cls = class_java_lang_Object; + + c->interfacescount = 0; + c->interfaces = NULL; + +#if defined(ENABLE_JAVASE) + c->interfaces = MNEW(classref_or_classinfo, 2); + + if (opt_eager) { + classinfo *tc; + + tc = class_java_lang_Cloneable; + assert(tc->state & CLASS_LOADED); + list_add_first(&unlinkedclasses, tc); + c->interfaces[0].cls = tc; + + tc = class_java_io_Serializable; + assert(tc->state & CLASS_LOADED); + list_add_first(&unlinkedclasses, tc); + c->interfaces[1].cls = tc; + } + else { + c->interfaces[0].cls = class_java_lang_Cloneable; + c->interfaces[1].cls = class_java_io_Serializable; + } +#endif + + c->methodscount = 1; + c->methods = MNEW(methodinfo, c->methodscount); + MZERO(c->methods, methodinfo, c->methodscount); + + classrefs = MNEW(constant_classref, 2); + CLASSREF_INIT(classrefs[0], c, c->name); + CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object); + + /* create descriptor for clone method */ + /* we need one paramslot which is reserved for the 'this' parameter */ + clonedesc = NEW(methoddesc); + clonedesc->returntype.type = TYPE_ADR; + clonedesc->returntype.classref = classrefs + 1; + clonedesc->returntype.arraydim = 0; + /* initialize params to "empty", add real params below in + descriptor_params_from_paramtypes */ + clonedesc->paramcount = 0; + clonedesc->paramslots = 0; + clonedesc->paramtypes[0].classref = classrefs + 0; + clonedesc->params = NULL; + + /* create methodinfo */ + + clone = c->methods; + MSET(clone, 0, methodinfo, 1); + +#if defined(ENABLE_THREADS) + lock_init_object_lock(&clone->header); +#endif + + /* ATTENTION: if you delete the ACC_NATIVE below, set + clone->maxlocals=1 (interpreter related) */ + + clone->flags = ACC_PUBLIC | ACC_NATIVE; + clone->name = utf_clone; + clone->descriptor = utf_void__java_lang_Object; + clone->parseddesc = clonedesc; + clone->class = c; + + /* parse the descriptor to get the register allocation */ + + if (!descriptor_params_from_paramtypes(clonedesc, clone->flags)) + return false; + + clone->code = codegen_createnativestub(BUILTIN_clone, clone); + + /* XXX: field: length? */ + + /* array classes are not loaded from class files */ + + c->state |= CLASS_LOADED; + c->parseddescs = (u1 *) clonedesc; + c->parseddescsize = sizeof(methodinfo); + c->classrefs = classrefs; + c->classrefcount = 1; + + /* insert class into the loaded class cache */ + /* XXX free classinfo if NULL returned? */ + + return classcache_store(loader, c, true); +} + + +/* loader_close **************************************************************** + + Frees all resources. + +*******************************************************************************/ + +void loader_close(void) +{ + /* empty */ +} + + +/* + * 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: + */ diff --git a/src/vmcore/loader.h b/src/vmcore/loader.h new file mode 100644 index 000000000..779018bd7 --- /dev/null +++ b/src/vmcore/loader.h @@ -0,0 +1,151 @@ +/* src/vmcore/loader.h - class loader header + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: loader.h 7246 2007-01-29 18:49:05Z twisti $ +*/ + + +#ifndef _LOADER_H +#define _LOADER_H + +/* forward typedefs ***********************************************************/ + +typedef struct classbuffer classbuffer; + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "vm/global.h" + +#include "vmcore/descriptor.h" +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/references.h" +#include "vmcore/utf8.h" + + +/* constant pool entries ******************************************************* + + All constant pool entries need a data structure which contain the entrys + value. In some cases this structure exist already, in the remaining cases + this structure must be generated: + + kind structure generated? + ---------------------------------------------------------------------- + CONSTANT_Class constant_classref yes + CONSTANT_Fieldref constant_FMIref yes + CONSTANT_Methodref constant_FMIref yes + CONSTANT_InterfaceMethodref constant_FMIref yes + CONSTANT_String unicode no + CONSTANT_Integer constant_integer yes + CONSTANT_Float constant_float yes + CONSTANT_Long constant_long yes + CONSTANT_Double constant_double yes + CONSTANT_NameAndType constant_nameandtype yes + CONSTANT_Utf8 unicode no + CONSTANT_UNUSED - + +*******************************************************************************/ + +typedef struct { /* Integer */ + s4 value; +} constant_integer; + + +typedef struct { /* Float */ + float value; +} constant_float; + + +typedef struct { /* Long */ + s8 value; +} constant_long; + + +typedef struct { /* Double */ + double value; +} constant_double; + + +typedef struct { /* NameAndType (Field or Method) */ + utf *name; /* field/method name */ + utf *descriptor; /* field/method type descriptor string */ +} constant_nameandtype; + + +/* classbuffer ****************************************************************/ + +struct classbuffer { + classinfo *class; /* pointer to classinfo structure */ + u1 *data; /* pointer to byte code */ + s4 size; /* size of the byte code */ + u1 *pos; /* current read position */ + char *path; /* path to file (for debugging) */ +}; + + +/* function prototypes ********************************************************/ + +/* initialize loader, load important systemclasses */ +bool loader_init(void); + +void loader_load_all_classes(void); + +bool loader_skip_attribute_body(classbuffer *cb); + +#if defined(ENABLE_JAVASE) +bool loader_load_attribute_signature(classbuffer *cb, utf **signature); +#endif + +/* free resources */ +void loader_close(void); + +/* class loading functions */ +classinfo *load_class_from_sysloader(utf *name); +classinfo *load_class_from_classloader(utf *name, java_objectheader *cl); +classinfo *load_class_bootstrap(utf *name); + +/* (don't use the following directly) */ +classinfo *load_class_from_classbuffer(classbuffer *cb); +classinfo *load_newly_created_array(classinfo *c,java_objectheader *loader); + +#endif /* _LOADER_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: + */ diff --git a/src/vmcore/method.c b/src/vmcore/method.c new file mode 100644 index 000000000..662ae1b89 --- /dev/null +++ b/src/vmcore/method.c @@ -0,0 +1,418 @@ +/* src/vmcore/method.c - method functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: method.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vm/global.h" + +#include "vm/jit/methodheader.h" + +#include "vmcore/class.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/method.h" +#include "vmcore/options.h" + + +#if !defined(NDEBUG) && defined(ENABLE_INLINING) +extern bool inline_debug_log; +#define INLINELOG(code) do { if (inline_debug_log) { code } } while (0) +#else +#define INLINELOG(code) +#endif + + +/* method_free ***************************************************************** + + Frees all memory that was allocated for this method. + +*******************************************************************************/ + +void method_free(methodinfo *m) +{ + 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) { + removenativestub(m->stubroutine); + + } else { + removecompilerstub(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_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 */ + codeinfo *code; + + /* 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->class->flags & ACC_INTERFACE) { + pmptr = vftbl->interfacetable[-(m->class->index)]; + mptr = pmptr[(m - m->class->methods)]; + } + else { + mptr = vftbl->table[m->vftblindex]; + } + + /* and now get the codeinfo pointer from the first data segment slot */ + + code = *((codeinfo **) (mptr + CodeinfoPointer)); + + resm = code->m; + + return resm; +} + + +/* 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_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); + } +} + + +/* 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_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.()V + +*******************************************************************************/ + +#if !defined(NDEBUG) +void method_print(methodinfo *m) +{ + if (m == NULL) { + printf("NULL"); + return; + } + + utf_display_printable_ascii_classname(m->class->name); + 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.()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_print(mr->p.method); + } + else { + printf(" "); + 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: + */ diff --git a/src/vmcore/method.h b/src/vmcore/method.h new file mode 100644 index 000000000..b90a3465a --- /dev/null +++ b/src/vmcore/method.h @@ -0,0 +1,181 @@ +/* src/vmcore/method.h - method functions header + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: method.h 7246 2007-01-29 18:49:05Z twisti $ +*/ + + +#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; + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vm/jit/code.h" +#include "vm/jit/codegen-common.h" + +#include "vmcore/descriptor.h" +#include "vmcore/references.h" +#include "vmcore/linker.h" + +#if defined(ENABLE_JAVASE) +# include "vmcore/stackmap.h" +#endif + +#include "vmcore/utf8.h" + + +/* methodinfo *****************************************************************/ + +struct methodinfo { /* method structure */ + java_objectheader header; /* we need this in jit's monitorenter */ + 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 *class; /* 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 */ +}; + + +/* 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; +}; + + +/* function prototypes ********************************************************/ + +void method_free(methodinfo *m); +bool method_canoverwrite(methodinfo *m, methodinfo *old); + +methodinfo *method_vftbl_lookup(vftbl_t *vftbl, 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); + +#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 + +#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: + */ diff --git a/src/vmcore/options.c b/src/vmcore/options.c new file mode 100644 index 000000000..3429c8298 --- /dev/null +++ b/src/vmcore/options.c @@ -0,0 +1,236 @@ +/* src/vmcore/options.c - contains global options + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + $Id: options.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "mm/memory.h" +#include "native/jni.h" +#include "vmcore/options.h" + + +/* command line option ********************************************************/ + +s4 opt_index = 0; /* index of processed arguments */ +char *opt_arg; /* this one exports the option argument */ + +bool opt_foo = false; /* option for development */ + +bool opt_jar = false; + +#if defined(ENABLE_JIT) +bool opt_jit = true; /* JIT mode execution (default) */ +bool opt_intrp = false; /* interpreter mode execution */ +#else +bool opt_jit = false; /* JIT mode execution */ +bool opt_intrp = true; /* interpreter mode execution (default) */ +#endif + +bool opt_run = true; + +s4 opt_heapmaxsize = 0; /* maximum heap size */ +s4 opt_heapstartsize = 0; /* initial heap size */ +s4 opt_stacksize = 0; /* thread stack size */ + +bool opt_verbose = false; +bool opt_debugcolor = false; /* use ANSI terminal sequences */ +bool compileall = false; + +bool loadverbose = false; +bool linkverbose = false; +bool initverbose = false; + +bool opt_verboseclass = false; +bool opt_verbosegc = false; +bool opt_verbosejni = false; +bool opt_verbosecall = false; /* trace all method invocation */ +bool opt_verboseexception = false; + +bool showmethods = false; +bool showconstantpool = false; +bool showutf = false; + +char *opt_method = NULL; +char *opt_signature = NULL; + +bool compileverbose = false; /* trace compiler actions */ +bool showstack = false; + +bool opt_showdisassemble = false; /* generate disassembler listing */ +bool opt_shownops = false; +bool opt_showddatasegment = false; /* generate data segment listing */ +bool opt_showintermediate = false; /* generate intermediate code listing */ +bool opt_showexceptionstubs = false; +bool opt_shownativestub = false; + +bool useinlining = false; /* use method inlining */ +bool inlinevirtuals = false; /* inline unique virtual methods */ +bool inlineexceptions = false; /* inline methods, that contain excptions */ +bool inlineparamopt = false; /* optimize parameter passing to inlined methods */ +bool inlineoutsiders = false; /* inline methods, that are not member of the invoker's class */ + +bool checkbounds = true; /* check array bounds */ +bool checknull = true; /* check null pointers */ +bool opt_noieee = false; /* don't implement ieee compliant floats */ +bool checksync = true; /* do synchronization */ +#if defined(ENABLE_LOOP) +bool opt_loops = false; /* optimize array accesses in loops */ +#endif + +bool makeinitializations = true; + +#if defined(ENABLE_STATISTICS) +bool opt_stat = false; +bool opt_getloadingtime = false; /* to measure the runtime */ +bool opt_getcompilingtime = false; /* compute compile time */ +#endif +#if defined(ENABLE_VERIFIER) +bool opt_verify = true; /* true if classfiles should be verified */ +#endif +bool opt_eager = false; + +#if defined(ENABLE_PROFILING) +bool opt_prof = false; +bool opt_prof_bb = false; +#endif + + +/* optimization options *******************************************************/ + +#if defined(ENABLE_IFCONV) +bool opt_ifconv = false; +#endif + +#if defined(ENABLE_LSRA) || defined(ENABLE_SSA) +bool opt_lsra = false; +#endif + + +/* interpreter options ********************************************************/ + +#if defined(ENABLE_INTRP) +bool opt_no_dynamic = false; /* suppress dynamic superinstructions */ +bool opt_no_replication = false; /* don't use replication in intrp */ +bool opt_no_quicksuper = false; /* instructions for quickening cannot be + part of dynamic superinstructions */ + +s4 opt_static_supers = 0x7fffffff; +bool vm_debug = false; /* XXX this should be called `opt_trace' */ +#endif + + +/* options_get ***************************************************************** + + DOCUMENT ME!!! + +*******************************************************************************/ + +s4 options_get(opt_struct *opts, JavaVMInitArgs *vm_args) +{ + char *option; + s4 i; + + if (opt_index >= vm_args->nOptions) + return OPT_DONE; + + /* get the current option */ + + option = vm_args->options[opt_index].optionString; + + if ((option == NULL) || (option[0] != '-')) + return OPT_DONE; + + for (i = 0; opts[i].name; i++) { + if (!opts[i].arg) { + /* boolean option found */ + + if (strcmp(option + 1, opts[i].name) == 0) { + opt_index++; + return opts[i].value; + } + + } else { + /* parameter option found */ + + /* with a space between */ + + if (strcmp(option + 1, opts[i].name) == 0) { + opt_index++; + + if (opt_index < vm_args->nOptions) { + opt_arg = strdup(vm_args->options[opt_index].optionString); + opt_index++; + return opts[i].value; + } + + return OPT_ERROR; + + } else { + /* parameter and option have no space between */ + + /* FIXME: this assumption is plain wrong, hits you if there is a + * parameter with no argument starting with same letter as param with argument + * but named after that one, ouch! */ + + size_t l = strlen(opts[i].name); + + if (strlen(option + 1) > l) { + if (memcmp(option + 1, opts[i].name, l) == 0) { + opt_index++; + opt_arg = strdup(option + 1 + l); + return opts[i].value; + } + } + } + } + } + + return OPT_ERROR; +} + + +/* + * 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: + */ diff --git a/src/vmcore/options.h b/src/vmcore/options.h new file mode 100644 index 000000000..fef61b247 --- /dev/null +++ b/src/vmcore/options.h @@ -0,0 +1,186 @@ +/* src/vm/options.h - define global options extern + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: options.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _OPTIONS_H +#define _OPTIONS_H + + +#include "config.h" +#include "vm/types.h" + +#include "native/jni.h" +#include "vm/global.h" + + +/* reserved option numbers ****************************************************/ + +/* define these negative since the other options are an enum */ + +#define OPT_DONE -1 +#define OPT_ERROR -2 +#define OPT_IGNORE -3 + + +typedef struct opt_struct opt_struct; + +struct opt_struct { + char *name; + bool arg; + int value; +}; + + +/* global variables ***********************************************************/ + +extern s4 opt_index; +extern char *opt_arg; + +extern bool opt_foo; + +extern bool opt_jit; +extern bool opt_intrp; + +extern bool opt_jar; +extern bool opt_run; + +extern s4 opt_heapmaxsize; +extern s4 opt_heapstartsize; +extern s4 opt_stacksize; + +extern bool opt_verbose; +extern bool opt_debugcolor; +extern bool compileall; + +extern bool loadverbose; /* Print debug messages during loading */ +extern bool linkverbose; +extern bool initverbose; /* Log class initialization */ + +extern bool opt_verboseclass; +extern bool opt_verbosegc; +extern bool opt_verbosejni; +extern bool opt_verbosecall; +extern bool opt_verboseexception; + +extern bool showmethods; +extern bool showconstantpool; +extern bool showutf; + +extern char *opt_method; +extern char *opt_signature; + +extern bool compileverbose; +extern bool showstack; + +extern bool opt_showdisassemble; +extern bool opt_shownops; +extern bool opt_showddatasegment; +extern bool opt_showintermediate; +extern bool opt_showexceptionstubs; +extern bool opt_shownativestub; + +extern bool useinlining; +extern bool inlinevirtuals; +extern bool inlineexceptions; +extern bool inlineparamopt; +extern bool inlineoutsiders; + +extern bool checkbounds; +extern bool checknull; +extern bool opt_noieee; +extern bool checksync; +#if defined(ENABLE_LOOP) +extern bool opt_loops; +#endif + +extern bool makeinitializations; + +#if defined(ENABLE_STATISTICS) +extern bool opt_stat; +extern bool opt_getloadingtime; +extern bool opt_getcompilingtime; +#endif +#if defined(ENABLE_VERIFIER) +extern bool opt_verify; +#endif +extern bool opt_eager; + +#if defined(ENABLE_PROFILING) +extern bool opt_prof; +extern bool opt_prof_bb; +#endif + + +/* optimization options *******************************************************/ + +#if defined(ENABLE_IFCONV) +extern bool opt_ifconv; +#endif + +#if defined(ENABLE_LSRA) || defined(ENABLE_SSA) +extern bool opt_lsra; +#endif + + +/* interpreter options ********************************************************/ + +#if defined(ENABLE_INTRP) +extern bool opt_no_dynamic; +extern bool opt_no_replication; +extern bool opt_no_quicksuper; + +extern s4 opt_static_supers; +extern bool vm_debug; +#endif + + +/* function prototypes ********************************************************/ + +s4 options_get(opt_struct *opts, JavaVMInitArgs *vm_args); + +#endif /* _OPTIONS_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: + */ diff --git a/src/vmcore/references.h b/src/vmcore/references.h new file mode 100644 index 000000000..04344fb87 --- /dev/null +++ b/src/vmcore/references.h @@ -0,0 +1,172 @@ +/* src/vmcore/references.h - references to classes/fields/methods + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: references.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + +#ifndef _REFERENCES_H_ +#define _REFERENCES_H_ + +/* forward typedefs ***********************************************************/ + +typedef struct constant_classref constant_classref; +typedef struct constant_FMIref constant_FMIref; + + +/* constant_classref **********************************************************/ + +struct constant_classref { + void *pseudo_vftbl; /* for distinguishing it from classinfo */ + struct classinfo *referer; /* class containing the reference */ + struct utf *name; /* name of the class refered to */ +}; + + +/* classref_or_classinfo ******************************************************/ + +typedef union classref_or_classinfo { + constant_classref *ref; /* a symbolic class reference */ + struct classinfo *cls; /* an already loaded class */ + void *any; /* used for general access (x != NULL,...) */ +} classref_or_classinfo; + + +/* parseddesc *****************************************************************/ + +typedef union parseddesc { + struct typedesc *fd; /* parsed field descriptor */ + struct methoddesc *md; /* parsed method descriptor */ + void *any; /* used for simple test against NULL */ +} parseddesc; + + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/descriptor.h" +#include "vmcore/field.h" +#include "vmcore/method.h" +#include "vmcore/utf8.h" + + +/*----------------------------------------------------------------------------*/ +/* References */ +/* */ +/* This header files defines the following types used for references to */ +/* classes/methods/fields and descriptors: */ +/* */ +/* classinfo * a loaded class */ +/* constant_classref a symbolic reference */ +/* classref_or_classinfo a loaded class or a symbolic reference */ +/* */ +/* constant_FMIref a symb. ref. to a field/method/intf.method */ +/* */ +/* typedesc * describes a field type */ +/* methoddesc * descrives a method type */ +/* parseddesc describes a field type or a method type */ +/*----------------------------------------------------------------------------*/ + +/* structs ********************************************************************/ + +/* constant_FMIref ************************************************************/ + +struct constant_FMIref{ /* Fieldref, Methodref and InterfaceMethodref */ + union { + s4 index; /* used only within the loader */ + constant_classref *classref; /* class having this field/meth./intfm. */ + fieldinfo *field; /* resolved field */ + methodinfo *method; /* resolved method */ + } p; + utf *name; /* field/method/interfacemethod name */ + utf *descriptor; /* field/method/intfmeth. type descriptor string */ + parseddesc parseddesc; /* parsed descriptor */ +}; + + +/* macros *********************************************************************/ + +/* a value that never occurrs in classinfo.header.vftbl */ +#define CLASSREF_PSEUDO_VFTBL ((void *) 1) + +/* macro for testing if a classref_or_classinfo is a classref */ +/* `reforinfo` is only evaluated once */ +#define IS_CLASSREF(reforinfo) \ + ((reforinfo).ref->pseudo_vftbl == CLASSREF_PSEUDO_VFTBL) + +/* macro for testing if a constant_FMIref has been resolved */ +/* `fmiref` is only evaluated once */ +#define IS_FMIREF_RESOLVED(fmiref) \ + ((fmiref)->p.classref->pseudo_vftbl != CLASSREF_PSEUDO_VFTBL) + +/* the same as IS_CLASSREF, but also check against NULL */ +#define IS_XCLASSREF(reforinfo) \ + ((reforinfo).any && IS_CLASSREF(reforinfo)) + +/* macro for casting a classref/classinfo * to a classref_or_classinfo */ +#define CLASSREF_OR_CLASSINFO(value) \ + (*((classref_or_classinfo *)(&(value)))) + +/* macro for accessing the name of a classref/classinfo */ +#define CLASSREF_OR_CLASSINFO_NAME(value) \ + (IS_CLASSREF(value) ? (value).ref->name : (value).cls->name) + +/* macro for accessing the class name of a method reference */ +#define METHODREF_CLASSNAME(fmiref) \ + (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.method->class->name \ + : (fmiref)->p.classref->name) + +/* macro for accessing the class name of a method reference */ +#define FIELDREF_CLASSNAME(fmiref) \ + (IS_FMIREF_RESOLVED(fmiref) ? (fmiref)->p.field->class->name \ + : (fmiref)->p.classref->name) + +/* initialize a constant_classref with referer `ref` and name `classname` */ + +#define CLASSREF_INIT(c,ref,classname) \ + do { \ + (c).pseudo_vftbl = CLASSREF_PSEUDO_VFTBL; \ + (c).referer = (ref); \ + (c).name = (classname); \ + } while (0) + +#endif /* _REFERENCES_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: + */ + diff --git a/src/vmcore/resolve.c b/src/vmcore/resolve.c new file mode 100644 index 000000000..ec4caac04 --- /dev/null +++ b/src/vmcore/resolve.c @@ -0,0 +1,3025 @@ +/* src/vmcore/resolve.c - resolving classes/interfaces/fields/methods + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: resolve.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vm/access.h" +#include "vm/exceptions.h" +#include "vm/global.h" + +#include "vm/jit/jit.h" +#include "vm/jit/verify/typeinfo.h" + +#include "vmcore/classcache.h" +#include "vmcore/descriptor.h" +#include "vmcore/linker.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/resolve.h" + + +/******************************************************************************/ +/* DEBUG HELPERS */ +/******************************************************************************/ + +/*#define RESOLVE_VERBOSE*/ + +/******************************************************************************/ +/* CLASS RESOLUTION */ +/******************************************************************************/ + +/* resolve_class_from_name ***************************************************** + + Resolve a symbolic class reference + + IN: + referer..........the class containing the reference + refmethod........the method from which resolution was triggered + (may be NULL if not applicable) + classname........class name to resolve + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + checkaccess......if true, access rights to the class are checked + link.............if true, guarantee that the returned class, if any, + has been linked + + OUT: + *result..........set to result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + + NOTE: + The returned class is *not* guaranteed to be linked! + (It is guaranteed to be loaded, though.) + +*******************************************************************************/ + +bool resolve_class_from_name(classinfo *referer, + methodinfo *refmethod, + utf *classname, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result) +{ + classinfo *cls = NULL; + char *utf_ptr; + int len; + + assert(result); + assert(referer); + assert(classname); + assert(mode == resolveLazy || mode == resolveEager); + + *result = NULL; + +#ifdef RESOLVE_VERBOSE + printf("resolve_class_from_name("); + utf_fprint_printable_ascii(stdout,referer->name); + printf(",%p,",(void*)referer->classloader); + utf_fprint_printable_ascii(stdout,classname); + printf(",%d,%d)\n",(int)checkaccess,(int)link); +#endif + + /* lookup if this class has already been loaded */ + + cls = classcache_lookup(referer->classloader, classname); + +#ifdef RESOLVE_VERBOSE + printf(" lookup result: %p\n",(void*)cls); +#endif + + if (!cls) { + /* resolve array types */ + + if (classname->text[0] == '[') { + utf_ptr = classname->text + 1; + len = classname->blength - 1; + + /* classname is an array type name */ + + switch (*utf_ptr) { + case 'L': + utf_ptr++; + len -= 2; + /* FALLTHROUGH */ + case '[': + /* the component type is a reference type */ + /* resolve the component type */ + if (!resolve_class_from_name(referer,refmethod, + utf_new(utf_ptr,len), + mode,checkaccess,link,&cls)) + return false; /* exception */ + if (!cls) { + assert(mode == resolveLazy); + return true; /* be lazy */ + } + /* create the array class */ + cls = class_array_of(cls,false); + if (!cls) + return false; /* exception */ + } + } + else { + /* the class has not been loaded, yet */ + if (mode == resolveLazy) + return true; /* be lazy */ + } + +#ifdef RESOLVE_VERBOSE + printf(" loading...\n"); +#endif + + /* load the class */ + if (!cls) { + if (!(cls = load_class_from_classloader(classname, + referer->classloader))) + return false; /* exception */ + } + } + + /* the class is now loaded */ + assert(cls); + assert(cls->state & CLASS_LOADED); + +#ifdef RESOLVE_VERBOSE + printf(" checking access rights...\n"); +#endif + + /* check access rights of referer to refered class */ + if (checkaccess && !access_is_accessible_class(referer,cls)) { + int msglen; + char *message; + + msglen = utf_bytes(cls->name) + utf_bytes(referer->name) + 100; + message = MNEW(char, msglen); + strcpy(message, "class is not accessible ("); + utf_cat_classname(message, cls->name); + strcat(message, " from "); + utf_cat_classname(message, referer->name); + strcat(message, ")"); + + exceptions_throw_illegalaccessexception(message); + + MFREE(message, char, msglen); + + return false; /* exception */ + } + + /* link the class if necessary */ + if (link) { + if (!(cls->state & CLASS_LINKED)) + if (!link_class(cls)) + return false; /* exception */ + + assert(cls->state & CLASS_LINKED); + } + + /* resolution succeeds */ +#ifdef RESOLVE_VERBOSE + printf(" success.\n"); +#endif + *result = cls; + return true; +} + +/* resolve_classref ************************************************************ + + Resolve a symbolic class reference + + IN: + refmethod........the method from which resolution was triggered + (may be NULL if not applicable) + ref..............class reference + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + checkaccess......if true, access rights to the class are checked + link.............if true, guarantee that the returned class, if any, + has been linked + + OUT: + *result..........set to result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + +*******************************************************************************/ + +bool resolve_classref(methodinfo *refmethod, + constant_classref *ref, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result) +{ + return resolve_classref_or_classinfo(refmethod,CLASSREF_OR_CLASSINFO(ref),mode,checkaccess,link,result); +} + +/* resolve_classref_or_classinfo *********************************************** + + Resolve a symbolic class reference if necessary + + IN: + refmethod........the method from which resolution was triggered + (may be NULL if not applicable) + cls..............class reference or classinfo + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + checkaccess......if true, access rights to the class are checked + link.............if true, guarantee that the returned class, if any, + has been linked + + OUT: + *result..........set to result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + +*******************************************************************************/ + +bool resolve_classref_or_classinfo(methodinfo *refmethod, + classref_or_classinfo cls, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result) +{ + classinfo *c; + + assert(cls.any); + assert(mode == resolveEager || mode == resolveLazy); + assert(result); + +#ifdef RESOLVE_VERBOSE + printf("resolve_classref_or_classinfo("); + utf_fprint_printable_ascii(stdout,(IS_CLASSREF(cls)) ? cls.ref->name : cls.cls->name); + printf(",%i,%i,%i)\n",mode,(int)checkaccess,(int)link); +#endif + + *result = NULL; + + if (IS_CLASSREF(cls)) { + /* we must resolve this reference */ + + if (!resolve_class_from_name(cls.ref->referer, refmethod, cls.ref->name, + mode, checkaccess, link, &c)) + goto return_exception; + + } else { + /* cls has already been resolved */ + c = cls.cls; + assert(c->state & CLASS_LOADED); + } + assert(c || (mode == resolveLazy)); + + if (!c) + return true; /* be lazy */ + + assert(c); + assert(c->state & CLASS_LOADED); + + if (link) { + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + goto return_exception; + + assert(c->state & CLASS_LINKED); + } + + /* succeeded */ + *result = c; + return true; + + return_exception: + *result = NULL; + return false; +} + + +/* resolve_class_from_typedesc ************************************************* + + Return a classinfo * for the given type descriptor + + IN: + d................type descriptor + checkaccess......if true, access rights to the class are checked + link.............if true, guarantee that the returned class, if any, + has been linked + OUT: + *result..........set to result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + + NOTE: + This function always resolves eagerly. + +*******************************************************************************/ + +bool resolve_class_from_typedesc(typedesc *d, bool checkaccess, bool link, classinfo **result) +{ + classinfo *cls; + + assert(d); + assert(result); + + *result = NULL; + +#ifdef RESOLVE_VERBOSE + printf("resolve_class_from_typedesc("); + descriptor_debug_print_typedesc(stdout,d); + printf(",%i,%i)\n",(int)checkaccess,(int)link); +#endif + + if (d->type == TYPE_ADR) { + /* a reference type */ + assert(d->classref); + if (!resolve_classref_or_classinfo(NULL,CLASSREF_OR_CLASSINFO(d->classref), + resolveEager,checkaccess,link,&cls)) + return false; /* exception */ + } + else { + /* a primitive type */ + cls = primitivetype_table[d->decltype].class_primitive; + assert(cls->state & CLASS_LOADED); + if (!(cls->state & CLASS_LINKED)) + if (!link_class(cls)) + return false; /* exception */ + } + assert(cls); + assert(cls->state & CLASS_LOADED); + assert(!link || (cls->state & CLASS_LINKED)); + +#ifdef RESOLVE_VERBOSE + printf(" result = ");utf_fprint_printable_ascii(stdout,cls->name);printf("\n"); +#endif + + *result = cls; + return true; +} + +/******************************************************************************/ +/* SUBTYPE SET CHECKS */ +/******************************************************************************/ + +/* resolve_subtype_check ******************************************************* + + Resolve the given types lazily and perform a subtype check + + IN: + refmethod........the method triggering the resolution + subtype..........checked to be a subtype of supertype + supertype........the super type to check agaings + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + error............which type of exception to throw if + the test fails. May be: + resolveLinkageError, or + resolveIllegalAccessError + IMPORTANT: If error==resolveIllegalAccessError, + then array types are not checked. + + RETURN VALUE: + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types. (This can only happen for + mode == resolveLazy.) + resolveFailed........the check failed, an exception has been thrown. + + NOTE: + The types are resolved first, so any + exception which may occurr during resolution may + be thrown by this function. + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_subtype_check(methodinfo *refmethod, + classref_or_classinfo subtype, + classref_or_classinfo supertype, + resolve_mode_t mode, + resolve_err_t error) +{ + classinfo *subclass; + typeinfo subti; + typecheck_result r; + + assert(refmethod); + assert(subtype.any); + assert(supertype.any); + assert(mode == resolveLazy || mode == resolveEager); + assert(error == resolveLinkageError || error == resolveIllegalAccessError); + + /* resolve the subtype */ + + if (!resolve_classref_or_classinfo(refmethod,subtype,mode,false,true,&subclass)) { + /* the subclass could not be resolved. therefore we are sure that */ + /* no instances of this subclass will ever exist -> skip this test */ + /* XXX this assumes that class loading has invariant results (as in JVM spec) */ + exceptions_clear_exception(); + return resolveSucceeded; + } + if (!subclass) + return resolveDeferred; /* be lazy */ + + assert(subclass->state & CLASS_LINKED); + + /* do not check access to protected members of arrays */ + + if (error == resolveIllegalAccessError && subclass->name->text[0] == '[') { + return resolveSucceeded; + } + + /* perform the subtype check */ + + typeinfo_init_classinfo(&subti,subclass); +check_again: + r = typeinfo_is_assignable_to_class(&subti,supertype); + if (r == typecheck_FAIL) + return resolveFailed; /* failed, exception is already set */ + + if (r == typecheck_MAYBE) { + assert(IS_CLASSREF(supertype)); + if (mode == resolveEager) { + if (!resolve_classref_or_classinfo(refmethod,supertype, + resolveEager,false,true, + &supertype.cls)) + { + return resolveFailed; + } + assert(supertype.cls); + goto check_again; + } + + return resolveDeferred; /* be lazy */ + } + + if (!r) { + /* sub class relationship is false */ + + char *message; + int msglen; + +#if defined(RESOLVE_VERBOSE) + printf("SUBTYPE CHECK FAILED!\n"); +#endif + + msglen = + utf_bytes(subclass->name) + + utf_bytes(CLASSREF_OR_CLASSINFO_NAME(supertype)) + + 200; + + message = MNEW(char, msglen); + + strcpy(message, (error == resolveIllegalAccessError) ? + "illegal access to protected member (" + : "subtype constraint violated ("); + + utf_cat_classname(message, subclass->name); + strcat(message, " is not a subclass of "); + utf_cat_classname(message, CLASSREF_OR_CLASSINFO_NAME(supertype)); + strcat(message, ")"); + + if (error == resolveIllegalAccessError) + exceptions_throw_illegalaccessexception(message); + else + exceptions_throw_linkageerror(message, NULL); + + MFREE(message, char, msglen); + + return resolveFailed; /* exception */ + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_lazy_subtype_checks ************************************************* + + Resolve the types to check lazily and perform subtype checks + + IN: + refmethod........the method triggering the resolution + subtinfo.........the typeinfo containing the subtypes + supertype........the supertype to test againgst + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + error............which type of exception to throw if + the test fails. May be: + resolveLinkageError, or + resolveIllegalAccessError + IMPORTANT: If error==resolveIllegalAccessError, + then array types in the set are skipped. + + RETURN VALUE: + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types + resolveFailed........the check failed, an exception has been thrown. + + NOTE: + The references in the set are resolved first, so any + exception which may occurr during resolution may + be thrown by this function. + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_lazy_subtype_checks(methodinfo *refmethod, + typeinfo *subtinfo, + classref_or_classinfo supertype, + resolve_err_t error) +{ + int count; + int i; + resolve_result_t result; + + assert(refmethod); + assert(subtinfo); + assert(supertype.any); + assert(error == resolveLinkageError || error == resolveIllegalAccessError); + + /* returnAddresses are illegal here */ + + if (TYPEINFO_IS_PRIMITIVE(*subtinfo)) { + exceptions_throw_verifyerror(refmethod, + "Invalid use of returnAddress"); + return resolveFailed; + } + + /* uninitialized objects are illegal here */ + + if (TYPEINFO_IS_NEWOBJECT(*subtinfo)) { + exceptions_throw_verifyerror(refmethod, + "Invalid use of uninitialized object"); + return resolveFailed; + } + + /* the nulltype is always assignable */ + + if (TYPEINFO_IS_NULLTYPE(*subtinfo)) + return resolveSucceeded; + + /* every type is assignable to (BOOTSTRAP)java.lang.Object */ + + if (supertype.cls == class_java_lang_Object + || (CLASSREF_OR_CLASSINFO_NAME(supertype) == utf_java_lang_Object + && refmethod->class->classloader == NULL)) + { + return resolveSucceeded; + } + + if (subtinfo->merged) { + + /* for a merged type we have to do a series of checks */ + + count = subtinfo->merged->count; + for (i=0; imerged->list[i]; + if (subtinfo->dimension > 0) { + /* a merge of array types */ + /* the merged list contains the possible _element_ types, */ + /* so we have to create array types with these elements. */ + if (IS_CLASSREF(c)) { + c.ref = class_get_classref_multiarray_of(subtinfo->dimension,c.ref); + } + else { + c.cls = class_multiarray_of(subtinfo->dimension,c.cls,false); + } + } + + /* do the subtype check against the type c */ + + result = resolve_subtype_check(refmethod,c,supertype,resolveLazy,error); + if (result != resolveSucceeded) + return result; + } + } + else { + + /* a single type, this is the common case, hopefully */ + + if (CLASSREF_OR_CLASSINFO_NAME(subtinfo->typeclass) + == CLASSREF_OR_CLASSINFO_NAME(supertype)) + { + /* the class names are the same */ + /* equality is guaranteed by the loading constraints */ + return resolveSucceeded; + } + else { + + /* some other type name, try to perform the check lazily */ + + return resolve_subtype_check(refmethod, + subtinfo->typeclass,supertype, + resolveLazy, + error); + } + } + + /* everything ok */ + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_and_check_subtype_set *********************************************** + + Resolve the references in the given set and test subtype relationships + + IN: + refmethod........the method triggering the resolution + ref..............a set of class/interface references + (may be empty) + typeref..........the type to test against the set + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + error............which type of exception to throw if + the test fails. May be: + resolveLinkageError, or + resolveIllegalAccessError + IMPORTANT: If error==resolveIllegalAccessError, + then array types in the set are skipped. + + RETURN VALUE: + resolveSucceeded.....the check succeeded + resolveDeferred......the check could not be performed due to + unresolved types. (This can only happen if + mode == resolveLazy.) + resolveFailed........the check failed, an exception has been thrown. + + NOTE: + The references in the set are resolved first, so any + exception which may occurr during resolution may + be thrown by this function. + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +static resolve_result_t resolve_and_check_subtype_set(methodinfo *refmethod, + unresolved_subtype_set *ref, + classref_or_classinfo typeref, + resolve_mode_t mode, + resolve_err_t error) +{ + classref_or_classinfo *setp; + typecheck_result checkresult; + + assert(refmethod); + assert(ref); + assert(typeref.any); + assert(mode == resolveLazy || mode == resolveEager); + assert(error == resolveLinkageError || error == resolveIllegalAccessError); + +#if defined(RESOLVE_VERBOSE) + printf("resolve_and_check_subtype_set:\n"); + unresolved_subtype_set_debug_dump(ref, stdout); + if (IS_CLASSREF(typeref)) + class_classref_println(typeref.ref); + else + class_println(typeref.cls); +#endif + + setp = ref->subtyperefs; + + /* an empty set of tests always succeeds */ + if (!setp || !setp->any) { + return resolveSucceeded; + } + + /* first resolve the type if necessary */ + if (!resolve_classref_or_classinfo(refmethod,typeref,mode,false,true,&(typeref.cls))) + return resolveFailed; /* exception */ + if (!typeref.cls) + return resolveDeferred; /* be lazy */ + + assert(typeref.cls->state & CLASS_LINKED); + + /* iterate over the set members */ + + for (; setp->any; ++setp) { + checkresult = resolve_subtype_check(refmethod,*setp,typeref,mode,error); +#if defined(RESOLVE_VERBOSE) + if (checkresult != resolveSucceeded) + printf("SUBTYPE CHECK FAILED!\n"); +#endif + if (checkresult != resolveSucceeded) + return checkresult; + } + + /* check succeeds */ + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/******************************************************************************/ +/* CLASS RESOLUTION */ +/******************************************************************************/ + +/* resolve_class *************************************************************** + + Resolve an unresolved class reference. The class is also linked. + + IN: + ref..............struct containing the reference + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + checkaccess......if true, access rights to the class are checked + + OUT: + *result..........set to the result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + +*******************************************************************************/ + +#ifdef ENABLE_VERIFIER +bool resolve_class(unresolved_class *ref, + resolve_mode_t mode, + bool checkaccess, + classinfo **result) +{ + classinfo *cls; + resolve_result_t checkresult; + + assert(ref); + assert(result); + assert(mode == resolveLazy || mode == resolveEager); + + *result = NULL; + +#ifdef RESOLVE_VERBOSE + unresolved_class_debug_dump(ref,stdout); +#endif + + /* first we must resolve the class */ + if (!resolve_classref(ref->referermethod, + ref->classref,mode,checkaccess,true,&cls)) + { + /* the class reference could not be resolved */ + return false; /* exception */ + } + if (!cls) + return true; /* be lazy */ + + assert(cls); + assert((cls->state & CLASS_LOADED) && (cls->state & CLASS_LINKED)); + + /* now we check the subtype constraints */ + + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->subtypeconstraints), + CLASSREF_OR_CLASSINFO(cls), + mode, + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + + /* succeed */ + *result = cls; + return true; +} +#endif /* ENABLE_VERIFIER */ + +/* resolve_classref_eager ****************************************************** + + Resolve an unresolved class reference eagerly. The class is also linked and + access rights to the class are checked. + + IN: + ref..............constant_classref to the class + + RETURN VALUE: + classinfo * to the class, or + NULL if an exception has been thrown + +*******************************************************************************/ + +classinfo * resolve_classref_eager(constant_classref *ref) +{ + classinfo *c; + + if (!resolve_classref(NULL,ref,resolveEager,true,true,&c)) + return NULL; + + return c; +} + +/* resolve_classref_eager_nonabstract ****************************************** + + Resolve an unresolved class reference eagerly. The class is also linked and + access rights to the class are checked. A check is performed that the class + is not abstract. + + IN: + ref..............constant_classref to the class + + RETURN VALUE: + classinfo * to the class, or + NULL if an exception has been thrown + +*******************************************************************************/ + +classinfo * resolve_classref_eager_nonabstract(constant_classref *ref) +{ + classinfo *c; + + if (!resolve_classref(NULL,ref,resolveEager,true,true,&c)) + return NULL; + + /* ensure that the class is not abstract */ + + if (c->flags & ACC_ABSTRACT) { + exceptions_throw_verifyerror(NULL,"creating instance of abstract class"); + return NULL; + } + + return c; +} + +/* resolve_class_eager ********************************************************* + + Resolve an unresolved class reference eagerly. The class is also linked and + access rights to the class are checked. + + IN: + ref..............struct containing the reference + + RETURN VALUE: + classinfo * to the class, or + NULL if an exception has been thrown + +*******************************************************************************/ + +#ifdef ENABLE_VERIFIER +classinfo * resolve_class_eager(unresolved_class *ref) +{ + classinfo *c; + + if (!resolve_class(ref,resolveEager,true,&c)) + return NULL; + + return c; +} +#endif /* ENABLE_VERIFIER */ + +/******************************************************************************/ +/* FIELD RESOLUTION */ +/******************************************************************************/ + +/* resolve_field_verifier_checks ******************************************* + + Do the verifier checks necessary after field has been resolved. + + IN: + refmethod........the method containing the reference + fieldref.........the field reference + container........the class where the field was found + fi...............the fieldinfo of the resolved field + instanceti.......instance typeinfo, if available + valueti..........value typeinfo, if available + isstatic.........true if this is a *STATIC* instruction + isput............true if this is a PUT* instruction + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_field_verifier_checks(methodinfo *refmethod, + constant_FMIref *fieldref, + classinfo *container, + fieldinfo *fi, + typeinfo *instanceti, + typeinfo *valueti, + bool isstatic, + bool isput) +{ + classinfo *declarer; + classinfo *referer; + resolve_result_t result; + constant_classref *fieldtyperef; + + assert(refmethod); + assert(fieldref); + assert(container); + assert(fi); + + /* get the classinfos and the field type */ + + referer = refmethod->class; + assert(referer); + + declarer = fi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); + + fieldtyperef = fieldref->parseddesc.fd->classref; + + /* check static */ + +#if true != 1 +#error This code assumes that `true` is `1`. Otherwise, use the ternary operator below. +#endif + + if (((fi->flags & ACC_STATIC) != 0) != isstatic) { + /* a static field is accessed via an instance, or vice versa */ + exceptions_throw_incompatibleclasschangeerror(declarer, + (fi->flags & ACC_STATIC) + ? "static field accessed via instance" + : "instance field accessed without instance"); + + return resolveFailed; + } + + /* check access rights */ + + if (!access_is_accessible_member(referer,declarer,fi->flags)) { + int msglen; + char *message; + + msglen = + utf_bytes(declarer->name) + + utf_bytes(fi->name) + + utf_bytes(referer->name) + + 100; + + message = MNEW(char, msglen); + + strcpy(message, "field is not accessible ("); + utf_cat_classname(message, declarer->name); + strcat(message, "."); + utf_cat(message, fi->name); + strcat(message, " from "); + utf_cat_classname(message, referer->name); + strcat(message, ")"); + + exceptions_throw_illegalaccessexception(message); + + MFREE(message, char, msglen); + + return resolveFailed; /* exception */ + } + + /* for non-static methods we have to check the constraints on the */ + /* instance type */ + + if (instanceti) { + typeinfo *insttip; + typeinfo tinfo; + + /* The instanceslot must contain a reference to a non-array type */ + + if (!TYPEINFO_IS_REFERENCE(*instanceti)) { + exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on non-reference"); + return resolveFailed; + } + if (TYPEINFO_IS_ARRAY(*instanceti)) { + exceptions_throw_verifyerror(refmethod, "illegal instruction: field access on array"); + return resolveFailed; + } + + if (isput && TYPEINFO_IS_NEWOBJECT(*instanceti)) + { + /* The instruction writes a field in an uninitialized object. */ + /* This is only allowed when a field of an uninitialized 'this' object is */ + /* written inside an initialization method */ + + classinfo *initclass; + instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); + + if (ins != NULL) { + exceptions_throw_verifyerror(refmethod, "accessing field of uninitialized object"); + return resolveFailed; + } + + /* XXX check that class of field == refmethod->class */ + initclass = referer; /* XXX classrefs */ + assert(initclass->state & CLASS_LINKED); + + typeinfo_init_classinfo(&tinfo, initclass); + insttip = &tinfo; + } + else { + insttip = instanceti; + } + + result = resolve_lazy_subtype_checks(refmethod, + insttip, + CLASSREF_OR_CLASSINFO(container), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + + /* check protected access */ + + if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) + { + result = resolve_lazy_subtype_checks(refmethod, + instanceti, + CLASSREF_OR_CLASSINFO(referer), + resolveIllegalAccessError); + if (result != resolveSucceeded) + return result; + } + + } + + /* for PUT* instructions we have to check the constraints on the value type */ + + if (valueti) { + assert(fieldtyperef); + + /* check subtype constraints */ + result = resolve_lazy_subtype_checks(refmethod, + valueti, + CLASSREF_OR_CLASSINFO(fieldtyperef), + resolveLinkageError); + + if (result != resolveSucceeded) + return result; + } + + /* impose loading constraint on field type */ + + if (fi->type == TYPE_ADR) { + assert(fieldtyperef); + if (!classcache_add_constraint(declarer->classloader, + referer->classloader, + fieldtyperef->name)) + return resolveFailed; + } + + /* XXX impose loading constraint on instance? */ + + /* everything ok */ + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + +/* resolve_field_lazy ********************************************************** + + Resolve an unresolved field reference lazily + + NOTE: This function does NOT do any verification checks. In case of a + successful resolution, you must call resolve_field_verifier_checks + in order to perform the necessary checks! + + IN: + refmethod........the referer method + fieldref.........the field reference + + RETURN VALUE: + resolveSucceeded.....the reference has been resolved + resolveDeferred......the resolving could not be performed lazily + resolveFailed........resolving failed, an exception has been thrown. + +*******************************************************************************/ + +resolve_result_t resolve_field_lazy(methodinfo *refmethod, + constant_FMIref *fieldref) +{ + classinfo *referer; + classinfo *container; + fieldinfo *fi; + + assert(refmethod); + + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* check if the field itself is already resolved */ + + if (IS_FMIREF_RESOLVED(fieldref)) + return resolveSucceeded; + + /* first we must resolve the class containg the field */ + + /* XXX can/may lazyResolving trigger linking? */ + + if (!resolve_class_from_name(referer, refmethod, + fieldref->p.classref->name, resolveLazy, true, true, &container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the field in `container` + * or one of its superclasses */ + + fi = class_resolvefield(container, + fieldref->name, fieldref->descriptor, + referer, true); + if (!fi) { + /* The field does not exist. But since we were called lazily, */ + /* this error must not be reported now. (It will be reported */ + /* if eager resolving of this field is ever tried.) */ + + exceptions_clear_exception(); + return resolveDeferred; /* be lazy */ + } + + /* cache the result of the resolution */ + + fieldref->p.field = fi; + + /* everything ok */ + return resolveSucceeded; +} + +/* resolve_field *************************************************************** + + Resolve an unresolved field reference + + IN: + ref..............struct containing the reference + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + + OUT: + *result..........set to the result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + +*******************************************************************************/ + +bool resolve_field(unresolved_field *ref, + resolve_mode_t mode, + fieldinfo **result) +{ + classinfo *referer; + classinfo *container; + classinfo *declarer; + constant_classref *fieldtyperef; + fieldinfo *fi; + resolve_result_t checkresult; + + assert(ref); + assert(result); + assert(mode == resolveLazy || mode == resolveEager); + + *result = NULL; + +#ifdef RESOLVE_VERBOSE + unresolved_field_debug_dump(ref,stdout); +#endif + + /* the class containing the reference */ + + referer = ref->referermethod->class; + assert(referer); + + /* check if the field itself is already resolved */ + if (IS_FMIREF_RESOLVED(ref->fieldref)) { + fi = ref->fieldref->p.field; + container = fi->class; + goto resolved_the_field; + } + + /* first we must resolve the class containg the field */ + if (!resolve_class_from_name(referer,ref->referermethod, + ref->fieldref->p.classref->name,mode,true,true,&container)) + { + /* the class reference could not be resolved */ + return false; /* exception */ + } + if (!container) + return true; /* be lazy */ + + assert(container); + assert(container->state & CLASS_LOADED); + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the field in `container` + * or one of its superclasses */ + +#ifdef RESOLVE_VERBOSE + printf(" resolving field in class...\n"); +#endif + + fi = class_resolvefield(container, + ref->fieldref->name,ref->fieldref->descriptor, + referer,true); + if (!fi) { + if (mode == resolveLazy) { + /* The field does not exist. But since we were called lazily, */ + /* this error must not be reported now. (It will be reported */ + /* if eager resolving of this field is ever tried.) */ + + exceptions_clear_exception(); + return true; /* be lazy */ + } + + return false; /* exception */ + } + + /* cache the result of the resolution */ + ref->fieldref->p.field = fi; + +resolved_the_field: + +#ifdef ENABLE_VERIFIER + /* Checking opt_verify is ok here, because the NULL iptr guarantees */ + /* that no missing parts of an instruction will be accessed. */ + if (opt_verify) { + checkresult = resolve_field_verifier_checks( + ref->referermethod, + ref->fieldref, + container, + fi, + NULL, /* instanceti, handled by constraints below */ + NULL, /* valueti, handled by constraints below */ + (ref->flags & RESOLVE_STATIC) != 0, /* isstatic */ + (ref->flags & RESOLVE_PUTFIELD) != 0 /* isput */); + + if (checkresult != resolveSucceeded) + return (bool) checkresult; + + declarer = fi->class; + assert(declarer); + assert(declarer->state & CLASS_LOADED); + assert(declarer->state & CLASS_LINKED); + + /* for non-static accesses we have to check the constraints on the */ + /* instance type */ + + if (!(ref->flags & RESOLVE_STATIC)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(container), + mode, resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + + fieldtyperef = ref->fieldref->parseddesc.fd->classref; + + /* for PUT* instructions we have to check the constraints on the value type */ + if (((ref->flags & RESOLVE_PUTFIELD) != 0) && fi->type == TYPE_ADR) { + assert(fieldtyperef); + if (!SUBTYPESET_IS_EMPTY(ref->valueconstraints)) { + /* check subtype constraints */ + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->valueconstraints), + CLASSREF_OR_CLASSINFO(fieldtyperef), + mode, resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + } + + /* check protected access */ + if (((fi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(referer), + mode, + resolveIllegalAccessError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + + } +#endif /* ENABLE_VERIFIER */ + + /* succeed */ + *result = fi; + + return true; +} + +/* resolve_field_eager ********************************************************* + + Resolve an unresolved field reference eagerly. + + IN: + ref..............struct containing the reference + + RETURN VALUE: + fieldinfo * to the field, or + NULL if an exception has been thrown + +*******************************************************************************/ + +fieldinfo * resolve_field_eager(unresolved_field *ref) +{ + fieldinfo *fi; + + if (!resolve_field(ref,resolveEager,&fi)) + return NULL; + + return fi; +} + +/******************************************************************************/ +/* METHOD RESOLUTION */ +/******************************************************************************/ + +/* resolve_method_invokespecial_lookup ***************************************** + + Do the special lookup for methods invoked by INVOKESPECIAL + + IN: + refmethod........the method containing the reference + mi...............the methodinfo of the resolved method + + RETURN VALUE: + a methodinfo *...the result of the lookup, + NULL.............an exception has been thrown + +*******************************************************************************/ + +methodinfo * resolve_method_invokespecial_lookup(methodinfo *refmethod, + methodinfo *mi) +{ + classinfo *declarer; + classinfo *referer; + + assert(refmethod); + assert(mi); + + /* get referer and declarer classes */ + + referer = refmethod->class; + assert(referer); + + declarer = mi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); + + /* checks for INVOKESPECIAL: */ + /* for and methods of the current class we don't need any */ + /* special checks. Otherwise we must verify that the called method */ + /* belongs to a super class of the current class */ + + if ((referer != declarer) && (mi->name != utf_init)) { + /* check that declarer is a super class of the current class */ + + if (!class_issubclass(referer,declarer)) { + exceptions_throw_verifyerror(refmethod, + "INVOKESPECIAL calling non-super class method"); + return NULL; + } + + /* if the referer has ACC_SUPER set, we must do the special */ + /* lookup starting with the direct super class of referer */ + + if ((referer->flags & ACC_SUPER) != 0) { + mi = class_resolvemethod(referer->super.cls, + mi->name, + mi->descriptor); + + if (mi == NULL) { +#if defined(ENABLE_JAVASE) + /* the spec calls for an AbstractMethodError in this case */ + exceptions_throw_abstractmethoderror(); +#else + exceptions_throw_virtualmachineerror(); +#endif + return NULL; + } + } + } + + /* everything ok */ + return mi; +} + +/* resolve_method_verifier_checks ****************************************** + + Do the verifier checks necessary after a method has been resolved. + + IN: + refmethod........the method containing the reference + methodref........the method reference + mi...............the methodinfo of the resolved method + invokestatic.....true if the method is invoked by INVOKESTATIC + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, + constant_FMIref *methodref, + methodinfo *mi, + bool invokestatic) +{ + classinfo *declarer; + classinfo *referer; + + assert(refmethod); + assert(methodref); + assert(mi); + +#ifdef RESOLVE_VERBOSE + printf("resolve_method_verifier_checks\n"); + printf(" flags: %02x\n",mi->flags); +#endif + + /* get the classinfos and the method descriptor */ + + referer = refmethod->class; + assert(referer); + + declarer = mi->class; + assert(declarer); + + /* check static */ + + if (((mi->flags & ACC_STATIC) != 0) != (invokestatic != false)) { + /* a static method is accessed via an instance, or vice versa */ + exceptions_throw_incompatibleclasschangeerror(declarer, + (mi->flags & ACC_STATIC) + ? "static method called via instance" + : "instance method called without instance"); + + return resolveFailed; + } + + /* check access rights */ + + if (!access_is_accessible_member(referer,declarer,mi->flags)) { + int msglen; + char *message; + + /* XXX clean this up. this should be in exceptions.c */ + msglen = + utf_bytes(declarer->name) + + utf_bytes(mi->name) + + utf_bytes(mi->descriptor) + + utf_bytes(referer->name) + + 100; + + message = MNEW(char, msglen); + + strcpy(message, "method is not accessible ("); + utf_cat_classname(message, declarer->name); + strcat(message, "."); + utf_cat(message, mi->name); + utf_cat(message, mi->descriptor); + strcat(message, " from "); + utf_cat_classname(message, referer->name); + strcat(message, ")"); + + exceptions_throw_illegalaccessexception(message); + + MFREE(message, char, msglen); + + return resolveFailed; /* exception */ + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_method_instance_type_checks ***************************************** + + Check the instance type of a method invocation. + + IN: + refmethod........the method containing the reference + mi...............the methodinfo of the resolved method + instanceti.......typeinfo of the instance slot + invokespecial....true if the method is invoked by INVOKESPECIAL + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_method_instance_type_checks(methodinfo *refmethod, + methodinfo *mi, + typeinfo *instanceti, + bool invokespecial) +{ + typeinfo tinfo; + typeinfo *tip; + resolve_result_t result; + + if (invokespecial && TYPEINFO_IS_NEWOBJECT(*instanceti)) + { /* XXX clean up */ + instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); + classref_or_classinfo initclass = (ins) ? ins[-1].sx.val.c + : CLASSREF_OR_CLASSINFO(refmethod->class); + tip = &tinfo; + if (!typeinfo_init_class(tip, initclass)) + return false; + } + else { + tip = instanceti; + } + + result = resolve_lazy_subtype_checks(refmethod, + tip, + CLASSREF_OR_CLASSINFO(mi->class), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + + /* check protected access */ + + /* XXX use other `declarer` than mi->class? */ + if (((mi->flags & ACC_PROTECTED) != 0) + && !SAME_PACKAGE(mi->class, refmethod->class)) + { + result = resolve_lazy_subtype_checks(refmethod, + tip, + CLASSREF_OR_CLASSINFO(refmethod->class), + resolveIllegalAccessError); + if (result != resolveSucceeded) + return result; + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_method_param_type_checks ******************************************** + + Check non-instance parameter types of a method invocation. + + IN: + jd...............jitdata of the method doing the call + refmethod........the method containing the reference + iptr.............the invoke instruction + mi...............the methodinfo of the resolved method + invokestatic.....true if the method is invoked by INVOKESTATIC + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_method_param_type_checks(jitdata *jd, + methodinfo *refmethod, + instruction *iptr, + methodinfo *mi, + bool invokestatic) +{ + varinfo *param; + resolve_result_t result; + methoddesc *md; + typedesc *paramtypes; + s4 type; + s4 instancecount; + s4 i; + + assert(jd); + + instancecount = (invokestatic) ? 0 : 1; + + /* check subtype constraints for TYPE_ADR parameters */ + + md = mi->parseddesc; + paramtypes = md->paramtypes; + + for (i = md->paramcount-1-instancecount; i>=0; --i) { + param = VAR(iptr->sx.s23.s2.args[i+instancecount]); + type = md->paramtypes[i+instancecount].type; + + assert(param); + assert(type == param->type); + + if (type == TYPE_ADR) { + result = resolve_lazy_subtype_checks(refmethod, + &(param->typeinfo), + CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + } + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_method_param_type_checks_stackbased ********************************* + + Check non-instance parameter types of a method invocation. + + IN: + refmethod........the method containing the reference + mi...............the methodinfo of the resolved method + invokestatic.....true if the method is invoked by INVOKESTATIC + stack............TOS before the INVOKE instruction + + RETURN VALUE: + resolveSucceeded....everything ok + resolveDeferred.....tests could not be done, have been deferred + resolveFailed.......exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_method_param_type_checks_stackbased( + methodinfo *refmethod, + methodinfo *mi, + bool invokestatic, + typedescriptor *stack) +{ + typedescriptor *param; + resolve_result_t result; + methoddesc *md; + typedesc *paramtypes; + s4 type; + s4 instancecount; + s4 i; + + instancecount = (invokestatic) ? 0 : 1; + + /* check subtype constraints for TYPE_ADR parameters */ + + md = mi->parseddesc; + paramtypes = md->paramtypes; + + param = stack - (md->paramslots - 1 - instancecount); + + for (i = instancecount; i < md->paramcount; ++i) { + type = md->paramtypes[i].type; + + assert(type == param->type); + + if (type == TYPE_ADR) { + result = resolve_lazy_subtype_checks(refmethod, + &(param->typeinfo), + CLASSREF_OR_CLASSINFO(paramtypes[i].classref), + resolveLinkageError); + if (result != resolveSucceeded) + return result; + } + + param += (IS_2_WORD_TYPE(type)) ? 2 : 1; + } + + /* everything ok */ + + return resolveSucceeded; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_method_loading_constraints ****************************************** + + Impose loading constraints on the parameters and return type of the + given method. + + IN: + referer..........the class refering to the method + mi...............the method + + RETURN VALUE: + true................everything ok + false...............an exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +bool resolve_method_loading_constraints(classinfo *referer, + methodinfo *mi) +{ + methoddesc *md; + typedesc *paramtypes; + utf *name; + s4 i; + s4 instancecount; + + /* impose loading constraints on parameters (including instance) */ + + md = mi->parseddesc; + paramtypes = md->paramtypes; + instancecount = (mi->flags & ACC_STATIC) / ACC_STATIC; + + for (i = 0; i < md->paramcount; i++) { + if (i < instancecount || paramtypes[i].type == TYPE_ADR) { + if (i < instancecount) { + /* The type of the 'this' pointer is the class containing */ + /* the method definition. Since container is the same as, */ + /* or a subclass of declarer, we also constrain declarer */ + /* by transitivity of loading constraints. */ + name = mi->class->name; + } + else { + name = paramtypes[i].classref->name; + } + + /* The caller (referer) and the callee (container) must agree */ + /* on the types of the parameters. */ + if (!classcache_add_constraint(referer->classloader, + mi->class->classloader, name)) + return false; /* exception */ + } + } + + /* impose loading constraint onto return type */ + + if (md->returntype.type == TYPE_ADR) { + /* The caller (referer) and the callee (container) must agree */ + /* on the return type. */ + if (!classcache_add_constraint(referer->classloader, + mi->class->classloader, + md->returntype.classref->name)) + return false; /* exception */ + } + + /* everything ok */ + + return true; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_method_lazy ********************************************************* + + Resolve an unresolved method reference lazily + + NOTE: This function does NOT do any verification checks. In case of a + successful resolution, you must call resolve_method_verifier_checks + in order to perform the necessary checks! + + IN: + refmethod........the referer method + methodref........the method reference + invokespecial....true if this is an INVOKESPECIAL instruction + + RETURN VALUE: + resolveSucceeded.....the reference has been resolved + resolveDeferred......the resolving could not be performed lazily + resolveFailed........resolving failed, an exception has been thrown. + +*******************************************************************************/ + +resolve_result_t resolve_method_lazy(methodinfo *refmethod, + constant_FMIref *methodref, + bool invokespecial) +{ + classinfo *referer; + classinfo *container; + methodinfo *mi; + + assert(refmethod); + +#ifdef RESOLVE_VERBOSE + printf("resolve_method_lazy\n"); +#endif + + /* the class containing the reference */ + + referer = refmethod->class; + assert(referer); + + /* check if the method itself is already resolved */ + + if (IS_FMIREF_RESOLVED(methodref)) + return resolveSucceeded; + + /* first we must resolve the class containg the method */ + + if (!resolve_class_from_name(referer, refmethod, + methodref->p.classref->name, resolveLazy, true, true, &container)) + { + /* the class reference could not be resolved */ + return resolveFailed; /* exception */ + } + if (!container) + return resolveDeferred; /* be lazy */ + + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the method in `container` + * or one of its superclasses */ + + if (container->flags & ACC_INTERFACE) { + mi = class_resolveinterfacemethod(container, + methodref->name, + methodref->descriptor, + referer, true); + + } else { + mi = class_resolveclassmethod(container, + methodref->name, + methodref->descriptor, + referer, true); + } + + if (!mi) { + /* The method does not exist. But since we were called lazily, */ + /* this error must not be reported now. (It will be reported */ + /* if eager resolving of this method is ever tried.) */ + + exceptions_clear_exception(); + return resolveDeferred; /* be lazy */ + } + + if (invokespecial) { + mi = resolve_method_invokespecial_lookup(refmethod, mi); + if (!mi) + return resolveFailed; /* exception */ + } + + /* have the method params already been parsed? no, do it. */ + + if (!mi->parseddesc->params) + if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) + return resolveFailed; + + /* cache the result of the resolution */ + + methodref->p.method = mi; + + /* succeed */ + + return resolveSucceeded; +} + +/* resolve_method ************************************************************** + + Resolve an unresolved method reference + + IN: + ref..............struct containing the reference + mode.............mode of resolution: + resolveLazy...only resolve if it does not + require loading classes + resolveEager..load classes if necessary + + OUT: + *result..........set to the result of resolution, or to NULL if + the reference has not been resolved + In the case of an exception, *result is + guaranteed to be set to NULL. + + RETURN VALUE: + true.............everything ok + (*result may still be NULL for resolveLazy) + false............an exception has been thrown + +*******************************************************************************/ + +bool resolve_method(unresolved_method *ref, resolve_mode_t mode, methodinfo **result) +{ + classinfo *referer; + classinfo *container; + classinfo *declarer; + methodinfo *mi; + typedesc *paramtypes; + int instancecount; + int i; + resolve_result_t checkresult; + + assert(ref); + assert(result); + assert(mode == resolveLazy || mode == resolveEager); + +#ifdef RESOLVE_VERBOSE + unresolved_method_debug_dump(ref,stdout); +#endif + + *result = NULL; + + /* the class containing the reference */ + + referer = ref->referermethod->class; + assert(referer); + + /* check if the method itself is already resolved */ + + if (IS_FMIREF_RESOLVED(ref->methodref)) { + mi = ref->methodref->p.method; + container = mi->class; + goto resolved_the_method; + } + + /* first we must resolve the class containing the method */ + + if (!resolve_class_from_name(referer,ref->referermethod, + ref->methodref->p.classref->name,mode,true,true,&container)) + { + /* the class reference could not be resolved */ + return false; /* exception */ + } + if (!container) + return true; /* be lazy */ + + assert(container); + assert(container->state & CLASS_LINKED); + + /* now we must find the declaration of the method in `container` + * or one of its superclasses */ + + if (container->flags & ACC_INTERFACE) { + mi = class_resolveinterfacemethod(container, + ref->methodref->name, + ref->methodref->descriptor, + referer, true); + + } else { + mi = class_resolveclassmethod(container, + ref->methodref->name, + ref->methodref->descriptor, + referer, true); + } + + if (!mi) { + if (mode == resolveLazy) { + /* The method does not exist. But since we were called lazily, */ + /* this error must not be reported now. (It will be reported */ + /* if eager resolving of this method is ever tried.) */ + + exceptions_clear_exception(); + return true; /* be lazy */ + } + + return false; /* exception */ /* XXX set exceptionptr? */ + } + + /* { the method reference has been resolved } */ + + if (ref->flags & RESOLVE_SPECIAL) { + mi = resolve_method_invokespecial_lookup(ref->referermethod,mi); + if (!mi) + return false; /* exception */ + } + + /* have the method params already been parsed? no, do it. */ + + if (!mi->parseddesc->params) + if (!descriptor_params_from_paramtypes(mi->parseddesc, mi->flags)) + return false; + + /* cache the resolution */ + + ref->methodref->p.method = mi; + +resolved_the_method: + +#ifdef ENABLE_VERIFIER + if (opt_verify) { + + checkresult = resolve_method_verifier_checks( + ref->referermethod, + ref->methodref, + mi, + (ref->flags & RESOLVE_STATIC)); + + if (checkresult != resolveSucceeded) + return (bool) checkresult; + + /* impose loading constraints on params and return type */ + + if (!resolve_method_loading_constraints(referer, mi)) + return false; + + declarer = mi->class; + assert(declarer); + assert(referer->state & CLASS_LINKED); + + /* for non-static methods we have to check the constraints on the */ + /* instance type */ + + if (!(ref->flags & RESOLVE_STATIC)) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(container), + mode, + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + instancecount = 1; + } + else { + instancecount = 0; + } + + /* check subtype constraints for TYPE_ADR parameters */ + + assert(mi->parseddesc->paramcount == ref->methodref->parseddesc.md->paramcount); + paramtypes = mi->parseddesc->paramtypes; + + for (i = 0; i < mi->parseddesc->paramcount-instancecount; i++) { + if (paramtypes[i+instancecount].type == TYPE_ADR) { + if (ref->paramconstraints) { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + ref->paramconstraints + i, + CLASSREF_OR_CLASSINFO(paramtypes[i+instancecount].classref), + mode, + resolveLinkageError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + } + } + + /* check protected access */ + + if (((mi->flags & ACC_PROTECTED) != 0) && !SAME_PACKAGE(declarer,referer)) + { + checkresult = resolve_and_check_subtype_set(ref->referermethod, + &(ref->instancetypes), + CLASSREF_OR_CLASSINFO(referer), + mode, + resolveIllegalAccessError); + if (checkresult != resolveSucceeded) + return (bool) checkresult; + } + } +#endif /* ENABLE_VERIFIER */ + + /* succeed */ + *result = mi; + return true; +} + +/* resolve_method_eager ******************************************************** + + Resolve an unresolved method reference eagerly. + + IN: + ref..............struct containing the reference + + RETURN VALUE: + methodinfo * to the method, or + NULL if an exception has been thrown + +*******************************************************************************/ + +methodinfo * resolve_method_eager(unresolved_method *ref) +{ + methodinfo *mi; + + if (!resolve_method(ref,resolveEager,&mi)) + return NULL; + + return mi; +} + +/******************************************************************************/ +/* CREATING THE DATA STRUCTURES */ +/******************************************************************************/ + +#ifdef ENABLE_VERIFIER +static bool unresolved_subtype_set_from_typeinfo(classinfo *referer, + methodinfo *refmethod, + unresolved_subtype_set *stset, + typeinfo *tinfo, + utf *declaredclassname) +{ + int count; + int i; + + assert(stset); + assert(tinfo); + +#ifdef RESOLVE_VERBOSE + printf("unresolved_subtype_set_from_typeinfo\n"); +#ifdef TYPEINFO_DEBUG + typeinfo_print(stdout,tinfo,4); +#endif + printf(" declared classname:");utf_fprint_printable_ascii(stdout,declaredclassname); + printf("\n"); +#endif + + if (TYPEINFO_IS_PRIMITIVE(*tinfo)) { + exceptions_throw_verifyerror(refmethod, + "Invalid use of returnAddress"); + return false; + } + + if (TYPEINFO_IS_NEWOBJECT(*tinfo)) { + exceptions_throw_verifyerror(refmethod, + "Invalid use of uninitialized object"); + return false; + } + + /* the nulltype is always assignable */ + if (TYPEINFO_IS_NULLTYPE(*tinfo)) + goto empty_set; + + /* every type is assignable to (BOOTSTRAP)java.lang.Object */ + if (declaredclassname == utf_java_lang_Object + && referer->classloader == NULL) /* XXX do loading constraints make the second check obsolete? */ + { + goto empty_set; + } + + if (tinfo->merged) { + count = tinfo->merged->count; + stset->subtyperefs = MNEW(classref_or_classinfo,count + 1); + for (i=0; imerged->list[i]; + if (tinfo->dimension > 0) { + /* a merge of array types */ + /* the merged list contains the possible _element_ types, */ + /* so we have to create array types with these elements. */ + if (IS_CLASSREF(c)) { + c.ref = class_get_classref_multiarray_of(tinfo->dimension,c.ref); + } + else { + c.cls = class_multiarray_of(tinfo->dimension,c.cls,false); + } + } + stset->subtyperefs[i] = c; + } + stset->subtyperefs[count].any = NULL; /* terminate */ + } + else { + if ((IS_CLASSREF(tinfo->typeclass) + ? tinfo->typeclass.ref->name + : tinfo->typeclass.cls->name) == declaredclassname) + { + /* the class names are the same */ + /* equality is guaranteed by the loading constraints */ + goto empty_set; + } + else { + stset->subtyperefs = MNEW(classref_or_classinfo,1 + 1); + stset->subtyperefs[0] = tinfo->typeclass; + stset->subtyperefs[1].any = NULL; /* terminate */ + } + } + + return true; + +empty_set: + UNRESOLVED_SUBTYPE_SET_EMTPY(*stset); + return true; +} +#endif /* ENABLE_VERIFIER */ + +/* create_unresolved_class ***************************************************** + + Create an unresolved_class struct for the given class reference + + IN: + refmethod........the method triggering the resolution (if any) + classref.........the class reference + valuetype........value type to check against the resolved class + may be NULL, if no typeinfo is available + + RETURN VALUE: + a pointer to a new unresolved_class struct, or + NULL if an exception has been thrown + +*******************************************************************************/ + +#ifdef ENABLE_VERIFIER +unresolved_class * create_unresolved_class(methodinfo *refmethod, + constant_classref *classref, + typeinfo *valuetype) +{ + unresolved_class *ref; + +#ifdef RESOLVE_VERBOSE + printf("create_unresolved_class\n"); + printf(" referer: ");utf_fprint_printable_ascii(stdout,classref->referer->name);fputc('\n',stdout); + if (refmethod) { + printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); + printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); + } + printf(" name : ");utf_fprint_printable_ascii(stdout,classref->name);fputc('\n',stdout); +#endif + + ref = NEW(unresolved_class); + ref->classref = classref; + ref->referermethod = refmethod; + + if (valuetype) { + if (!unresolved_subtype_set_from_typeinfo(classref->referer,refmethod, + &(ref->subtypeconstraints),valuetype,classref->name)) + return NULL; + } + else { + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->subtypeconstraints); + } + + return ref; +} +#endif /* ENABLE_VERIFIER */ + +/* resolve_create_unresolved_field ********************************************* + + Create an unresolved_field struct for the given field access instruction + + IN: + referer..........the class containing the reference + refmethod........the method triggering the resolution (if any) + iptr.............the {GET,PUT}{FIELD,STATIC}{,CONST} instruction + + RETURN VALUE: + a pointer to a new unresolved_field struct, or + NULL if an exception has been thrown + +*******************************************************************************/ + +unresolved_field * resolve_create_unresolved_field(classinfo *referer, + methodinfo *refmethod, + instruction *iptr) +{ + unresolved_field *ref; + constant_FMIref *fieldref = NULL; + +#ifdef RESOLVE_VERBOSE + printf("create_unresolved_field\n"); + printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); + printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); + printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); +#endif + + ref = NEW(unresolved_field); + ref->flags = 0; + ref->referermethod = refmethod; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); + + switch (iptr->opc) { + case ICMD_PUTFIELD: + ref->flags |= RESOLVE_PUTFIELD; + break; + + case ICMD_PUTFIELDCONST: + ref->flags |= RESOLVE_PUTFIELD; + break; + + case ICMD_PUTSTATIC: + ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; + break; + + case ICMD_PUTSTATICCONST: + ref->flags |= RESOLVE_PUTFIELD | RESOLVE_STATIC; + break; + + case ICMD_GETFIELD: + break; + + case ICMD_GETSTATIC: + ref->flags |= RESOLVE_STATIC; + break; + +#if !defined(NDEBUG) + default: + assert(false); +#endif + } + + fieldref = iptr->sx.s23.s3.fmiref; + + assert(fieldref); + +#ifdef RESOLVE_VERBOSE +/* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout);*/ + printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout); + printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout); + printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd); + fputc('\n',stdout); +#endif + + ref->fieldref = fieldref; + + return ref; +} + +/* resolve_constrain_unresolved_field ****************************************** + + Record subtype constraints for a field access. + + IN: + ref..............the unresolved_field structure of the access + referer..........the class containing the reference + refmethod........the method triggering the resolution (if any) + instanceti.......instance typeinfo, if available + valueti..........value typeinfo, if available + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +bool resolve_constrain_unresolved_field(unresolved_field *ref, + classinfo *referer, + methodinfo *refmethod, + typeinfo *instanceti, + typeinfo *valueti) +{ + constant_FMIref *fieldref; + int type; + typeinfo tinfo; + typedesc *fd; + + assert(ref); + + fieldref = ref->fieldref; + assert(fieldref); + +#ifdef RESOLVE_VERBOSE + printf("constrain_unresolved_field\n"); + printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); + printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); + printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); +/* printf(" class : ");utf_fprint_printable_ascii(stdout,fieldref->p.classref->name);fputc('\n',stdout); */ + printf(" name : ");utf_fprint_printable_ascii(stdout,fieldref->name);fputc('\n',stdout); + printf(" desc : ");utf_fprint_printable_ascii(stdout,fieldref->descriptor);fputc('\n',stdout); + printf(" type : ");descriptor_debug_print_typedesc(stdout,fieldref->parseddesc.fd); + fputc('\n',stdout); +#endif + + assert(instanceti || ((ref->flags & RESOLVE_STATIC) != 0)); + fd = fieldref->parseddesc.fd; + assert(fd); + + /* record subtype constraints for the instance type, if any */ + if (instanceti) { + typeinfo *insttip; + + /* The instanceslot must contain a reference to a non-array type */ + if (!TYPEINFO_IS_REFERENCE(*instanceti)) { + exceptions_throw_verifyerror(refmethod, + "illegal instruction: field access on non-reference"); + return false; + } + if (TYPEINFO_IS_ARRAY(*instanceti)) { + exceptions_throw_verifyerror(refmethod, + "illegal instruction: field access on array"); + return false; + } + + if (((ref->flags & RESOLVE_PUTFIELD) != 0) && + TYPEINFO_IS_NEWOBJECT(*instanceti)) + { + /* The instruction writes a field in an uninitialized object. */ + /* This is only allowed when a field of an uninitialized 'this' object is */ + /* written inside an initialization method */ + + classinfo *initclass; + instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); + + if (ins != NULL) { + exceptions_throw_verifyerror(refmethod, + "accessing field of uninitialized object"); + return false; + } + /* XXX check that class of field == refmethod->class */ + initclass = refmethod->class; /* XXX classrefs */ + assert(initclass->state & CLASS_LOADED); + assert(initclass->state & CLASS_LINKED); + + typeinfo_init_classinfo(&tinfo, initclass); + insttip = &tinfo; + } + else { + insttip = instanceti; + } + if (!unresolved_subtype_set_from_typeinfo(referer, refmethod, + &(ref->instancetypes), insttip, + FIELDREF_CLASSNAME(fieldref))) + return false; + } + else { + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); + } + + /* record subtype constraints for the value type, if any */ + type = fd->type; + if (type == TYPE_ADR && ((ref->flags & RESOLVE_PUTFIELD) != 0)) { + assert(valueti); + if (!unresolved_subtype_set_from_typeinfo(referer, refmethod, + &(ref->valueconstraints), valueti, + fieldref->parseddesc.fd->classref->name)) + return false; + } + else { + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); + } + + return true; +} +#endif /* ENABLE_VERIFIER */ + +/* resolve_create_unresolved_method ******************************************** + + Create an unresolved_method struct for the given method invocation + + IN: + referer..........the class containing the reference + refmethod........the method triggering the resolution (if any) + iptr.............the INVOKE* instruction + + RETURN VALUE: + a pointer to a new unresolved_method struct, or + NULL if an exception has been thrown + +*******************************************************************************/ + +unresolved_method * resolve_create_unresolved_method(classinfo *referer, + methodinfo *refmethod, + constant_FMIref *methodref, + bool invokestatic, + bool invokespecial) +{ + unresolved_method *ref; + + assert(methodref); + +#ifdef RESOLVE_VERBOSE + printf("create_unresolved_method\n"); + printf(" referer: ");utf_fprint_printable_ascii(stdout,referer->name);fputc('\n',stdout); + printf(" rmethod: ");utf_fprint_printable_ascii(stdout,refmethod->name);fputc('\n',stdout); + printf(" rmdesc : ");utf_fprint_printable_ascii(stdout,refmethod->descriptor);fputc('\n',stdout); + printf(" name : ");utf_fprint_printable_ascii(stdout,methodref->name);fputc('\n',stdout); + printf(" desc : ");utf_fprint_printable_ascii(stdout,methodref->descriptor);fputc('\n',stdout); +#endif + + /* allocate params if necessary */ + if (!methodref->parseddesc.md->params) + if (!descriptor_params_from_paramtypes(methodref->parseddesc.md, + (invokestatic) ? ACC_STATIC : ACC_NONE)) + return NULL; + + /* create the data structure */ + ref = NEW(unresolved_method); + ref->flags = ((invokestatic) ? RESOLVE_STATIC : 0) + | ((invokespecial) ? RESOLVE_SPECIAL : 0); + ref->referermethod = refmethod; + ref->methodref = methodref; + ref->paramconstraints = NULL; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); + + return ref; +} + + +/* resolve_constrain_unresolved_method_instance ******************************** + + Record subtype constraints for the instance argument of a method call. + + IN: + ref..............the unresolved_method structure of the call + referer..........the class containing the reference + refmethod........the method triggering the resolution (if any) + iptr.............the INVOKE* instruction + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +bool resolve_constrain_unresolved_method_instance(unresolved_method *ref, + methodinfo *refmethod, + typeinfo *instanceti, + bool invokespecial) +{ + constant_FMIref *methodref; + constant_classref *instanceref; + typeinfo tinfo; + typeinfo *tip; + + assert(ref); + methodref = ref->methodref; + assert(methodref); + + /* XXX clean this up */ + instanceref = IS_FMIREF_RESOLVED(methodref) + ? class_get_self_classref(methodref->p.method->class) + : methodref->p.classref; + +#ifdef RESOLVE_VERBOSE + printf("resolve_constrain_unresolved_method_instance\n"); + printf(" rmethod: "); method_println(refmethod); + printf(" mref : "); method_methodref_println(methodref); +#endif + + /* record subtype constraints for the instance type, if any */ + + if (invokespecial && TYPEINFO_IS_NEWOBJECT(*instanceti)) + { /* XXX clean up */ + instruction *ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*instanceti); + classref_or_classinfo initclass = (ins) ? ins[-1].sx.val.c + : CLASSREF_OR_CLASSINFO(refmethod->class); + tip = &tinfo; + if (!typeinfo_init_class(tip, initclass)) + return false; + } + else { + tip = instanceti; + } + + if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, + &(ref->instancetypes),tip,instanceref->name)) + return false; + + return true; +} +#endif /* defined(ENABLE_VERIFIER) */ + + +/* resolve_constrain_unresolved_method_params ********************************* + + Record subtype constraints for the non-instance arguments of a method call. + + IN: + jd...............current jitdata (for looking up variables) + ref..............the unresolved_method structure of the call + refmethod........the method triggering the resolution (if any) + iptr.............the INVOKE* instruction + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +bool resolve_constrain_unresolved_method_params(jitdata *jd, + unresolved_method *ref, + methodinfo *refmethod, + instruction *iptr) +{ + constant_FMIref *methodref; + varinfo *param; + methoddesc *md; + int i,j; + int type; + int instancecount; + + assert(ref); + methodref = ref->methodref; + assert(methodref); + md = methodref->parseddesc.md; + assert(md); + assert(md->params != NULL); + +#ifdef RESOLVE_VERBOSE + printf("resolve_constrain_unresolved_method_params\n"); + printf(" rmethod: "); method_println(refmethod); + printf(" mref : "); method_methodref_println(methodref); +#endif + + instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1; + + /* record subtype constraints for the parameter types, if any */ + + for (i=md->paramcount-1-instancecount; i>=0; --i) { + param = VAR(iptr->sx.s23.s2.args[i+instancecount]); + type = md->paramtypes[i+instancecount].type; + + assert(param); + assert(type == param->type); + + if (type == TYPE_ADR) { + if (!ref->paramconstraints) { + ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount); + for (j=md->paramcount-1-instancecount; j>i; --j) + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]); + } + assert(ref->paramconstraints); + if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, + ref->paramconstraints + i,&(param->typeinfo), + md->paramtypes[i+instancecount].classref->name)) + return false; + } + else { + if (ref->paramconstraints) + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]); + } + } + + return true; +} +#endif /* ENABLE_VERIFIER */ + + +/* resolve_constrain_unresolved_method_params_stackbased *********************** + + Record subtype constraints for the non-instance arguments of a method call. + + IN: + ref..............the unresolved_method structure of the call + refmethod........the method triggering the resolution (if any) + stack............TOS before the INVOKE instruction + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + +*******************************************************************************/ + +#if defined(ENABLE_VERIFIER) +bool resolve_constrain_unresolved_method_params_stackbased( + unresolved_method *ref, + methodinfo *refmethod, + typedescriptor *stack) +{ + constant_FMIref *methodref; + typedescriptor *param; + methoddesc *md; + int i,j; + int type; + int instancecount; + + assert(ref); + methodref = ref->methodref; + assert(methodref); + md = methodref->parseddesc.md; + assert(md); + assert(md->params != NULL); + +#ifdef RESOLVE_VERBOSE + printf("resolve_constrain_unresolved_method_params_stackbased\n"); + printf(" rmethod: "); method_println(refmethod); + printf(" mref : "); method_methodref_println(methodref); +#endif + + instancecount = (ref->flags & RESOLVE_STATIC) ? 0 : 1; + + /* record subtype constraints for the parameter types, if any */ + + param = stack - (md->paramslots - 1 - instancecount); + + for (i = instancecount; i < md->paramcount; ++i) { + type = md->paramtypes[i].type; + + assert(type == param->type); + + if (type == TYPE_ADR) { + if (!ref->paramconstraints) { + ref->paramconstraints = MNEW(unresolved_subtype_set,md->paramcount); + for (j = 0; j < i - instancecount; ++j) + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[j]); + } + assert(ref->paramconstraints); + if (!unresolved_subtype_set_from_typeinfo(refmethod->class, refmethod, + ref->paramconstraints + i - instancecount,&(param->typeinfo), + md->paramtypes[i].classref->name)) + return false; + } + else { + if (ref->paramconstraints) + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->paramconstraints[i]); + } + + param += (IS_2_WORD_TYPE(type)) ? 2 : 1; + } + + return true; +} +#endif /* ENABLE_VERIFIER */ + + +/******************************************************************************/ +/* FREEING MEMORY */ +/******************************************************************************/ + +#ifdef ENABLE_VERIFIER +inline static void unresolved_subtype_set_free_list(classref_or_classinfo *list) +{ + if (list) { + classref_or_classinfo *p = list; + + /* this is silly. we *only* need to count the elements for MFREE */ + while ((p++)->any) + ; + MFREE(list,classref_or_classinfo,(p - list)); + } +} +#endif /* ENABLE_VERIFIER */ + +/* unresolved_class_free ******************************************************* + + Free the memory used by an unresolved_class + + IN: + ref..............the unresolved_class + +*******************************************************************************/ + +void unresolved_class_free(unresolved_class *ref) +{ + assert(ref); + +#ifdef ENABLE_VERIFIER + unresolved_subtype_set_free_list(ref->subtypeconstraints.subtyperefs); +#endif + FREE(ref,unresolved_class); +} + +/* unresolved_field_free ******************************************************* + + Free the memory used by an unresolved_field + + IN: + ref..............the unresolved_field + +*******************************************************************************/ + +void unresolved_field_free(unresolved_field *ref) +{ + assert(ref); + +#ifdef ENABLE_VERIFIER + unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs); + unresolved_subtype_set_free_list(ref->valueconstraints.subtyperefs); +#endif + FREE(ref,unresolved_field); +} + +/* unresolved_method_free ****************************************************** + + Free the memory used by an unresolved_method + + IN: + ref..............the unresolved_method + +*******************************************************************************/ + +void unresolved_method_free(unresolved_method *ref) +{ + assert(ref); + +#ifdef ENABLE_VERIFIER + unresolved_subtype_set_free_list(ref->instancetypes.subtyperefs); + if (ref->paramconstraints) { + int i; + int count = ref->methodref->parseddesc.md->paramcount; + + for (i=0; iparamconstraints[i].subtyperefs); + MFREE(ref->paramconstraints,unresolved_subtype_set,count); + } +#endif + FREE(ref,unresolved_method); +} + +/******************************************************************************/ +/* DEBUG DUMPS */ +/******************************************************************************/ + +#if !defined(NDEBUG) + +/* unresolved_subtype_set_debug_dump ******************************************* + + Print debug info for unresolved_subtype_set to stream + + IN: + stset............the unresolved_subtype_set + file.............the stream + +*******************************************************************************/ + +void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file) +{ + classref_or_classinfo *p; + + if (SUBTYPESET_IS_EMPTY(*stset)) { + fprintf(file," (empty)\n"); + } + else { + p = stset->subtyperefs; + for (;p->any; ++p) { + if (IS_CLASSREF(*p)) { + fprintf(file," ref: "); + utf_fprint_printable_ascii(file,p->ref->name); + } + else { + fprintf(file," cls: "); + utf_fprint_printable_ascii(file,p->cls->name); + } + fputc('\n',file); + } + } +} + +/* unresolved_class_debug_dump ************************************************* + + Print debug info for unresolved_class to stream + + IN: + ref..............the unresolved_class + file.............the stream + +*******************************************************************************/ + +void unresolved_class_debug_dump(unresolved_class *ref,FILE *file) +{ + fprintf(file,"unresolved_class(%p):\n",(void *)ref); + if (ref) { + fprintf(file," referer : "); + utf_fprint_printable_ascii(file,ref->classref->referer->name); fputc('\n',file); + fprintf(file," refmethod : "); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); + fprintf(file," refmethodd: "); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); + fprintf(file," classname : "); + utf_fprint_printable_ascii(file,ref->classref->name); fputc('\n',file); + fprintf(file," subtypeconstraints:\n"); + unresolved_subtype_set_debug_dump(&(ref->subtypeconstraints),file); + } +} + +/* unresolved_field_debug_dump ************************************************* + + Print debug info for unresolved_field to stream + + IN: + ref..............the unresolved_field + file.............the stream + +*******************************************************************************/ + +void unresolved_field_debug_dump(unresolved_field *ref,FILE *file) +{ + fprintf(file,"unresolved_field(%p):\n",(void *)ref); + if (ref) { + fprintf(file," referer : "); + utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); + fprintf(file," refmethod : "); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); + fprintf(file," refmethodd: "); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); + fprintf(file," classname : "); + utf_fprint_printable_ascii(file,FIELDREF_CLASSNAME(ref->fieldref)); fputc('\n',file); + fprintf(file," name : "); + utf_fprint_printable_ascii(file,ref->fieldref->name); fputc('\n',file); + fprintf(file," descriptor: "); + utf_fprint_printable_ascii(file,ref->fieldref->descriptor); fputc('\n',file); + fprintf(file," parseddesc: "); + descriptor_debug_print_typedesc(file,ref->fieldref->parseddesc.fd); fputc('\n',file); + fprintf(file," flags : %04x\n",ref->flags); + fprintf(file," instancetypes:\n"); + unresolved_subtype_set_debug_dump(&(ref->instancetypes),file); + fprintf(file," valueconstraints:\n"); + unresolved_subtype_set_debug_dump(&(ref->valueconstraints),file); + } +} + +/* unresolved_method_debug_dump ************************************************ + + Print debug info for unresolved_method to stream + + IN: + ref..............the unresolved_method + file.............the stream + +*******************************************************************************/ + +void unresolved_method_debug_dump(unresolved_method *ref,FILE *file) +{ + int i; + + fprintf(file,"unresolved_method(%p):\n",(void *)ref); + if (ref) { + fprintf(file," referer : "); + utf_fprint_printable_ascii(file,ref->referermethod->class->name); fputc('\n',file); + fprintf(file," refmethod : "); + utf_fprint_printable_ascii(file,ref->referermethod->name); fputc('\n',file); + fprintf(file," refmethodd: "); + utf_fprint_printable_ascii(file,ref->referermethod->descriptor); fputc('\n',file); + fprintf(file," classname : "); + utf_fprint_printable_ascii(file,METHODREF_CLASSNAME(ref->methodref)); fputc('\n',file); + fprintf(file," name : "); + utf_fprint_printable_ascii(file,ref->methodref->name); fputc('\n',file); + fprintf(file," descriptor: "); + utf_fprint_printable_ascii(file,ref->methodref->descriptor); fputc('\n',file); + fprintf(file," parseddesc: "); + descriptor_debug_print_methoddesc(file,ref->methodref->parseddesc.md); fputc('\n',file); + fprintf(file," flags : %04x\n",ref->flags); + fprintf(file," instancetypes:\n"); + unresolved_subtype_set_debug_dump(&(ref->instancetypes),file); + fprintf(file," paramconstraints:\n"); + if (ref->paramconstraints) { + for (i=0; imethodref->parseddesc.md->paramcount; ++i) { + fprintf(file," param %d:\n",i); + unresolved_subtype_set_debug_dump(ref->paramconstraints + i,file); + } + } + else { + fprintf(file," (empty)\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: + */ diff --git a/src/vmcore/resolve.h b/src/vmcore/resolve.h new file mode 100644 index 000000000..2f49a2efc --- /dev/null +++ b/src/vmcore/resolve.h @@ -0,0 +1,273 @@ +/* src/vmcore/resolve.h - resolving classes/interfaces/fields/methods + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: resolve.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _RESOLVE_H +#define _RESOLVE_H + +/* forward declarations *******************************************************/ + +typedef struct unresolved_class unresolved_class; +typedef struct unresolved_field unresolved_field; +typedef struct unresolved_method unresolved_method; +typedef struct unresolved_subtype_set unresolved_subtype_set; + + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vm/jit/jit.h" +#include "vm/jit/reg.h" +#include "vm/jit/verify/typeinfo.h" + +#include "vmcore/class.h" +#include "vmcore/field.h" +#include "vmcore/method.h" +#include "vmcore/references.h" + + +/* constants ******************************************************************/ + +#define RESOLVE_STATIC 0x0001 /* ref to static fields/methods */ +#define RESOLVE_PUTFIELD 0x0002 /* field ref inside a PUT{FIELD,STATIC}... */ +#define RESOLVE_SPECIAL 0x0004 /* method ref inside INVOKESPECIAL */ + + +/* enums **********************************************************************/ + +typedef enum { + resolveLazy, + resolveEager +} resolve_mode_t; + +typedef enum { + resolveLinkageError, + resolveIllegalAccessError +} resolve_err_t; + +typedef enum { + resolveFailed = false, /* this must be a false value */ + resolveDeferred = true, /* this must be a true value */ + resolveSucceeded +} resolve_result_t; + +/* structs ********************************************************************/ + +struct unresolved_subtype_set { + classref_or_classinfo *subtyperefs; /* NULL terminated list */ +}; + +struct unresolved_class { + constant_classref *classref; + methodinfo *referermethod; + unresolved_subtype_set subtypeconstraints; +}; + +/* XXX unify heads of unresolved_field and unresolved_method? */ + +struct unresolved_field { + constant_FMIref *fieldref; + methodinfo *referermethod; + s4 flags; + + unresolved_subtype_set instancetypes; + unresolved_subtype_set valueconstraints; +}; + +struct unresolved_method { + constant_FMIref *methodref; + methodinfo *referermethod; + s4 flags; + + unresolved_subtype_set instancetypes; + unresolved_subtype_set *paramconstraints; +}; + +#define SUBTYPESET_IS_EMPTY(stset) \ + ((stset).subtyperefs == NULL) + +#define UNRESOLVED_SUBTYPE_SET_EMTPY(stset) \ + do { (stset).subtyperefs = NULL; } while(0) + +/* function prototypes ********************************************************/ + +bool resolve_class_from_name(classinfo* referer,methodinfo *refmethod, + utf *classname, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result); + +bool resolve_classref(methodinfo *refmethod, + constant_classref *ref, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result); + +bool resolve_classref_or_classinfo(methodinfo *refmethod, + classref_or_classinfo cls, + resolve_mode_t mode, + bool checkaccess, + bool link, + classinfo **result); + +bool resolve_class_from_typedesc(typedesc *d,bool checkaccess,bool link,classinfo **result); + +#ifdef ENABLE_VERIFIER +bool resolve_class(unresolved_class *ref, + resolve_mode_t mode, + bool checkaccess, + classinfo **result); + +classinfo * resolve_class_eager(unresolved_class *ref); +#endif /* ENABLE_VERIFIER */ + +bool resolve_field(unresolved_field *ref, + resolve_mode_t mode, + fieldinfo **result); + +bool resolve_method(unresolved_method *ref, + resolve_mode_t mode, + methodinfo **result); + +classinfo * resolve_classref_eager(constant_classref *ref); +classinfo * resolve_classref_eager_nonabstract(constant_classref *ref); +fieldinfo * resolve_field_eager(unresolved_field *ref); +methodinfo * resolve_method_eager(unresolved_method *ref); + +#ifdef ENABLE_VERIFIER +unresolved_class * create_unresolved_class(methodinfo *refmethod, + constant_classref *classref, + typeinfo *valuetype); +#endif + +unresolved_field *resolve_create_unresolved_field(classinfo *referer, + methodinfo *refmethod, + instruction *iptr); + +unresolved_method * resolve_create_unresolved_method(classinfo *referer, + methodinfo *refmethod, + constant_FMIref *methodref, + bool invokestatic, + bool invokespecial); + +void unresolved_class_free(unresolved_class *ref); +void unresolved_field_free(unresolved_field *ref); +void unresolved_method_free(unresolved_method *ref); + +resolve_result_t resolve_method_lazy(methodinfo *refmethod, + constant_FMIref *methodref, + bool invokespecial); + +resolve_result_t resolve_field_lazy(methodinfo *refmethod, + constant_FMIref *fieldref); + +#if defined(ENABLE_VERIFIER) +resolve_result_t resolve_field_verifier_checks(methodinfo *refmethod, + constant_FMIref *fieldref, + classinfo *container, + fieldinfo *fi, + typeinfo *instanceti, + typeinfo *valueti, + bool isstatic, + bool isput); + +bool resolve_constrain_unresolved_field(unresolved_field *ref, + classinfo *referer, + methodinfo *refmethod, + typeinfo *instanceti, + typeinfo *valueti); + +resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, + constant_FMIref *methodref, + methodinfo *mi, + bool invokestatic); + +resolve_result_t resolve_method_instance_type_checks(methodinfo *refmethod, + methodinfo *mi, + typeinfo *instanceti, + bool invokespecial); + +resolve_result_t resolve_method_param_type_checks(jitdata *jd, + methodinfo *refmethod, + instruction *iptr, + methodinfo *mi, + bool invokestatic); + +resolve_result_t resolve_method_param_type_checks_stackbased( + methodinfo *refmethod, + methodinfo *mi, + bool invokestatic, + typedescriptor *stack); + +bool resolve_method_loading_constraints(classinfo *referer, + methodinfo *mi); + +bool resolve_constrain_unresolved_method_instance(unresolved_method *ref, + methodinfo *refmethod, + typeinfo *instanceti, + bool invokespecial); + +bool resolve_constrain_unresolved_method_params(jitdata *jd, + unresolved_method *ref, + methodinfo *refmethod, + instruction *iptr); + +bool resolve_constrain_unresolved_method_params_stackbased( + unresolved_method *ref, + methodinfo *refmethod, + typedescriptor *stack); + +#endif /* defined(ENABLE_VERIFIER) */ + +#ifndef NDEBUG +void unresolved_class_debug_dump(unresolved_class *ref,FILE *file); +void unresolved_field_debug_dump(unresolved_field *ref,FILE *file); +void unresolved_method_debug_dump(unresolved_method *ref,FILE *file); +void unresolved_subtype_set_debug_dump(unresolved_subtype_set *stset,FILE *file); +#endif + +#endif /* _RESOLVE_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: + */ + diff --git a/src/vmcore/rt-timing.c b/src/vmcore/rt-timing.c new file mode 100644 index 000000000..1cb99a168 --- /dev/null +++ b/src/vmcore/rt-timing.c @@ -0,0 +1,186 @@ +/* src/vmcore/rt-timing.c - POSIX real-time timing utilities + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id$ + +*/ + + +#include "config.h" + +#include +#include +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vm/global.h" + +#include "vmcore/rt-timing.h" + + +struct rt_timing_stat { + int index; + int totalindex; + const char *name; +}; + +static struct rt_timing_stat rt_timing_stat_defs[] = { + { RT_TIMING_JIT_CHECKS ,RT_TIMING_JIT_TOTAL , "checks at beginning" }, + { RT_TIMING_JIT_PARSE ,RT_TIMING_JIT_TOTAL , "parse" }, + { RT_TIMING_JIT_STACK ,RT_TIMING_JIT_TOTAL , "analyse_stack" }, + { RT_TIMING_JIT_TYPECHECK ,RT_TIMING_JIT_TOTAL , "typecheck" }, + { RT_TIMING_JIT_LOOP ,RT_TIMING_JIT_TOTAL , "loop" }, + { RT_TIMING_JIT_IFCONV ,RT_TIMING_JIT_TOTAL , "if conversion" }, + { RT_TIMING_JIT_ALLOC ,RT_TIMING_JIT_TOTAL , "register allocation" }, + { RT_TIMING_JIT_RPLPOINTS ,RT_TIMING_JIT_TOTAL , "replacement point generation" }, + { RT_TIMING_JIT_CODEGEN ,RT_TIMING_JIT_TOTAL , "codegen" }, + { RT_TIMING_JIT_TOTAL ,-1 , "total compile time" }, + { -1 ,-1 , "" }, + + { RT_TIMING_LINK_RESOLVE ,RT_TIMING_LINK_TOTAL, "link: resolve superclass/superinterfaces"}, + { RT_TIMING_LINK_C_VFTBL ,RT_TIMING_LINK_TOTAL, "link: compute vftbl length"}, + { RT_TIMING_LINK_ABSTRACT ,RT_TIMING_LINK_TOTAL, "link: handle abstract methods"}, + { RT_TIMING_LINK_C_IFTBL ,RT_TIMING_LINK_TOTAL, "link: compute interface table"}, + { RT_TIMING_LINK_F_VFTBL ,RT_TIMING_LINK_TOTAL, "link: fill vftbl"}, + { RT_TIMING_LINK_OFFSETS ,RT_TIMING_LINK_TOTAL, "link: set offsets"}, + { RT_TIMING_LINK_F_IFTBL ,RT_TIMING_LINK_TOTAL, "link: fill interface table"}, + { RT_TIMING_LINK_FINALIZER ,RT_TIMING_LINK_TOTAL, "link: set finalizer"}, + { RT_TIMING_LINK_EXCEPTS ,RT_TIMING_LINK_TOTAL, "link: resolve exception classes"}, + { RT_TIMING_LINK_SUBCLASS ,RT_TIMING_LINK_TOTAL, "link: re-calculate subclass indices"}, + { RT_TIMING_LINK_TOTAL ,-1 , "total link time" }, + { -1 ,-1 , "" }, + + { RT_TIMING_LOAD_CHECKS ,RT_TIMING_LOAD_TOTAL, "load: initial checks"}, + { RT_TIMING_LOAD_NDPOOL ,RT_TIMING_LOAD_TOTAL, "load: new descriptor pool"}, + { RT_TIMING_LOAD_CPOOL ,RT_TIMING_LOAD_TOTAL, "load: load constant pool"}, + { RT_TIMING_LOAD_SETUP ,RT_TIMING_LOAD_TOTAL, "load: class setup"}, + { RT_TIMING_LOAD_FIELDS ,RT_TIMING_LOAD_TOTAL, "load: load fields"}, + { RT_TIMING_LOAD_METHODS ,RT_TIMING_LOAD_TOTAL, "load: load methods"}, + { RT_TIMING_LOAD_CLASSREFS ,RT_TIMING_LOAD_TOTAL, "load: create classrefs"}, + { RT_TIMING_LOAD_DESCS ,RT_TIMING_LOAD_TOTAL, "load: allocate descriptors"}, + { RT_TIMING_LOAD_SETREFS ,RT_TIMING_LOAD_TOTAL, "load: set classrefs"}, + { RT_TIMING_LOAD_PARSEFDS ,RT_TIMING_LOAD_TOTAL, "load: parse field descriptors"}, + { RT_TIMING_LOAD_PARSEMDS ,RT_TIMING_LOAD_TOTAL, "load: parse method descriptors"}, + { RT_TIMING_LOAD_PARSECP ,RT_TIMING_LOAD_TOTAL, "load: parse descriptors in constant pool"}, + { RT_TIMING_LOAD_VERIFY ,RT_TIMING_LOAD_TOTAL, "load: verifier checks"}, + { RT_TIMING_LOAD_ATTRS ,RT_TIMING_LOAD_TOTAL, "load: load attributes"}, + { RT_TIMING_LOAD_TOTAL ,-1 , "total load time (from classbuffer)"}, + { -1 ,-1 , "" }, + + { RT_TIMING_LOAD_BOOT_LOOKUP,-1 , "boot: lookup in classcache"}, + { RT_TIMING_LOAD_BOOT_ARRAY ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: load array classes"}, + { RT_TIMING_LOAD_BOOT_SUCK ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: suck class files"}, + { RT_TIMING_LOAD_BOOT_LOAD ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: load from class buffer"}, + { RT_TIMING_LOAD_BOOT_CACHE ,RT_TIMING_LOAD_BOOT_TOTAL, "boot: store in classcache"}, + { RT_TIMING_LOAD_BOOT_TOTAL ,-1 , "total bootstrap loader time"}, + { -1 ,-1 , "" }, + + { RT_TIMING_LOAD_CL_LOOKUP ,-1 , "classloader: lookup in classcache" }, + { RT_TIMING_LOAD_CL_PREPARE ,-1 , "classloader: prepare loader call" }, + { RT_TIMING_LOAD_CL_JAVA ,-1 , "classloader: loader Java code" }, + { RT_TIMING_LOAD_CL_CACHE ,-1 , "classloader: store in classcache" }, + { -1 ,-1 , "" }, + + { RT_TIMING_NEW_OBJECT ,-1 , "builtin_new time" }, + { RT_TIMING_NEW_ARRAY ,-1 , "builtin_newarray time" }, + { -1 ,-1 , "" }, + + { 0 ,-1 , NULL } +}; + +static long long rt_timing_sum[RT_TIMING_N] = { 0 }; + +void rt_timing_gettime(struct timespec *ts) +{ + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID,ts) != 0) { + fprintf(stderr,"could not get time by clock_gettime: %s\n",strerror(errno)); + abort(); + } +} + +long rt_timing_diff_usec(struct timespec *a,struct timespec *b) +{ + long diff; + time_t atime; + + diff = (b->tv_nsec - a->tv_nsec) / 1000; + atime = a->tv_sec; + while (atime < b->tv_sec) { + atime++; + diff += 1000000; + } + return diff; +} + +void rt_timing_time_diff(struct timespec *a,struct timespec *b,int index) +{ + long diff; + + diff = rt_timing_diff_usec(a,b); + rt_timing_sum[index] += diff; +} + +void rt_timing_print_time_stats(FILE *file) +{ + struct rt_timing_stat *stats; + double total; + + for (stats = rt_timing_stat_defs; stats->name; ++stats) { + if (stats->index < 0) { + fprintf(file,"%s\n",stats->name); + continue; + } + + if (stats->totalindex >= 0) { + total = rt_timing_sum[stats->totalindex]; + fprintf(file,"%12lld usec %3.0f%% %s\n", + rt_timing_sum[stats->index], + (total != 0.0) ? rt_timing_sum[stats->index] / total * 100.0 : 0.0, + stats->name); + } + else { + fprintf(file,"%12lld usec %s\n", + rt_timing_sum[stats->index], + stats->name); + } + } +} + +/* + * 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: + */ diff --git a/src/vmcore/rt-timing.h b/src/vmcore/rt-timing.h new file mode 100644 index 000000000..2585315ac --- /dev/null +++ b/src/vmcore/rt-timing.h @@ -0,0 +1,137 @@ +/* src/vmcore/rt-timing.h - POSIX real-time timing utilities + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id$ + +*/ + + +#ifndef _RT_TIMING_H +#define _RT_TIMING_H + +#include "config.h" + +#if defined(ENABLE_RT_TIMING) + +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vm/global.h" + + +#define RT_TIMING_GET_TIME(ts) \ + rt_timing_gettime(&(ts)); + +#define RT_TIMING_TIME_DIFF(a,b,index) \ + rt_timing_time_diff(&(a),&(b),(index)); + +#define RT_TIMING_JIT_CHECKS 0 +#define RT_TIMING_JIT_PARSE 1 +#define RT_TIMING_JIT_STACK 2 +#define RT_TIMING_JIT_TYPECHECK 3 +#define RT_TIMING_JIT_LOOP 4 +#define RT_TIMING_JIT_IFCONV 5 +#define RT_TIMING_JIT_ALLOC 6 +#define RT_TIMING_JIT_RPLPOINTS 7 +#define RT_TIMING_JIT_CODEGEN 8 +#define RT_TIMING_JIT_TOTAL 9 + +#define RT_TIMING_LINK_RESOLVE 10 +#define RT_TIMING_LINK_C_VFTBL 11 +#define RT_TIMING_LINK_ABSTRACT 12 +#define RT_TIMING_LINK_C_IFTBL 13 +#define RT_TIMING_LINK_F_VFTBL 14 +#define RT_TIMING_LINK_OFFSETS 15 +#define RT_TIMING_LINK_F_IFTBL 16 +#define RT_TIMING_LINK_FINALIZER 17 +#define RT_TIMING_LINK_EXCEPTS 18 +#define RT_TIMING_LINK_SUBCLASS 19 +#define RT_TIMING_LINK_TOTAL 20 + +#define RT_TIMING_LOAD_CHECKS 21 +#define RT_TIMING_LOAD_NDPOOL 22 +#define RT_TIMING_LOAD_CPOOL 23 +#define RT_TIMING_LOAD_SETUP 24 +#define RT_TIMING_LOAD_FIELDS 25 +#define RT_TIMING_LOAD_METHODS 26 +#define RT_TIMING_LOAD_CLASSREFS 27 +#define RT_TIMING_LOAD_DESCS 28 +#define RT_TIMING_LOAD_SETREFS 29 +#define RT_TIMING_LOAD_PARSEFDS 30 +#define RT_TIMING_LOAD_PARSEMDS 31 +#define RT_TIMING_LOAD_PARSECP 32 +#define RT_TIMING_LOAD_VERIFY 33 +#define RT_TIMING_LOAD_ATTRS 34 +#define RT_TIMING_LOAD_TOTAL 35 + +#define RT_TIMING_LOAD_BOOT_LOOKUP 36 +#define RT_TIMING_LOAD_BOOT_ARRAY 37 +#define RT_TIMING_LOAD_BOOT_SUCK 38 +#define RT_TIMING_LOAD_BOOT_LOAD 39 +#define RT_TIMING_LOAD_BOOT_CACHE 40 +#define RT_TIMING_LOAD_BOOT_TOTAL 41 + +#define RT_TIMING_LOAD_CL_LOOKUP 42 +#define RT_TIMING_LOAD_CL_PREPARE 43 +#define RT_TIMING_LOAD_CL_JAVA 44 +#define RT_TIMING_LOAD_CL_CACHE 45 + +#define RT_TIMING_NEW_OBJECT 46 +#define RT_TIMING_NEW_ARRAY 47 + +#define RT_TIMING_N 48 + +void rt_timing_gettime(struct timespec *ts); + +void rt_timing_time_diff(struct timespec *a,struct timespec *b,int index); + +long rt_timing_diff_usec(struct timespec *a,struct timespec *b); + +void rt_timing_print_time_stats(FILE *file); + +#else /* !defined(ENABLE_RT_TIMING) */ + +#define RT_TIMING_GET_TIME(ts) +#define RT_TIMING_TIME_DIFF(a,b,index) + +#endif /* defined(ENABLE_RT_TIMING) */ + +#endif /* _RT_TIMING_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: + */ diff --git a/src/vmcore/stackmap.c b/src/vmcore/stackmap.c new file mode 100644 index 000000000..d642c34a3 --- /dev/null +++ b/src/vmcore/stackmap.c @@ -0,0 +1,528 @@ +/* src/vmcore/stackmap.c - class attribute StackMapTable + + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, + R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, + C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, + Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "mm/memory.h" + +#include "vm/exceptions.h" + +#include "vmcore/class.h" +#include "vmcore/method.h" +#include "vmcore/options.h" +#include "vmcore/stackmap.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#include "vmcore/suck.h" + + +/* stackmap_get_verification_type_info ***************************************** + + union verification_type_info { + Top_variable_info; + Integer_variable_info; + Float_variable_info; + Long_variable_info; + Double_variable_info; + Null_variable_info; + UninitializedThis_variable_info; + Object_variable_info; + Uninitialized_variable_info; + } + + Top_variable_info { + u1 tag = ITEM_Top; // 0 + } + + Integer_variable_info { + u1 tag = ITEM_Integer; // 1 + } + + Float_variable_info { + u1 tag = ITEM_Float; // 2 + } + + Long_variable_info { + u1 tag = ITEM_Long; // 4 + } + + Double_variable_info { + u1 tag = ITEM_Double; // 3 + } + + Null_variable_info { + u1 tag = ITEM_Null; // 5 + } + + UninitializedThis_variable_info { + u1 tag = ITEM_UninitializedThis; // 6 + } + + Object_variable_info { + u1 tag = ITEM_Object; // 7 + u2 cpool_index; + } + + Uninitialized_variable_info { + u1 tag = ITEM_Uninitialized; // 8 + u2 offset; + } + +*******************************************************************************/ + +static bool stackmap_get_verification_type_info(classbuffer *cb, verification_type_info_t *verification_type_info) +{ + /* get verification type */ + + if (!suck_check_classbuffer_size(cb, 1)) + return false; + + verification_type_info->tag = suck_u1(cb); + + /* process the tag */ + + switch (verification_type_info->tag) { + case ITEM_Top: + case ITEM_Integer: + case ITEM_Float: + case ITEM_Long: + case ITEM_Double: + case ITEM_Null: + case ITEM_UninitializedThis: + break; + + case ITEM_Object: + /* get constant pool index */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + verification_type_info->Object_variable_info.cpool_index = suck_u2(cb); + break; + + case ITEM_Uninitialized: + /* get offset */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + verification_type_info->Uninitialized_variable_info.offset = suck_u2(cb); + break; + } + + return true; +} + + +/* stackmap_get_same_locals_1_stack_item_frame ********************************* + + same_locals_1_stack_item_frame { + u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 + verification_type_info stack[1]; + } + +*******************************************************************************/ + +static bool stackmap_get_same_locals_1_stack_item_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) +{ + same_locals_1_stack_item_frame_t *same_locals_1_stack_item_frame; + + /* for convenience */ + + same_locals_1_stack_item_frame = + &(stack_map_frame->same_locals_1_stack_item_frame); + + if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame->stack[0]))) + return false; + + return true; +} + + +/* stackmap_get_same_locals_1_stack_item_frame_extended ************************ + + same_locals_1_stack_item_frame_extended { + u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; // 247 + u2 offset_delta; + verification_type_info stack[1]; + } + +*******************************************************************************/ + +static bool stackmap_get_same_locals_1_stack_item_frame_extended(classbuffer *cb, stack_map_frame_t *stack_map_frame) +{ + same_locals_1_stack_item_frame_extended_t *same_locals_1_stack_item_frame_extended; + + /* for convenience */ + + same_locals_1_stack_item_frame_extended = + &(stack_map_frame->same_locals_1_stack_item_frame_extended); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + /* get offset delta */ + + same_locals_1_stack_item_frame_extended->offset_delta = suck_u2(cb); + + /* process stack */ + + if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame_extended->stack[0]))) + return false; + + return true; +} + + +/* stackmap_get_chop_frame ***************************************************** + + chop_frame { + u1 frame_type = CHOP_FRAME; // 248-250 + u2 offset_delta; + } + +*******************************************************************************/ + +static bool stackmap_get_chop_frame(classbuffer *cb, + stack_map_frame_t *stack_map_frame) +{ + chop_frame_t *chop_frame; + + /* for convenience */ + + chop_frame = &(stack_map_frame->chop_frame); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + /* get offset delta */ + + chop_frame->offset_delta = suck_u2(cb); + + return true; +} + + +/* stackmap_get_same_frame_extended ******************************************** + + same_frame_extended { + u1 frame_type = SAME_FRAME_EXTENDED; // 251 + u2 offset_delta; + } + +*******************************************************************************/ + +static bool stackmap_get_same_frame_extended(classbuffer *cb, + stack_map_frame_t *stack_map_frame) +{ + same_frame_extended_t *same_frame_extended; + + /* for convenience */ + + same_frame_extended = &(stack_map_frame->same_frame_extended); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + /* get offset delta */ + + same_frame_extended->offset_delta = suck_u2(cb); + + return true; +} + + +/* stackmap_get_append_frame *************************************************** + + append_frame { + u1 frame_type = APPEND_FRAME; // 252-254 + u2 offset_delta; + verification_type_info locals[frame_Type - 251]; + } + +*******************************************************************************/ + +static bool stackmap_get_append_frame(classbuffer *cb, + stack_map_frame_t *stack_map_frame) +{ + append_frame_t *append_frame; + s4 number_of_locals; + s4 i; + + /* for convenience */ + + append_frame = &(stack_map_frame->append_frame); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + /* get offset delta */ + + append_frame->offset_delta = suck_u2(cb); + + /* allocate locals array */ + + number_of_locals = append_frame->frame_type - 251; + + append_frame->locals = DMNEW(verification_type_info_t, number_of_locals); + + /* process all locals */ + + for (i = 0; i < number_of_locals; i++) + if (!stackmap_get_verification_type_info(cb, &(append_frame->locals[i]))) + return false; + + return true; +} + + +/* stackmap_get_full_frame ***************************************************** + + full_frame { + u1 frame_type = FULL_FRAME; + u2 offset_delta; + u2 number_of_locals; + verification_type_info locals[number_of_locals]; + u2 number_of_stack_items; + verification_type_info stack[number_of_stack_items]; + } + +*******************************************************************************/ + +static bool stackmap_get_full_frame(classbuffer *cb, + stack_map_frame_t *stack_map_frame) +{ + full_frame_t *full_frame; + s4 i; + + /* for convenience */ + + full_frame = &(stack_map_frame->full_frame); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 2 + 2)) + return false; + + /* get offset delta */ + + stack_map_frame->full_frame.offset_delta = suck_u2(cb); + + /* get number of locals */ + + full_frame->number_of_locals = suck_u2(cb); + + /* allocate locals array */ + + full_frame->locals = + DMNEW(verification_type_info_t, full_frame->number_of_locals); + + /* process all locals */ + + for (i = 0; i < full_frame->number_of_locals; i++) + if (!stackmap_get_verification_type_info(cb, &(full_frame->locals[i]))) + return false; + + /* get number of stack items */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + full_frame->number_of_stack_items = suck_u2(cb); + + /* allocate stack array */ + + full_frame->stack = + DMNEW(verification_type_info_t, full_frame->number_of_stack_items); + + /* process all stack items */ + + for (i = 0; i < full_frame->number_of_stack_items; i++) + if (!stackmap_get_verification_type_info(cb, &(full_frame->stack[i]))) + return false; + + return true; +} + + +/* stackmap_load_attribute_stackmaptable *************************************** + + stack_map { + u2 attribute_name_index; + u4 attribute_length; + u2 number_of_entries; + stack_map_frame entries[number_of_entries]; + } + + union stack_map_frame { + same_frame; + same_locals_1_stack_item_frame; + same_locals_1_stack_item_frame_extended; + chop_frame; + same_frame_extended; + append_frame; + full_frame; + } + + same_frame { + u1 frame_type = SAME; // 0-63 + } + +*******************************************************************************/ + +bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m) +{ + classinfo *c; + stack_map_t *stack_map; + s4 i; + u1 frame_type; + + /* get classinfo */ + + c = cb->class; + + /* allocate stack map structure */ + + stack_map = DNEW(stack_map_t); + + STATISTICS(size_stack_map += sizeof(stack_map_t)); + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* attribute_length */ + + stack_map->attribute_length = suck_u4(cb); + + if (!suck_check_classbuffer_size(cb, stack_map->attribute_length)) + return false; + + /* get number of entries */ + + stack_map->number_of_entries = suck_u2(cb); + + /* process all entries */ + + stack_map->entries = DMNEW(stack_map_frame_t, stack_map->number_of_entries); + + for (i = 0; i < stack_map->number_of_entries; i++) { + /* get the frame type */ + + frame_type = suck_u1(cb); + + stack_map->entries[i].frame_type = frame_type; + + /* process frame */ + + if (frame_type <= FRAME_TYPE_SAME) { + /* same_frame */ + } + else if (frame_type <= FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM) { + /* same_locals_1_stack_item_frame */ + + if (!stackmap_get_same_locals_1_stack_item_frame(cb, &(stack_map->entries[i]))) + return false; + } + else if (frame_type <= FRAME_TYPE_RESERVED) { + /* reserved */ + + exceptions_throw_classformaterror(c, "reserved frame type"); + return false; + } + else if (frame_type == FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + /* same_locals_1_stack_item_frame_extended */ + + if (!stackmap_get_same_locals_1_stack_item_frame_extended(cb, &(stack_map->entries[i]))) + return false; + } + else if (frame_type <= FRAME_TYPE_CHOP) { + /* chop_frame */ + + if (!stackmap_get_chop_frame(cb, &(stack_map->entries[i]))) + return false; + } + else if (frame_type == FRAME_TYPE_SAME_FRAME_EXTENDED) { + /* same_frame_extended */ + + if (!stackmap_get_same_frame_extended(cb, &(stack_map->entries[i]))) + return false; + } + else if (frame_type <= FRAME_TYPE_APPEND) { + /* append_frame */ + + if (!stackmap_get_append_frame(cb, &(stack_map->entries[i]))) + return false; + } + else if (frame_type == FRAME_TYPE_FULL_FRAME) { + /* full_frame */ + + if (!stackmap_get_full_frame(cb, &(stack_map->entries[i]))) + return false; + } + } + + /* store stack map in method structure */ + +#if 0 + /* currently not used */ + + m->stack_map = stack_map; +#endif + + return true; +} + + +/* + * 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: + */ diff --git a/src/vmcore/stackmap.h b/src/vmcore/stackmap.h new file mode 100644 index 000000000..e8e519ac7 --- /dev/null +++ b/src/vmcore/stackmap.h @@ -0,0 +1,234 @@ +/* src/vmcore/stackmap.h - class attribute StackMapTable + + Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, + R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, + C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, + Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $ + +*/ + + +#ifndef _STACKMAP_H +#define _STACKMAP_H + +/* forward typedefs ***********************************************************/ + +typedef struct stack_map_t stack_map_t; +typedef union stack_map_frame_t stack_map_frame_t; +typedef struct same_locals_1_stack_item_frame_t same_locals_1_stack_item_frame_t; +typedef struct same_locals_1_stack_item_frame_extended_t same_locals_1_stack_item_frame_extended_t; +typedef struct chop_frame_t chop_frame_t; +typedef struct same_frame_extended_t same_frame_extended_t; +typedef struct append_frame_t append_frame_t; +typedef struct full_frame_t full_frame_t; + +typedef union verification_type_info_t verification_type_info_t; +typedef struct Top_variable_info_t Top_variable_info_t; +typedef struct Integer_variable_info_t Integer_variable_info_t; +typedef struct Float_variable_info_t Float_variable_info_t; +typedef struct Long_variable_info_t Long_variable_info_t; +typedef struct Double_variable_info_t Double_variable_info_t; +typedef struct Null_variable_info_t Null_variable_info_t; +typedef struct UninitializedThis_variable_info_t UninitializedThis_variable_info_t; +typedef struct Object_variable_info_t Object_variable_info_t; +typedef struct Uninitialized_variable_info_t Uninitialized_variable_info_t; + + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + +#include "vmcore/loader.h" +#include "vmcore/method.h" + + +/* verification_type_info *****************************************************/ + +#define ITEM_Top 0 +#define ITEM_Integer 1 +#define ITEM_Float 2 +#define ITEM_Double 3 +#define ITEM_Long 4 +#define ITEM_Null 5 +#define ITEM_UninitializedThis 6 +#define ITEM_Object 7 +#define ITEM_Uninitialized 8 + +struct Top_variable_info_t { + u1 tag; +}; + +struct Integer_variable_info_t { + u1 tag; +}; + +struct Float_variable_info_t { + u1 tag; +}; + +struct Long_variable_info_t { + u1 tag; +}; + +struct Double_variable_info_t { + u1 tag; +}; + +struct Null_variable_info_t { + u1 tag; +}; + +struct UninitializedThis_variable_info_t { + u1 tag; +}; + +struct Object_variable_info_t { + u1 tag; + u2 cpool_index; +}; + +struct Uninitialized_variable_info_t { + u1 tag; + u2 offset; +}; + +union verification_type_info_t { + u1 tag; + Top_variable_info_t Top_variable_info; + Integer_variable_info_t Integer_variable_info; + Float_variable_info_t Float_variable_info; + Long_variable_info_t Long_variable_info; + Double_variable_info_t Double_variable_info; + Null_variable_info_t Null_variable_info; + UninitializedThis_variable_info_t UninitializedThis_variable_info; + Object_variable_info_t Object_variable_info; + Uninitialized_variable_info_t Uninitialized_variable_info; +}; + + +/* stack_map_t ****************************************************************/ + +struct stack_map_t { + u2 attribute_name_index; + u4 attribute_length; + u2 number_of_entries; + stack_map_frame_t *entries; +}; + + +/* same_locals_1_stack_item_frame_t *******************************************/ + +struct same_locals_1_stack_item_frame_t { + u1 frame_type; + verification_type_info_t stack[1]; +}; + + +/* same_locals_1_stack_item_frame_extended_t **********************************/ + +struct same_locals_1_stack_item_frame_extended_t { + u1 frame_type; + u2 offset_delta; + verification_type_info_t stack[1]; +}; + + +/* chop_frame_t ***************************************************************/ + +struct chop_frame_t { + u1 frame_type; + u2 offset_delta; +}; + + +/* same_frame_extended_t ******************************************************/ + +struct same_frame_extended_t { + u1 frame_type; + u2 offset_delta; +}; + + +/* append_frame_t *************************************************************/ + +struct append_frame_t { + u1 frame_type; + u2 offset_delta; + verification_type_info_t *locals; +}; + + +/* full_frame_t ***************************************************************/ + +struct full_frame_t { + u1 frame_type; + u2 offset_delta; + u2 number_of_locals; + verification_type_info_t *locals; + u2 number_of_stack_items; + verification_type_info_t *stack; +}; + + +/* stack_map_frame_t **********************************************************/ + +#define FRAME_TYPE_SAME 63 /* 0-63 */ +#define FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM 127 /* 0-127 */ +#define FRAME_TYPE_RESERVED 246 /* 128-246 */ +#define FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED 247 /* 247 */ +#define FRAME_TYPE_CHOP 250 /* 248-250 */ +#define FRAME_TYPE_SAME_FRAME_EXTENDED 251 /* 251 */ +#define FRAME_TYPE_APPEND 254 /* 252-254 */ +#define FRAME_TYPE_FULL_FRAME 255 /* 255 */ + +union stack_map_frame_t { + u1 frame_type; + same_locals_1_stack_item_frame_t same_locals_1_stack_item_frame; + same_locals_1_stack_item_frame_extended_t same_locals_1_stack_item_frame_extended; + chop_frame_t chop_frame; + same_frame_extended_t same_frame_extended; + append_frame_t append_frame; + full_frame_t full_frame; +}; + + +/* function prototypes ********************************************************/ + +bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m); + +#endif /* _STACKMAP_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: + */ diff --git a/src/vmcore/statistics.c b/src/vmcore/statistics.c new file mode 100644 index 000000000..5135be202 --- /dev/null +++ b/src/vmcore/statistics.c @@ -0,0 +1,665 @@ +/* src/vmcore/statistics.c - global varables for statistics + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: statistics.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include + +#include "vm/types.h" + +#include "toolbox/logging.h" +#include "vm/global.h" +#include "vmcore/options.h" +#include "vmcore/statistics.h" + + +/* global variables ***********************************************************/ + +static s8 loadingtime = 0; /* accumulated loading time */ +static s8 loadingstarttime = 0; +static s8 loadingstoptime = 0; +static s4 loadingtime_recursion = 0; + +static s8 compilingtime = 0; /* accumulated compile time */ +static s8 compilingstarttime = 0; +static s8 compilingstoptime = 0; +static s4 compilingtime_recursion = 0; + +s4 codememusage = 0; +s4 maxcodememusage = 0; + +s4 memoryusage = 0; +s4 maxmemusage = 0; + +s4 maxdumpsize = 0; + +s4 globalallocateddumpsize = 0; +s4 globaluseddumpsize = 0; + + +/* variables for measurements *************************************************/ + +s4 size_classinfo = 0; +s4 size_fieldinfo = 0; +s4 size_methodinfo = 0; +s4 size_lineinfo = 0; +s4 size_codeinfo = 0; + +s4 size_stack_map = 0; + +int count_const_pool_len = 0; +int count_classref_len = 0; +int count_parsed_desc_len = 0; +int count_vftbl_len = 0; +int count_all_methods = 0; +int count_methods_marked_used = 0; /* RTA */ + +int count_vmcode_len = 0; +int count_extable_len = 0; +int count_class_loads = 0; +int count_class_inits = 0; + +int count_utf_len = 0; /* size of utf hash */ +int count_utf_new = 0; /* calls of utf_new */ +int count_utf_new_found = 0; /* calls of utf_new with fast return */ + +int count_locals_conflicts = 0; /* register allocator statistics */ +int count_locals_spilled = 0; +int count_locals_register = 0; +int count_ss_spilled = 0; +int count_ss_register = 0; +int count_methods_allocated_by_lsra = 0; +int count_mem_move_bb = 0; +int count_interface_size = 0; +int count_argument_mem_ss = 0; +int count_argument_reg_ss = 0; +int count_method_in_register = 0; +int count_mov_reg_reg = 0; +int count_mov_mem_reg = 0; +int count_mov_reg_mem = 0; +int count_mov_mem_mem = 0; + +int count_jit_calls = 0; +int count_methods = 0; +int count_spills = 0; +int count_spills_read = 0; +int count_pcmd_activ = 0; +int count_pcmd_drop = 0; +int count_pcmd_zero = 0; +int count_pcmd_const_store = 0; +int count_pcmd_const_alu = 0; +int count_pcmd_const_bra = 0; +int count_pcmd_load = 0; +int count_pcmd_move = 0; +int count_load_instruction = 0; +int count_pcmd_store = 0; +int count_pcmd_store_comb = 0; +int count_dup_instruction = 0; +int count_pcmd_op = 0; +int count_pcmd_mem = 0; +int count_pcmd_met = 0; +int count_pcmd_bra = 0; +int count_pcmd_table = 0; +int count_pcmd_return = 0; +int count_pcmd_returnx = 0; +int count_check_null = 0; +int count_check_bound = 0; +int count_max_basic_blocks = 0; +int count_basic_blocks = 0; +int count_javainstr = 0; +int count_max_javainstr = 0; +int count_javacodesize = 0; +int count_javaexcsize = 0; +int count_calls = 0; +int count_tryblocks = 0; +int count_code_len = 0; +int count_data_len = 0; +int count_cstub_len = 0; +int count_nstub_len = 0; +int count_max_new_stack = 0; +int count_upper_bound_new_stack = 0; + +s4 count_branches_resolved = 0; +s4 count_branches_unresolved = 0; + +u8 count_native_function_calls=0; +u8 count_jni_callXmethod_calls=0; +u8 count_jni_calls=0; + + +static int count_block_stack_init[11] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0 +}; +int *count_block_stack = count_block_stack_init; +static int count_analyse_iterations_init[5] = { + 0, 0, 0, 0, 0 +}; +int *count_analyse_iterations = count_analyse_iterations_init; +static int count_method_bb_distribution_init[9] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; +int *count_method_bb_distribution = count_method_bb_distribution_init; +static int count_block_size_distribution_init[18] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0 +}; +int *count_block_size_distribution = count_block_size_distribution_init; +static int count_store_length_init[21] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0 +}; +int *count_store_length = count_store_length_init; +static int count_store_depth_init[11] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0 +}; +int *count_store_depth = count_store_depth_init; + + +/* instruction scheduler statistics *******************************************/ + +s4 count_schedule_basic_blocks = 0; +s4 count_schedule_nodes = 0; +s4 count_schedule_leaders = 0; +s4 count_schedule_max_leaders = 0; +s4 count_schedule_critical_path = 0; + + +/* nativeinvokation *********************************************************** + + increments the native invokation count by one + +*******************************************************************************/ + +void nativeinvokation(void) +{ + /* XXX do locking here */ + count_native_function_calls++; +} + + +/* jnicallXmethodinvokation *************************************************** + + increments the jni CallXMethod invokation count by one + +*******************************************************************************/ + +void jnicallXmethodnvokation(void) +{ + /* XXX do locking here */ + count_jni_callXmethod_calls++; +} + + +/* jniinvokation ************************************************************* + + increments the jni overall invokation count by one + +*******************************************************************************/ + +void jniinvokation(void) +{ + /* XXX do locking here */ + count_jni_calls++; +} + + +/* getcputime *********************************** ****************************** + + Returns the used CPU time in microseconds + +*******************************************************************************/ + +s8 getcputime(void) +{ + struct rusage ru; + int sec, usec; + + getrusage(RUSAGE_SELF, &ru); + sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec; + usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec; + + return sec * 1000000 + usec; +} + + +/* loadingtime_stop ************************************************************ + + XXX + +*******************************************************************************/ + +void loadingtime_start(void) +{ + loadingtime_recursion++; + + if (loadingtime_recursion == 1) + loadingstarttime = getcputime(); +} + + +/* loadingtime_stop ************************************************************ + + XXX + +*******************************************************************************/ + +void loadingtime_stop(void) +{ + if (loadingtime_recursion == 1) { + loadingstoptime = getcputime(); + loadingtime += (loadingstoptime - loadingstarttime); + } + + loadingtime_recursion--; +} + + +/* compilingtime_stop ********************************************************** + + XXX + +*******************************************************************************/ + +void compilingtime_start(void) +{ + compilingtime_recursion++; + + if (compilingtime_recursion == 1) + compilingstarttime = getcputime(); +} + + +/* compilingtime_stop ********************************************************** + + XXX + +*******************************************************************************/ + +void compilingtime_stop(void) +{ + if (compilingtime_recursion == 1) { + compilingstoptime = getcputime(); + compilingtime += (compilingstoptime - compilingstarttime); + } + + compilingtime_recursion--; +} + + +/* print_times ***************************************************************** + + Prints a summary of CPU time usage. + +*******************************************************************************/ + +void print_times(void) +{ + s8 totaltime; + s8 runtime; + + totaltime = getcputime(); + runtime = totaltime - loadingtime - compilingtime; + +#if SIZEOF_VOID_P == 8 + dolog("Time for loading classes: %6ld ms", loadingtime / 1000); + dolog("Time for compiling code: %6ld ms", compilingtime / 1000); + dolog("Time for running program: %6ld ms", runtime / 1000); + dolog("Total time: %6ld ms", totaltime / 1000); +#else + dolog("Time for loading classes: %6lld ms", loadingtime / 1000); + dolog("Time for compiling code: %6lld ms", compilingtime / 1000); + dolog("Time for running program: %6lld ms", runtime / 1000); + dolog("Total time: %6lld ms", totaltime / 1000); +#endif +} + + +/* print_stats ***************************************************************** + + outputs detailed compiler statistics + +*******************************************************************************/ + +void print_stats(void) +{ + s4 i; + float f; + s4 sum; + + + dolog("Number of JIT compiler calls: %6d", count_jit_calls); + dolog("Number of compiled methods: %6d", count_methods); + + dolog("Number of compiled basic blocks: %6d", + count_basic_blocks); + dolog("Number of max. basic blocks per method: %6d", + count_max_basic_blocks); + + dolog("Number of compiled JavaVM instructions: %6d", + count_javainstr); + dolog("Number of max. JavaVM instructions per method: %6d", + count_max_javainstr); + dolog("Size of compiled JavaVM instructions: %6d(%d)", + count_javacodesize, count_javacodesize - count_methods * 18); + + dolog("Size of compiled Exception Tables: %d", count_javaexcsize); + dolog("Number of Machine-Instructions: %d", count_code_len >> 2); + dolog("Number of Spills (write to memory): %d", count_spills); + dolog("Number of Spills (read from memory): %d", count_spills_read); + dolog("Number of Activ Pseudocommands: %6d", count_pcmd_activ); + dolog("Number of Drop Pseudocommands: %6d", count_pcmd_drop); + dolog("Number of Const Pseudocommands: %6d (zero:%5d)", + count_pcmd_load, count_pcmd_zero); + dolog("Number of ConstAlu Pseudocommands: %6d (cmp: %5d, store:%5d)", + count_pcmd_const_alu, count_pcmd_const_bra, count_pcmd_const_store); + dolog("Number of Move Pseudocommands: %6d", count_pcmd_move); + dolog("Number of Load Pseudocommands: %6d", count_load_instruction); + dolog("Number of Store Pseudocommands: %6d (combined: %5d)", + count_pcmd_store, count_pcmd_store - count_pcmd_store_comb); + dolog("Number of OP Pseudocommands: %6d", count_pcmd_op); + dolog("Number of DUP Pseudocommands: %6d", count_dup_instruction); + dolog("Number of Mem Pseudocommands: %6d", count_pcmd_mem); + dolog("Number of Method Pseudocommands: %6d", count_pcmd_met); + dolog("Number of Branch Pseudocommands: %6d (rets:%5d, Xrets: %5d)", + count_pcmd_bra, count_pcmd_return, count_pcmd_returnx); + log_println(" resolved branches: %6d", count_branches_resolved); + log_println(" unresolved branches: %6d", count_branches_unresolved); + dolog("Number of Table Pseudocommands: %6d", count_pcmd_table); + dolog("Number of Useful Pseudocommands: %6d", count_pcmd_table + + count_pcmd_bra + count_pcmd_load + count_pcmd_mem + count_pcmd_op); + dolog("Number of Null Pointer Checks: %6d", count_check_null); + dolog("Number of Array Bound Checks: %6d", count_check_bound); + dolog("Number of Try-Blocks: %d", count_tryblocks); + dolog("Maximal count of stack elements: %d", count_max_new_stack); + dolog("Upper bound of max stack elements: %d", count_upper_bound_new_stack); + dolog("Distribution of stack sizes at block boundary"); + dolog(" 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", + count_block_stack[0], count_block_stack[1], count_block_stack[2], + count_block_stack[3], count_block_stack[4], count_block_stack[5], + count_block_stack[6], count_block_stack[7], count_block_stack[8], + count_block_stack[9], count_block_stack[10]); + dolog("Distribution of store stack depth"); + dolog(" 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", + count_store_depth[0], count_store_depth[1], count_store_depth[2], + count_store_depth[3], count_store_depth[4], count_store_depth[5], + count_store_depth[6], count_store_depth[7], count_store_depth[8], + count_store_depth[9], count_store_depth[10]); + dolog("Distribution of store creator chains first part"); + dolog(" 0 1 2 3 4 5 6 7 8 9"); + dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", + count_store_length[0], count_store_length[1], count_store_length[2], + count_store_length[3], count_store_length[4], count_store_length[5], + count_store_length[6], count_store_length[7], count_store_length[8], + count_store_length[9]); + dolog("Distribution of store creator chains second part"); + dolog(" 10 11 12 13 14 15 16 17 18 19 >=20"); + dolog("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d", + count_store_length[10], count_store_length[11], + count_store_length[12], count_store_length[13], + count_store_length[14], count_store_length[15], + count_store_length[16], count_store_length[17], + count_store_length[18], count_store_length[19], + count_store_length[20]); + dolog("Distribution of analysis iterations"); + dolog(" 1 2 3 4 >=5"); + dolog("%6d%6d%6d%6d%6d", + count_analyse_iterations[0], count_analyse_iterations[1], + count_analyse_iterations[2], count_analyse_iterations[3], + count_analyse_iterations[4]); + + + /* Distribution of basic blocks per method ********************************/ + + log_println("Distribution of basic blocks per method:"); + log_println(" <=5 <=10 <=15 <=20 <=30 <=40 <=50 <=75 >75"); + + log_start(); + for (i = 0; i <= 8; i++) + log_print("%6d", count_method_bb_distribution[i]); + log_finish(); + + /* print ratio */ + + f = (float) count_methods; + + log_start(); + for (i = 0; i <= 8; i++) + log_print("%6.2f", (float) count_method_bb_distribution[i] / f); + log_finish(); + + /* print cumulated ratio */ + + log_start(); + for (i = 0, sum = 0; i <= 8; i++) { + sum += count_method_bb_distribution[i]; + log_print("%6.2f", (float) sum / f); + } + log_finish(); + + + /* Distribution of basic block sizes **************************************/ + + log_println("Distribution of basic block sizes:"); + log_println(" 0 1 2 3 4 5 6 7 8 9 <13 <15 <17 <19 <21 <26 <31 >30"); + + /* print block sizes */ + + log_start(); + for (i = 0; i <= 17; i++) + log_print("%6d", count_block_size_distribution[i]); + log_finish(); + + /* print ratio */ + + f = (float) count_basic_blocks; + + log_start(); + for (i = 0; i <= 17; i++) + log_print("%6.2f", (float) count_block_size_distribution[i] / f); + log_finish(); + + /* print cumulated ratio */ + + log_start(); + for (i = 0, sum = 0; i <= 17; i++) { + sum += count_block_size_distribution[i]; + log_print("%6.2f", (float) sum / f); + } + log_finish(); + + statistics_print_memory_usage(); + + dolog("Number of class loads: %6d", count_class_loads); + dolog("Number of class inits: %6d", count_class_inits); + dolog("Number of loaded Methods: %6d\n", count_all_methods); + + dolog("Calls of utf_new: %6d", count_utf_new); + dolog("Calls of utf_new (element found): %6d\n", count_utf_new_found); + + + /* LSRA statistics ********************************************************/ + + dolog("Moves reg -> reg: %6d", count_mov_reg_reg); + dolog("Moves mem -> reg: %6d", count_mov_mem_reg); + dolog("Moves reg -> mem: %6d", count_mov_reg_mem); + dolog("Moves mem -> mem: %6d", count_mov_mem_mem); + + dolog("Methods allocated by LSRA: %6d", + count_methods_allocated_by_lsra); + dolog("Conflicts between local Variables: %6d", count_locals_conflicts); + dolog("Local Variables held in Memory: %6d", count_locals_spilled); + dolog("Local Variables held in Registers: %6d", count_locals_register); + dolog("Stackslots held in Memory: %6d", count_ss_spilled); + dolog("Stackslots held in Registers: %6d", count_ss_register); + dolog("Memory moves at BB Boundaries: %6d", count_mem_move_bb); + dolog("Number of interface slots: %6d\n", count_interface_size); + dolog("Number of Argument stack slots in register: %6d", + count_argument_reg_ss); + dolog("Number of Argument stack slots in memory: %6d\n", + count_argument_mem_ss); + dolog("Number of Methods kept in registers: %6d\n", + count_method_in_register); + + + /* instruction scheduler statistics ***************************************/ + +#if defined(USE_SCHEDULER) + dolog("Instruction scheduler statistics:"); + dolog("Number of basic blocks: %7d", count_schedule_basic_blocks); + dolog("Number of nodes: %7d", count_schedule_nodes); + dolog("Number of leaders nodes: %7d", count_schedule_leaders); + dolog("Number of max. leaders nodes: %7d", count_schedule_max_leaders); + dolog("Length of critical path: %7d\n", count_schedule_critical_path); +#endif + + + /* call statistics ********************************************************/ + + dolog("Function call statistics:"); + dolog("Number of native function invokations: %ld", + count_native_function_calls); + dolog("Number of jni->CallXMethod function invokations: %ld", + count_jni_callXmethod_calls); + dolog("Overall number of jni invokations: %ld", + count_jni_calls); + + + /* now print other statistics ********************************************/ + +#if defined(ENABLE_INTRP) + print_dynamic_super_statistics(); +#endif +} + + +/* statistics_print_memory_usage *********************************************** + + Print current memory usage. + +*******************************************************************************/ + +void statistics_print_memory_usage(void) +{ + s4 sum; + + printf("memory usage ----------------------\n\n"); + printf("code: %10d\n", count_code_len); + printf("data: %10d\n", count_data_len); + + printf(" ----------\n"); + + sum = + count_code_len + + count_data_len; + + printf(" %10d\n", sum); + printf("\n"); + + printf("classinfo (%3d B): %10d\n", sizeof(classinfo), size_classinfo); + printf("fieldinfo (%3d B): %10d\n", sizeof(fieldinfo), size_fieldinfo); + printf("methodinfo (%3d B): %10d\n", sizeof(methodinfo), size_methodinfo); + printf("lineinfo (%3d B): %10d\n", sizeof(lineinfo), size_lineinfo); + printf("codeinfo (%3d B): %10d\n", sizeof(codeinfo), size_codeinfo); + printf(" ----------\n"); + + sum = + size_classinfo + + size_fieldinfo + + size_methodinfo + + size_lineinfo + + size_codeinfo; + + printf(" %10d\n", sum); + printf("\n"); + + printf("constant pool: %10d\n", count_const_pool_len); + printf("classref: %10d\n", count_classref_len); + printf("parsed descriptors: %10d\n", count_parsed_desc_len); + printf("vftbl: %10d\n", count_vftbl_len); + printf("compiler stubs: %10d\n", count_cstub_len); + printf("native stubs: %10d\n", count_nstub_len); + printf("utf: %10d\n", count_utf_len); + printf("vmcode: %10d\n", count_vmcode_len); + printf("exception tables: %10d\n", count_extable_len); + printf("stack map: %10d\n", size_stack_map); + printf(" ----------\n"); + + sum = + count_const_pool_len + + count_classref_len + + count_parsed_desc_len + + count_vftbl_len + + count_cstub_len + + count_nstub_len + + count_utf_len + + count_vmcode_len + + count_extable_len + + size_stack_map; + + printf(" %10d\n", sum); + printf("\n"); + + printf("max. memory usage: %10d\n", maxcodememusage); + printf("max. heap memory usage: %10d\n", maxmemusage); + printf("max. dump memory usage: %10d\n", maxdumpsize); + printf("\n"); + + printf("heap memory not freed: %10d\n", (s4) memoryusage); + printf("dump memory not freed: %10d\n", (s4) globalallocateddumpsize); + printf("\n"); +} + + +/* + * 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: + */ diff --git a/src/vmcore/statistics.h b/src/vmcore/statistics.h new file mode 100644 index 000000000..fdf371a42 --- /dev/null +++ b/src/vmcore/statistics.h @@ -0,0 +1,237 @@ +/* src/vmcore/statistics.h - exports global varables for statistics + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: statistics.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _STATISTICS_H +#define _STATISTICS_H + +#include "config.h" +#include "vm/types.h" + +#include "vm/global.h" + + +/* statistic macros ***********************************************************/ + +#if defined(ENABLE_STATISTICS) +#define STATISTICS(x) \ + do { \ + if (opt_stat) { \ + x; \ + } \ + } while (0) +#else +#define STATISTICS(x) /* nothing */ +#endif + +/* in_ inline statistics */ + +#define IN_MAX 9 +#define IN_UNIQUEVIRT 0x0000 +#define IN_UNIQUE_INTERFACE 0x0001 +#define IN_OUTSIDERS 0x0004 +#define IN_MAXDEPTH 0x0008 +#define IN_MAXCODE 0x0010 +#define IN_JCODELENGTH 0x0020 +#define IN_EXCEPTION 0x0040 +#define IN_NOT_UNIQUE_VIRT 0x0080 +#define IN_NOT_UNIQUE_INTERFACE 0x0100 + +#define N_UNIQUEVIRT 0 +#define N_UNIQUE_INTERFACE 1 +#define N_OUTSIDERS 2 +#define N_MAXDEPTH 3 +#define N_MAXCODE 4 +#define N_JCODELENGTH 5 +#define N_EXCEPTION 6 +#define N_NOT_UNIQUE_VIRT 7 +#define N_NOT_UNIQUE_INTERFACE 8 + + +/* global variables ***********************************************************/ + +extern s4 codememusage; +extern s4 maxcodememusage; + +extern s4 memoryusage; +extern s4 maxmemusage; + +extern s4 maxdumpsize; + +extern s4 globalallocateddumpsize; +extern s4 globaluseddumpsize; + + +/* variables for measurements *************************************************/ + +extern s4 size_classinfo; +extern s4 size_fieldinfo; +extern s4 size_methodinfo; +extern s4 size_lineinfo; +extern s4 size_codeinfo; + +extern s4 size_stack_map; + +extern int count_const_pool_len; +extern int count_classref_len; +extern int count_parsed_desc_len; +extern int count_vftbl_len; +extern int count_all_methods; +extern int count_methods_marked_used; /*RTA*/ +extern int count_vmcode_len; +extern int count_extable_len; +extern int count_class_loads; +extern int count_class_inits; + +extern int count_utf_len; /* size of utf hash */ +extern int count_utf_new; +extern int count_utf_new_found; + +extern int count_locals_conflicts; +extern int count_locals_spilled; +extern int count_locals_register; +extern int count_ss_spilled; +extern int count_ss_register; +extern int count_methods_allocated_by_lsra; +extern int count_mem_move_bb; +extern int count_interface_size; +extern int count_argument_mem_ss; +extern int count_argument_reg_ss; +extern int count_method_in_register; +extern int count_mov_reg_reg; +extern int count_mov_mem_reg; +extern int count_mov_reg_mem; +extern int count_mov_mem_mem; + +extern int count_jit_calls; +extern int count_methods; +extern int count_spills; +extern int count_spills_read; +extern int count_pcmd_activ; +extern int count_pcmd_drop; +extern int count_pcmd_zero; +extern int count_pcmd_const_store; +extern int count_pcmd_const_alu; +extern int count_pcmd_const_bra; +extern int count_pcmd_load; +extern int count_pcmd_move; +extern int count_load_instruction; +extern int count_pcmd_store; +extern int count_pcmd_store_comb; +extern int count_dup_instruction; +extern int count_pcmd_op; +extern int count_pcmd_mem; +extern int count_pcmd_met; +extern int count_pcmd_bra; +extern int count_pcmd_table; +extern int count_pcmd_return; +extern int count_pcmd_returnx; +extern int count_check_null; +extern int count_check_bound; +extern int count_max_basic_blocks; +extern int count_basic_blocks; +extern int count_max_javainstr; +extern int count_javainstr; +extern int count_javacodesize; +extern int count_javaexcsize; +extern int count_calls; +extern int count_tryblocks; +extern int count_code_len; +extern int count_data_len; +extern int count_cstub_len; +extern int count_nstub_len; +extern int count_max_new_stack; +extern int count_upper_bound_new_stack; + +extern s4 count_branches_resolved; +extern s4 count_branches_unresolved; + +extern int *count_block_stack; +extern int *count_analyse_iterations; +extern int *count_method_bb_distribution; +extern int *count_block_size_distribution; +extern int *count_store_length; +extern int *count_store_depth; + /* in_ inline statistics */ +extern int count_in; +extern int count_in_uniqVirt; +extern int count_in_uniqIntf; +extern int count_in_rejected; +extern int count_in_rejected_mult; +extern int count_in_outsiders; +extern int count_in_uniqueVirt_not_inlined; +extern int count_in_uniqueInterface_not_inlined; +extern int count_in_maxDepth; +extern int count_in_maxMethods; + +extern u2 count_in_not [512]; + +/* instruction scheduler statistics *******************************************/ + +extern s4 count_schedule_basic_blocks; +extern s4 count_schedule_nodes; +extern s4 count_schedule_leaders; +extern s4 count_schedule_max_leaders; +extern s4 count_schedule_critical_path; + + +/* function prototypes ********************************************************/ + +s8 getcputime(void); + +void loadingtime_start(void); +void loadingtime_stop(void); +void compilingtime_start(void); +void compilingtime_stop(void); + +void print_times(void); +void print_stats(void); + +void statistics_print_memory_usage(void); +void mem_usagelog(bool givewarnings); + +void nativeinvokation(void); +void compiledinvokation(void); +void jnicallXmethodnvokation(void); +void jniinvokation(void); + +#endif /* _STATISTICS_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: + */ diff --git a/src/vmcore/suck.c b/src/vmcore/suck.c new file mode 100644 index 000000000..5aeed7364 --- /dev/null +++ b/src/vmcore/suck.c @@ -0,0 +1,647 @@ +/* src/vmcore/suck.c - functions to read LE ordered types from a buffer + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: suck.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include + +#include "vm/types.h" + +#include "arch.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#else +# include "threads/none/lock.h" +#endif + +#include "toolbox/list.h" +#include "toolbox/logging.h" +#include "toolbox/util.h" + +#include "vm/exceptions.h" +#include "vm/properties.h" +#include "vm/vm.h" + +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vmcore/suck.h" +#include "vmcore/zip.h" + + +/* global variables ***********************************************************/ + +list *list_classpath_entries; + + +/* suck_init ******************************************************************* + + Initializes the suck subsystem like initializing the classpath + entries list. + +*******************************************************************************/ + +bool suck_init(void) +{ + list_classpath_entries = list_create(OFFSET(list_classpath_entry, linkage)); + + /* everything's ok */ + + return true; +} + + +/* scandir_filter ************************************************************** + + Filters for zip/jar files. + +*******************************************************************************/ + +#if defined(__LINUX__) +static int scandir_filter(const struct dirent *a) +#else +static int scandir_filter(struct dirent *a) +#endif +{ + s4 namlen; + +#if defined(_DIRENT_HAVE_D_NAMLEN) + namlen = a->d_namlen; +#else + namlen = strlen(a->d_name); +#endif + + if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) || + (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0)) + return 1; + + return 0; +} + + +/* suck_add ******************************************************************** + + Adds a classpath to the global classpath entries list. + +*******************************************************************************/ + +void suck_add(char *classpath) +{ + list_classpath_entry *lce; + char *start; + char *end; + char *filename; + s4 filenamelen; + bool is_zip; + char *cwd; + s4 cwdlen; +#if defined(ENABLE_ZLIB) + hashtable *ht; +#endif + + /* parse the classpath string */ + + for (start = classpath; (*start) != '\0'; ) { + + /* search for ':' delimiter to get the end of the current entry */ + for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); + + if (start != end) { + is_zip = false; + filenamelen = end - start; + + if (filenamelen > 4) { + if ((strncasecmp(end - 4, ".zip", 4) == 0) || + (strncasecmp(end - 4, ".jar", 4) == 0)) { + is_zip = true; + } + } + + /* save classpath entries as absolute pathnames */ + + cwd = NULL; + cwdlen = 0; + + if (*start != '/') { /* XXX fix me for win32 */ + cwd = _Jv_getcwd(); + cwdlen = strlen(cwd) + strlen("/"); + } + + /* allocate memory for filename and fill it */ + + filename = MNEW(char, filenamelen + cwdlen + strlen("/") + + strlen("0")); + + if (cwd) { + strcpy(filename, cwd); + strcat(filename, "/"); + strncat(filename, start, filenamelen); + + /* add cwd length to file length */ + filenamelen += cwdlen; + + } else { + strncpy(filename, start, filenamelen); + filename[filenamelen] = '\0'; + } + + lce = NULL; + + if (is_zip) { +#if defined(ENABLE_ZLIB) + ht = zip_open(filename); + + if (ht != NULL) { + lce = NEW(list_classpath_entry); + + lce->type = CLASSPATH_ARCHIVE; + lce->htclasses = ht; + lce->path = filename; + lce->pathlen = filenamelen; + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass) + printf("[Opened %s]\n", filename); + } + +#else + vm_abort("suck_add: zip/jar files not supported"); +#endif + } + else { + if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */ + filename[filenamelen] = '/'; + filename[filenamelen + 1] = '\0'; + filenamelen++; + } + + lce = NEW(list_classpath_entry); + + lce->type = CLASSPATH_PATH; + lce->path = filename; + lce->pathlen = filenamelen; + } + + /* add current classpath entry, if no error */ + + if (lce != NULL) + list_add_last(list_classpath_entries, lce); + } + + /* goto next classpath entry, skip ':' delimiter */ + + if ((*end) == ':') + start = end + 1; + else + start = end; + } +} + + +/* suck_add_from_property ****************************************************** + + Adds a classpath form a property entry to the global classpath + entries list. + +*******************************************************************************/ + +void suck_add_from_property(char *key) +{ + char *value; + char *start; + char *end; + char *path; + s4 pathlen; + struct dirent **namelist; + s4 n; + s4 i; + s4 namlen; + char *tmpbootclasspath; + + /* get the property value */ + + value = properties_get(key); + + if (value == NULL) + return; + + /* get the directory entries of the property */ + + for (start = value; (*start) != '\0'; ) { + + /* search for ':' delimiter to get the end of the current entry */ + + for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); + + /* found an entry */ + + if (start != end) { + /* allocate memory for the path entry */ + + pathlen = end - start; + path = MNEW(char, pathlen + strlen("0")); + + /* copy and terminate the string */ + + strncpy(path, start, pathlen); + path[pathlen] = '\0'; + + /* Reset namelist to NULL for the freeing in an error case + (see below). */ + + namelist = NULL; + + /* scan the directory found for zip/jar files */ + + n = scandir(path, &namelist, scandir_filter, alphasort); + + /* On error, just continue, this should be ok. */ + + if (n > 0) { + for (i = 0; i < n; i++) { +#if defined(_DIRENT_HAVE_D_NAMLEN) + namlen = namelist[i]->d_namlen; +#else + namlen = strlen(namelist[i]->d_name); +#endif + + /* reallocate memory for bootclasspath */ + + tmpbootclasspath = MNEW(char, + pathlen + strlen("/") + namlen + + strlen(":") + + strlen(_Jv_bootclasspath) + + strlen("0")); + + /* prepend the file found to bootclasspath */ + + strcpy(tmpbootclasspath, path); + strcat(tmpbootclasspath, "/"); + strcat(tmpbootclasspath, namelist[i]->d_name); + strcat(tmpbootclasspath, ":"); + + strcat(tmpbootclasspath, _Jv_bootclasspath); + + /* free old bootclasspath memory */ + + MFREE(_Jv_bootclasspath, u1, strlen(_Jv_bootclasspath)); + + /* and set the new bootclasspath */ + + _Jv_bootclasspath = tmpbootclasspath; + + /* free the memory allocated by scandir */ + /* (We use `free` as the memory came from the C library.) */ + + free(namelist[i]); + } + } + + /* On some systems (like Linux) when n == 0, then namelist + returned from scnadir is NULL, thus we don't have to + free it. + (Use `free` as the memory came from the C library.) */ + + if (namelist != NULL) + free(namelist); + + MFREE(path, char, pathlen + strlen("0")); + } + + /* goto next entry, skip ':' delimiter */ + + if ((*end) == ':') + start = end + 1; + else + start = end; + } +} + + +/* suck_check_classbuffer_size ************************************************* + + Assert that at least bytes are left to read is limited + to the range of non-negative s4 values. + +*******************************************************************************/ + +bool suck_check_classbuffer_size(classbuffer *cb, s4 len) +{ +#ifdef ENABLE_VERIFIER + if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) { + exceptions_throw_classformaterror((cb)->class, "Truncated class file"); + return false; + } +#endif /* ENABLE_VERIFIER */ + + return true; +} + + +u1 suck_u1(classbuffer *cb) +{ + u1 a; + + a = SUCK_BE_U1(cb->pos); + cb->pos++; + + return a; +} + + +u2 suck_u2(classbuffer *cb) +{ + u2 a; + + a = SUCK_BE_U2(cb->pos); + cb->pos += 2; + + return a; +} + + +u4 suck_u4(classbuffer *cb) +{ + u4 a; + + a = SUCK_BE_U4(cb->pos); + cb->pos += 4; + + return a; +} + + +u8 suck_u8(classbuffer *cb) +{ +#if U8_AVAILABLE == 1 + u8 a; + + a = SUCK_BE_U8(cb->pos); + cb->pos += 8; + + return a; +#else + u8 v; + + v.high = suck_u4(cb); + v.low = suck_u4(cb); + + return v; +#endif +} + + +float suck_float(classbuffer *cb) +{ + float f; + +#if WORDS_BIGENDIAN == 0 + u1 buffer[4]; + u2 i; + + for (i = 0; i < 4; i++) + buffer[3 - i] = suck_u1(cb); + + MCOPY((u1 *) (&f), buffer, u1, 4); +#else + suck_nbytes((u1*) (&f), cb, 4); +#endif + + if (sizeof(float) != 4) { + exceptions_throw_internalerror("Incompatible float-format"); + + /* XXX should we exit in such a case? */ + throw_exception_exit(); + } + + return f; +} + + +double suck_double(classbuffer *cb) +{ + double d; + +#if WORDS_BIGENDIAN == 0 + u1 buffer[8]; + u2 i; + +#if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__) + /* + * On little endian ARM processors when using FPA, word order + * of doubles is still big endian. So take that into account + * here. When using VFP, word order of doubles follows byte + * order. (michi 2005/07/24) + */ + for (i = 0; i < 4; i++) + buffer[3 - i] = suck_u1(cb); + for (i = 0; i < 4; i++) + buffer[7 - i] = suck_u1(cb); +#else + for (i = 0; i < 8; i++) + buffer[7 - i] = suck_u1(cb); +#endif /* defined(__ARM__) && ... */ + + MCOPY((u1 *) (&d), buffer, u1, 8); +#else + suck_nbytes((u1*) (&d), cb, 8); +#endif + + if (sizeof(double) != 8) { + exceptions_throw_internalerror("Incompatible double-format"); + + /* XXX should we exit in such a case? */ + throw_exception_exit(); + } + + return d; +} + + +/* suck_nbytes ***************************************************************** + + Transfer block of classfile data into a buffer. + +*******************************************************************************/ + +void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len) +{ + MCOPY(buffer, cb->pos, u1, len); + cb->pos += len; +} + + +/* suck_skip_nbytes ************************************************************ + + Skip block of classfile data. + +*******************************************************************************/ + +void suck_skip_nbytes(classbuffer *cb, s4 len) +{ + cb->pos += len; +} + + +/* suck_start ****************************************************************** + + Returns true if classbuffer is already loaded or a file for the + specified class has succussfully been read in. All directories of + the searchpath are used to find the classfile (.class). + Returns NULL if no classfile is found and writes an error message. + +*******************************************************************************/ + +classbuffer *suck_start(classinfo *c) +{ + list_classpath_entry *lce; + char *filename; + s4 filenamelen; + char *path; + FILE *classfile; + s4 len; + struct stat buffer; + classbuffer *cb; + + /* initialize return value */ + + cb = NULL; + + /* get the classname as char string (do it here for the warning at + the end of the function) */ + + filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0"); + filename = MNEW(char, filenamelen); + + utf_copy(filename, c->name); + strcat(filename, ".class"); + + /* walk through all classpath entries */ + + for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL; + lce = list_next(list_classpath_entries, lce)) { +#if defined(ENABLE_ZLIB) + if (lce->type == CLASSPATH_ARCHIVE) { + + /* enter a monitor on zip/jar archives */ + + LOCK_MONITOR_ENTER(lce); + + /* try to get the file in current archive */ + + cb = zip_get(lce, c); + + /* leave the monitor */ + + LOCK_MONITOR_EXIT(lce); + + } else { +#endif /* defined(ENABLE_ZLIB) */ + path = MNEW(char, lce->pathlen + filenamelen); + strcpy(path, lce->path); + strcat(path, filename); + + classfile = fopen(path, "r"); + + if (classfile) { /* file exists */ + if (!stat(path, &buffer)) { /* read classfile data */ + cb = NEW(classbuffer); + cb->class = c; + cb->size = buffer.st_size; + cb->data = MNEW(u1, cb->size); + cb->pos = cb->data; + cb->path = lce->path; + + /* read class data */ + + len = fread(cb->data, 1, cb->size, classfile); + + if (len != buffer.st_size) { + suck_stop(cb); +/* if (ferror(classfile)) { */ +/* } */ + } + + /* close the class file */ + + fclose(classfile); + } + } + + MFREE(path, char, lce->pathlen + filenamelen); +#if defined(ENABLE_ZLIB) + } +#endif + } + + if (opt_verbose) + if (cb == NULL) + dolog("Warning: Can not open class file '%s'", filename); + + MFREE(filename, char, filenamelen); + + return cb; +} + + +/* suck_stop ******************************************************************* + + Frees memory for buffer with classfile data. + + CAUTION: This function may only be called if buffer has been + allocated by suck_start with reading a file. + +*******************************************************************************/ + +void suck_stop(classbuffer *cb) +{ + /* free memory */ + + MFREE(cb->data, u1, cb->size); + FREE(cb, classbuffer); +} + + +/* + * 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: + */ diff --git a/src/vmcore/suck.h b/src/vmcore/suck.h new file mode 100644 index 000000000..8d24a0955 --- /dev/null +++ b/src/vmcore/suck.h @@ -0,0 +1,203 @@ +/* src/vmcore/suck.h - functions to read LE ordered types from a buffer + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: suck.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _SUCK_H +#define _SUCK_H + +#include "config.h" +#include "vm/types.h" + +#include "toolbox/hashtable.h" +#include "toolbox/list.h" + +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/loader.h" + + +/* list_classpath_entry *******************************************************/ + +enum { + CLASSPATH_PATH, + CLASSPATH_ARCHIVE +}; + +typedef struct list_classpath_entry list_classpath_entry; + +struct list_classpath_entry { +#if defined(ENABLE_THREADS) + java_objectheader header; /* monitor locking on zip/jar files */ +#endif + s4 type; + char *path; + s4 pathlen; +#if defined(ENABLE_ZLIB) + hashtable *htclasses; +#endif + listnode linkage; +}; + + +/* macros to read LE and BE types from a buffer ******************************** + + BE macros are for Java class file loading. + LE macros are for ZIP file loading. + +*******************************************************************************/ + +/* LE macros (for ZIP files ) *************************************************/ + +#if defined(__I386__) || defined(__X86_64__) + +/* we can optimize the LE access on little endian machines without alignment */ + +#define SUCK_LE_U1(p) *((u1 *) (p)) +#define SUCK_LE_U2(p) *((u2 *) (p)) +#define SUCK_LE_U4(p) *((u4 *) (p)) + +#if U8_AVAILABLE == 1 +#define SUCK_LE_U8(p) *((u8 *) (p)) +#endif + +#else /* defined(__I386__) || defined(__X86_64__) */ + +#define SUCK_LE_U1(p) \ + ((u1) (p)[0]) + +#define SUCK_LE_U2(p) \ + ((((u2) (p)[1]) << 8) + \ + ((u2) (p)[0])) + +#define SUCK_LE_U4(p) \ + ((((u4) (p)[3]) << 24) + \ + (((u4) (p)[2]) << 16) + \ + (((u4) (p)[1]) << 8) + \ + ((u4) (p)[0])) + +#if U8_AVAILABLE == 1 +#define SUCK_LE_U8(p) \ + ((((u8) (p)[7]) << 56) + \ + (((u8) (p)[6]) << 48) + \ + (((u8) (p)[5]) << 40) + \ + (((u8) (p)[4]) << 32) + \ + (((u8) (p)[3]) << 24) + \ + (((u8) (p)[2]) << 16) + \ + (((u8) (p)[1]) << 8) + \ + ((u8) (p)[0])) +#endif + +#endif /* defined(__I386__) || defined(__X86_64__) */ + + +/* BE macros (for Java class files ) ******************************************/ + +#define SUCK_BE_U1(p) \ + ((u1) (p)[0]) + +#define SUCK_BE_U2(p) \ + ((((u2) (p)[0]) << 8) + \ + ((u2) (p)[1])) + +#define SUCK_BE_U4(p) \ + ((((u4) (p)[0]) << 24) + \ + (((u4) (p)[1]) << 16) + \ + (((u4) (p)[2]) << 8) + \ + ((u4) (p)[3])) + +#if U8_AVAILABLE == 1 +#define SUCK_BE_U8(p) \ + ((((u8) (p)[0]) << 56) + \ + (((u8) (p)[1]) << 48) + \ + (((u8) (p)[2]) << 40) + \ + (((u8) (p)[3]) << 32) + \ + (((u8) (p)[4]) << 24) + \ + (((u8) (p)[5]) << 16) + \ + (((u8) (p)[6]) << 8) + \ + ((u8) (p)[7])) +#endif + + +#define SUCK_BE_S1(p) (s1) SUCK_BE_U1(p) +#define SUCK_BE_S2(p) (s2) SUCK_BE_U2(p) +#define SUCK_BE_S4(p) (s4) SUCK_BE_U4(p) +#define SUCK_BE_S8(p) (s8) SUCK_BE_U8(p) + + +/* signed suck defines ********************************************************/ + +#define suck_s1(a) (s1) suck_u1((a)) +#define suck_s2(a) (s2) suck_u2((a)) +#define suck_s4(a) (s4) suck_u4((a)) +#define suck_s8(a) (s8) suck_u8((a)) + + +/* export variables ***********************************************************/ + +extern list *list_classpath_entries; + + +/* function prototypes ********************************************************/ + +bool suck_init(void); + +void suck_add(char *classpath); +void suck_add_from_property(char *key); + +bool suck_check_classbuffer_size(classbuffer *cb, s4 len); + +u1 suck_u1(classbuffer *cb); +u2 suck_u2(classbuffer *cb); +u4 suck_u4(classbuffer *cb); +u8 suck_u8(classbuffer *cb); + +float suck_float(classbuffer *cb); +double suck_double(classbuffer *cb); + +void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len); +void suck_skip_nbytes(classbuffer *cb, s4 len); + +classbuffer *suck_start(classinfo *c); + +void suck_stop(classbuffer *cb); + +#endif /* _SUCK_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: + */ diff --git a/src/vmcore/utf8.c b/src/vmcore/utf8.c new file mode 100644 index 000000000..46a0c7e16 --- /dev/null +++ b/src/vmcore/utf8.c @@ -0,0 +1,1867 @@ +/* src/vmcore/utf8.c - utf8 string functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#else +# include "threads/none/lock.h" +#endif + +#include "toolbox/hashtable.h" + +#include "vm/exceptions.h" + +#include "vmcore/options.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + +#include "vmcore/utf8.h" + + +/* global variables ***********************************************************/ + +/* hashsize must be power of 2 */ + +#define HASHTABLE_UTF_SIZE 16384 /* initial size of utf-hash */ + +hashtable *hashtable_utf; /* hashtable for utf8-symbols */ + + +/* utf-symbols for pointer comparison of frequently used strings **************/ + +utf *utf_java_lang_Object; + +utf *utf_java_lang_Class; +utf *utf_java_lang_ClassLoader; +utf *utf_java_lang_Cloneable; +utf *utf_java_lang_SecurityManager; +utf *utf_java_lang_String; +utf *utf_java_lang_System; +utf *utf_java_lang_ThreadGroup; +utf *utf_java_io_Serializable; + +utf *utf_java_lang_Throwable; +utf *utf_java_lang_Error; +utf *utf_java_lang_ClassCircularityError; +utf *utf_java_lang_ClassFormatError; +utf *utf_java_lang_ExceptionInInitializerError; +utf *utf_java_lang_IncompatibleClassChangeError; +utf *utf_java_lang_InstantiationError; +utf *utf_java_lang_InternalError; +utf *utf_java_lang_LinkageError; +utf *utf_java_lang_NoClassDefFoundError; +utf *utf_java_lang_OutOfMemoryError; +utf *utf_java_lang_UnsatisfiedLinkError; +utf *utf_java_lang_UnsupportedClassVersionError; +utf *utf_java_lang_VerifyError; +utf *utf_java_lang_VirtualMachineError; + +#if defined(ENABLE_JAVASE) +utf *utf_java_lang_AbstractMethodError; +utf *utf_java_lang_NoSuchFieldError; +utf *utf_java_lang_NoSuchMethodError; +#endif + +#if defined(WITH_CLASSPATH_GNU) +utf *utf_java_lang_VMThrowable; +#endif + +utf *utf_java_lang_Exception; +utf *utf_java_lang_ArithmeticException; +utf *utf_java_lang_ArrayIndexOutOfBoundsException; +utf *utf_java_lang_ArrayStoreException; +utf *utf_java_lang_ClassCastException; +utf *utf_java_lang_ClassNotFoundException; +utf *utf_java_lang_CloneNotSupportedException; +utf *utf_java_lang_IllegalAccessException; +utf *utf_java_lang_IllegalArgumentException; +utf *utf_java_lang_IllegalMonitorStateException; +utf *utf_java_lang_InstantiationException; +utf *utf_java_lang_InterruptedException; +utf *utf_java_lang_InvocationTargetException; +utf *utf_java_lang_NegativeArraySizeException; +utf *utf_java_lang_NullPointerException; +utf *utf_java_lang_StringIndexOutOfBoundsException; + +#if defined(ENABLE_JAVASE) +utf* utf_java_lang_Void; +#endif + +utf* utf_java_lang_Boolean; +utf* utf_java_lang_Byte; +utf* utf_java_lang_Character; +utf* utf_java_lang_Short; +utf* utf_java_lang_Integer; +utf* utf_java_lang_Long; +utf* utf_java_lang_Float; +utf* utf_java_lang_Double; + +#if defined(ENABLE_JAVASE) +utf *utf_java_lang_StackTraceElement; +utf *utf_java_lang_reflect_Constructor; +utf *utf_java_lang_reflect_Field; +utf *utf_java_lang_reflect_Method; +utf *utf_java_util_Vector; +#endif + +utf *utf_InnerClasses; /* InnerClasses */ +utf *utf_ConstantValue; /* ConstantValue */ +utf *utf_Code; /* Code */ +utf *utf_Exceptions; /* Exceptions */ +utf *utf_LineNumberTable; /* LineNumberTable */ +utf *utf_SourceFile; /* SourceFile */ + +#if defined(ENABLE_JAVASE) +utf *utf_EnclosingMethod; +utf *utf_Signature; +utf *utf_RuntimeVisibleAnnotations; +utf *utf_StackMapTable; +#endif + +utf *utf_init; /* */ +utf *utf_clinit; /* */ +utf *utf_clone; /* clone */ +utf *utf_finalize; /* finalize */ +utf *utf_run; /* run */ + +utf *utf_add; +utf *utf_remove; +utf *utf_addThread; +utf *utf_removeThread; +utf *utf_put; +utf *utf_get; +utf *utf_value; + +utf *utf_fillInStackTrace; +utf *utf_getSystemClassLoader; +utf *utf_loadClass; +utf *utf_printStackTrace; + +utf *utf_Z; /* Z */ +utf *utf_B; /* B */ +utf *utf_C; /* C */ +utf *utf_S; /* S */ +utf *utf_I; /* I */ +utf *utf_J; /* J */ +utf *utf_F; /* F */ +utf *utf_D; /* D */ + +utf *utf_void__void; /* ()V */ +utf *utf_boolean__void; /* (Z)V */ +utf *utf_byte__void; /* (B)V */ +utf *utf_char__void; /* (C)V */ +utf *utf_short__void; /* (S)V */ +utf *utf_int__void; /* (I)V */ +utf *utf_long__void; /* (J)V */ +utf *utf_float__void; /* (F)V */ +utf *utf_double__void; /* (D)V */ + +utf *utf_void__java_lang_ClassLoader; /* ()Ljava/lang/ClassLoader; */ +utf *utf_void__java_lang_Object; /* ()Ljava/lang/Object; */ +utf *utf_void__java_lang_Throwable; /* ()Ljava/lang/Throwable; */ +utf *utf_java_lang_Object__java_lang_Object; +utf *utf_java_lang_String__void; /* (Ljava/lang/String;)V */ +utf *utf_java_lang_String__java_lang_Class; +utf *utf_java_lang_Thread__V; /* (Ljava/lang/Thread;)V */ +utf *utf_java_lang_Throwable__void; /* (Ljava/lang/Throwable;)V */ + +utf *utf_not_named_yet; /* special name for unnamed classes */ +utf *utf_null; +utf *array_packagename; + + +/* utf_init ******************************************************************** + + Initializes the utf8 subsystem. + +*******************************************************************************/ + +bool utf8_init(void) +{ + /* create utf8 hashtable */ + + hashtable_utf = NEW(hashtable); + + hashtable_create(hashtable_utf, HASHTABLE_UTF_SIZE); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_utf_len += sizeof(utf*) * hashtable_utf->size; +#endif + + /* create utf-symbols for pointer comparison of frequently used strings */ + + utf_java_lang_Object = utf_new_char("java/lang/Object"); + + utf_java_lang_Class = utf_new_char("java/lang/Class"); + utf_java_lang_ClassLoader = utf_new_char("java/lang/ClassLoader"); + utf_java_lang_Cloneable = utf_new_char("java/lang/Cloneable"); + utf_java_lang_SecurityManager = utf_new_char("java/lang/SecurityManager"); + utf_java_lang_String = utf_new_char("java/lang/String"); + utf_java_lang_System = utf_new_char("java/lang/System"); + utf_java_lang_ThreadGroup = utf_new_char("java/lang/ThreadGroup"); + utf_java_io_Serializable = utf_new_char("java/io/Serializable"); + + utf_java_lang_Throwable = utf_new_char("java/lang/Throwable"); + utf_java_lang_Error = utf_new_char("java/lang/Error"); + + utf_java_lang_ClassCircularityError = + utf_new_char("java/lang/ClassCircularityError"); + + utf_java_lang_ClassFormatError = utf_new_char("java/lang/ClassFormatError"); + + utf_java_lang_ExceptionInInitializerError = + utf_new_char("java/lang/ExceptionInInitializerError"); + + utf_java_lang_IncompatibleClassChangeError = + utf_new_char("java/lang/IncompatibleClassChangeError"); + + utf_java_lang_InstantiationError = + utf_new_char("java/lang/InstantiationError"); + + utf_java_lang_InternalError = utf_new_char("java/lang/InternalError"); + utf_java_lang_LinkageError = utf_new_char("java/lang/LinkageError"); + + utf_java_lang_NoClassDefFoundError = + utf_new_char("java/lang/NoClassDefFoundError"); + + utf_java_lang_OutOfMemoryError = utf_new_char("java/lang/OutOfMemoryError"); + + utf_java_lang_UnsatisfiedLinkError = + utf_new_char("java/lang/UnsatisfiedLinkError"); + + utf_java_lang_UnsupportedClassVersionError = + utf_new_char("java/lang/UnsupportedClassVersionError"); + + utf_java_lang_VerifyError = utf_new_char("java/lang/VerifyError"); + + utf_java_lang_VirtualMachineError = + utf_new_char("java/lang/VirtualMachineError"); + +#if defined(ENABLE_JAVASE) + utf_java_lang_AbstractMethodError = + utf_new_char("java/lang/AbstractMethodError"); + + utf_java_lang_NoSuchFieldError = + utf_new_char("java/lang/NoSuchFieldError"); + + utf_java_lang_NoSuchMethodError = + utf_new_char("java/lang/NoSuchMethodError"); +#endif + +#if defined(WITH_CLASSPATH_GNU) + utf_java_lang_VMThrowable = utf_new_char("java/lang/VMThrowable"); +#endif + + utf_java_lang_Exception = utf_new_char("java/lang/Exception"); + + utf_java_lang_ArithmeticException = + utf_new_char("java/lang/ArithmeticException"); + + utf_java_lang_ArrayIndexOutOfBoundsException = + utf_new_char("java/lang/ArrayIndexOutOfBoundsException"); + + utf_java_lang_ArrayStoreException = + utf_new_char("java/lang/ArrayStoreException"); + + utf_java_lang_ClassCastException = + utf_new_char("java/lang/ClassCastException"); + + utf_java_lang_ClassNotFoundException = + utf_new_char("java/lang/ClassNotFoundException"); + + utf_java_lang_CloneNotSupportedException = + utf_new_char("java/lang/CloneNotSupportedException"); + + utf_java_lang_IllegalAccessException = + utf_new_char("java/lang/IllegalAccessException"); + + utf_java_lang_IllegalArgumentException = + utf_new_char("java/lang/IllegalArgumentException"); + + utf_java_lang_IllegalMonitorStateException = + utf_new_char("java/lang/IllegalMonitorStateException"); + + utf_java_lang_InstantiationException = + utf_new_char("java/lang/InstantiationException"); + + utf_java_lang_InterruptedException = + utf_new_char("java/lang/InterruptedException"); + + utf_java_lang_InvocationTargetException = + utf_new_char("java/lang/InvocationTargetException"); + + utf_java_lang_NegativeArraySizeException = + utf_new_char("java/lang/NegativeArraySizeException"); + + utf_java_lang_NullPointerException = + utf_new_char("java/lang/NullPointerException"); + + utf_java_lang_StringIndexOutOfBoundsException = + utf_new_char("java/lang/StringIndexOutOfBoundsException"); + +#if defined(ENABLE_JAVASE) + utf_java_lang_Void = utf_new_char("java/lang/Void"); +#endif + + utf_java_lang_Boolean = utf_new_char("java/lang/Boolean"); + utf_java_lang_Byte = utf_new_char("java/lang/Byte"); + utf_java_lang_Character = utf_new_char("java/lang/Character"); + utf_java_lang_Short = utf_new_char("java/lang/Short"); + utf_java_lang_Integer = utf_new_char("java/lang/Integer"); + utf_java_lang_Long = utf_new_char("java/lang/Long"); + utf_java_lang_Float = utf_new_char("java/lang/Float"); + utf_java_lang_Double = utf_new_char("java/lang/Double"); + +#if defined(ENABLE_JAVASE) + utf_java_lang_StackTraceElement = + utf_new_char("java/lang/StackTraceElement"); + + utf_java_lang_reflect_Constructor = + utf_new_char("java/lang/reflect/Constructor"); + + utf_java_lang_reflect_Field = utf_new_char("java/lang/reflect/Field"); + utf_java_lang_reflect_Method = utf_new_char("java/lang/reflect/Method"); + utf_java_util_Vector = utf_new_char("java/util/Vector"); +#endif + + utf_InnerClasses = utf_new_char("InnerClasses"); + utf_ConstantValue = utf_new_char("ConstantValue"); + utf_Code = utf_new_char("Code"); + utf_Exceptions = utf_new_char("Exceptions"); + utf_LineNumberTable = utf_new_char("LineNumberTable"); + utf_SourceFile = utf_new_char("SourceFile"); + +#if defined(ENABLE_JAVASE) + utf_EnclosingMethod = utf_new_char("EnclosingMethod"); + utf_Signature = utf_new_char("Signature"); + utf_RuntimeVisibleAnnotations = utf_new_char("RuntimeVisibleAnnotations"); + utf_StackMapTable = utf_new_char("StackMapTable"); +#endif + + utf_init = utf_new_char(""); + utf_clinit = utf_new_char(""); + utf_clone = utf_new_char("clone"); + utf_finalize = utf_new_char("finalize"); + utf_run = utf_new_char("run"); + + utf_add = utf_new_char("add"); + utf_remove = utf_new_char("remove"); + utf_addThread = utf_new_char("addThread"); + utf_removeThread = utf_new_char("removeThread"); + utf_put = utf_new_char("put"); + utf_get = utf_new_char("get"); + utf_value = utf_new_char("value"); + + utf_printStackTrace = utf_new_char("printStackTrace"); + utf_fillInStackTrace = utf_new_char("fillInStackTrace"); + utf_loadClass = utf_new_char("loadClass"); + utf_getSystemClassLoader = utf_new_char("getSystemClassLoader"); + + utf_Z = utf_new_char("Z"); + utf_B = utf_new_char("B"); + utf_C = utf_new_char("C"); + utf_S = utf_new_char("S"); + utf_I = utf_new_char("I"); + utf_J = utf_new_char("J"); + utf_F = utf_new_char("F"); + utf_D = utf_new_char("D"); + + utf_void__void = utf_new_char("()V"); + utf_boolean__void = utf_new_char("(Z)V"); + utf_byte__void = utf_new_char("(B)V"); + utf_char__void = utf_new_char("(C)V"); + utf_short__void = utf_new_char("(S)V"); + utf_int__void = utf_new_char("(I)V"); + utf_long__void = utf_new_char("(J)V"); + utf_float__void = utf_new_char("(F)V"); + utf_double__void = utf_new_char("(D)V"); + utf_void__java_lang_Object = utf_new_char("()Ljava/lang/Object;"); + utf_void__java_lang_Throwable = utf_new_char("()Ljava/lang/Throwable;"); + + utf_void__java_lang_ClassLoader = + utf_new_char("()Ljava/lang/ClassLoader;"); + + utf_java_lang_Object__java_lang_Object = + utf_new_char("(Ljava/lang/Object;)Ljava/lang/Object;"); + + utf_java_lang_String__void = utf_new_char("(Ljava/lang/String;)V"); + + utf_java_lang_String__java_lang_Class = + utf_new_char("(Ljava/lang/String;)Ljava/lang/Class;"); + + utf_java_lang_Thread__V = utf_new_char("(Ljava/lang/Thread;)V"); + utf_java_lang_Throwable__void = utf_new_char("(Ljava/lang/Throwable;)V"); + + utf_null = utf_new_char("null"); + utf_not_named_yet = utf_new_char("\t"); + array_packagename = utf_new_char("\t"); + + /* everything's ok */ + + return true; +} + + +/* utf_hashkey ***************************************************************** + + The hashkey is computed from the utf-text by using up to 8 + characters. For utf-symbols longer than 15 characters 3 characters + are taken from the beginning and the end, 2 characters are taken + from the middle. + +*******************************************************************************/ + +#define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val */ +#define fbs(val) ((u4) *( text) << val) /* get first byte, left shift by val */ + +u4 utf_hashkey(const char *text, u4 length) +{ + const char *start_pos = text; /* pointer to utf text */ + u4 a; + + switch (length) { + case 0: /* empty string */ + return 0; + + case 1: return fbs(0); + case 2: return fbs(0) ^ nbs(3); + case 3: return fbs(0) ^ nbs(3) ^ nbs(5); + case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6); + case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6); + case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6); + case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6); + case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7); + + case 9: + a = fbs(0); + a ^= nbs(1); + a ^= nbs(2); + text++; + return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8); + + case 10: + a = fbs(0); + text++; + a ^= nbs(2); + a ^= nbs(3); + a ^= nbs(4); + text++; + return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9); + + case 11: + a = fbs(0); + text++; + a ^= nbs(2); + a ^= nbs(3); + a ^= nbs(4); + text++; + return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10); + + case 12: + a = fbs(0); + text += 2; + a ^= nbs(2); + a ^= nbs(3); + text++; + a ^= nbs(5); + a ^= nbs(6); + a ^= nbs(7); + text++; + return a ^ nbs(9) ^ nbs(10); + + case 13: + a = fbs(0); + a ^= nbs(1); + text++; + a ^= nbs(3); + a ^= nbs(4); + text += 2; + a ^= nbs(7); + a ^= nbs(8); + text += 2; + return a ^ nbs(9) ^ nbs(10); + + case 14: + a = fbs(0); + text += 2; + a ^= nbs(3); + a ^= nbs(4); + text += 2; + a ^= nbs(7); + a ^= nbs(8); + text += 2; + return a ^ nbs(9) ^ nbs(10) ^ nbs(11); + + case 15: + a = fbs(0); + text += 2; + a ^= nbs(3); + a ^= nbs(4); + text += 2; + a ^= nbs(7); + a ^= nbs(8); + text += 2; + return a ^ nbs(9) ^ nbs(10) ^ nbs(11); + + default: /* 3 characters from beginning */ + a = fbs(0); + text += 2; + a ^= nbs(3); + a ^= nbs(4); + + /* 2 characters from middle */ + text = start_pos + (length / 2); + a ^= fbs(5); + text += 2; + a ^= nbs(6); + + /* 3 characters from end */ + text = start_pos + length - 4; + + a ^= fbs(7); + text++; + + return a ^ nbs(10) ^ nbs(11); + } +} + +/* utf_full_hashkey ************************************************************ + + This function computes a hash value using all bytes in the string. + + The algorithm is the "One-at-a-time" algorithm as published + by Bob Jenkins on http://burtleburtle.net/bob/hash/doobs.html. + +*******************************************************************************/ + +u4 utf_full_hashkey(const char *text, u4 length) +{ + register const unsigned char *p = (const unsigned char *) text; + register u4 hash; + register u4 i; + + hash = 0; + for (i=length; i--;) + { + hash += *p++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} + +/* unicode_hashkey ************************************************************* + + Compute the hashkey of a unicode string. + +*******************************************************************************/ + +u4 unicode_hashkey(u2 *text, u2 len) +{ + return utf_hashkey((char *) text, len); +} + + +/* utf_new ********************************************************************* + + Creates a new utf-symbol, the text of the symbol is passed as a + u1-array. The function searches the utf-hashtable for a utf-symbol + with this text. On success the element returned, otherwise a new + hashtable element is created. + + If the number of entries in the hashtable exceeds twice the size of + the hashtable slots a reorganization of the hashtable is done and + the utf symbols are copied to a new hashtable with doubled size. + +*******************************************************************************/ + +utf *utf_new(const char *text, u2 length) +{ + u4 key; /* hashkey computed from utf-text */ + u4 slot; /* slot in hashtable */ + utf *u; /* hashtable element */ + u2 i; + + LOCK_MONITOR_ENTER(hashtable_utf->header); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_utf_new++; +#endif + + key = utf_hashkey(text, length); + slot = key & (hashtable_utf->size - 1); + u = hashtable_utf->ptr[slot]; + + /* search external hash chain for utf-symbol */ + + while (u) { + if (u->blength == length) { + /* compare text of hashtable elements */ + + for (i = 0; i < length; i++) + if (text[i] != u->text[i]) + goto nomatch; + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_utf_new_found++; +#endif + + /* symbol found in hashtable */ + + LOCK_MONITOR_EXIT(hashtable_utf->header); + + return u; + } + + nomatch: + u = u->hashlink; /* next element in external chain */ + } + + /* location in hashtable found, create new utf element */ + + u = NEW(utf); + + u->blength = length; /* length in bytes of utfstring */ + u->hashlink = hashtable_utf->ptr[slot]; /* link in external hashchain */ + u->text = mem_alloc(length + 1);/* allocate memory for utf-text */ + + memcpy(u->text, text, length); /* copy utf-text */ + u->text[length] = '\0'; + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_utf_len += sizeof(utf) + length + 1; +#endif + + hashtable_utf->ptr[slot] = u; /* insert symbol into table */ + hashtable_utf->entries++; /* update number of entries */ + + if (hashtable_utf->entries > (hashtable_utf->size * 2)) { + + /* reorganization of hashtable, average length of the external + chains is approx. 2 */ + + hashtable *newhash; /* the new hashtable */ + u4 i; + utf *u; + utf *nextu; + u4 slot; + + /* create new hashtable, double the size */ + + newhash = hashtable_resize(hashtable_utf, hashtable_utf->size * 2); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_utf_len += sizeof(utf*) * hashtable_utf->size; +#endif + + /* transfer elements to new hashtable */ + + for (i = 0; i < hashtable_utf->size; i++) { + u = hashtable_utf->ptr[i]; + + while (u) { + nextu = u->hashlink; + slot = utf_hashkey(u->text, u->blength) & (newhash->size - 1); + + u->hashlink = (utf *) newhash->ptr[slot]; + newhash->ptr[slot] = u; + + /* follow link in external hash chain */ + + u = nextu; + } + } + + /* dispose old table */ + + hashtable_free(hashtable_utf); + + hashtable_utf = newhash; + } + + LOCK_MONITOR_EXIT(hashtable_utf->header); + + return u; +} + + +/* utf_new_u2 ****************************************************************** + + Make utf symbol from u2 array, if isclassname is true '.' is + replaced by '/'. + +*******************************************************************************/ + +utf *utf_new_u2(u2 *unicode_pos, u4 unicode_length, bool isclassname) +{ + char *buffer; /* memory buffer for unicode characters */ + char *pos; /* pointer to current position in buffer */ + u4 left; /* unicode characters left */ + u4 buflength; /* utf length in bytes of the u2 array */ + utf *result; /* resulting utf-string */ + int i; + + /* determine utf length in bytes and allocate memory */ + + buflength = u2_utflength(unicode_pos, unicode_length); + buffer = MNEW(char, buflength); + + left = buflength; + pos = buffer; + + for (i = 0; i++ < unicode_length; unicode_pos++) { + /* next unicode character */ + u2 c = *unicode_pos; + + if ((c != 0) && (c < 0x80)) { + /* 1 character */ + left--; + if ((int) left < 0) break; + /* convert classname */ + if (isclassname && c == '.') + *pos++ = '/'; + else + *pos++ = (char) c; + + } else if (c < 0x800) { + /* 2 characters */ + unsigned char high = c >> 6; + unsigned char low = c & 0x3F; + left = left - 2; + if ((int) left < 0) break; + *pos++ = high | 0xC0; + *pos++ = low | 0x80; + + } else { + /* 3 characters */ + char low = c & 0x3f; + char mid = (c >> 6) & 0x3F; + char high = c >> 12; + left = left - 3; + if ((int) left < 0) break; + *pos++ = high | 0xE0; + *pos++ = mid | 0x80; + *pos++ = low | 0x80; + } + } + + /* insert utf-string into symbol-table */ + result = utf_new(buffer,buflength); + + MFREE(buffer, char, buflength); + + return result; +} + + +/* utf_new_char **************************************************************** + + Creates a new utf symbol, the text for this symbol is passed as a + c-string ( = char* ). + +*******************************************************************************/ + +utf *utf_new_char(const char *text) +{ + return utf_new(text, strlen(text)); +} + + +/* utf_new_char_classname ****************************************************** + + Creates a new utf symbol, the text for this symbol is passed as a + c-string ( = char* ) "." characters are going to be replaced by + "/". Since the above function is used often, this is a separte + function, instead of an if. + +*******************************************************************************/ + +utf *utf_new_char_classname(const char *text) +{ + if (strchr(text, '.')) { + char *txt = strdup(text); + char *end = txt + strlen(txt); + char *c; + utf *tmpRes; + + for (c = txt; c < end; c++) + if (*c == '.') *c = '/'; + + tmpRes = utf_new(txt, strlen(txt)); + FREE(txt, 0); + + return tmpRes; + + } else + return utf_new(text, strlen(text)); +} + + +/* utf_nextu2 ****************************************************************** + + Read the next unicode character from the utf string and increment + the utf-string pointer accordingly. + + CAUTION: This function is unsafe for input that was not checked + by is_valid_utf! + +*******************************************************************************/ + +u2 utf_nextu2(char **utf_ptr) +{ + /* uncompressed unicode character */ + u2 unicode_char = 0; + /* current position in utf text */ + unsigned char *utf = (unsigned char *) (*utf_ptr); + /* bytes representing the unicode character */ + unsigned char ch1, ch2, ch3; + /* number of bytes used to represent the unicode character */ + int len = 0; + + switch ((ch1 = utf[0]) >> 4) { + default: /* 1 byte */ + (*utf_ptr)++; + return (u2) ch1; + case 0xC: + case 0xD: /* 2 bytes */ + if (((ch2 = utf[1]) & 0xC0) == 0x80) { + unsigned char high = ch1 & 0x1F; + unsigned char low = ch2 & 0x3F; + unicode_char = (high << 6) + low; + len = 2; + } + break; + + case 0xE: /* 2 or 3 bytes */ + if (((ch2 = utf[1]) & 0xC0) == 0x80) { + if (((ch3 = utf[2]) & 0xC0) == 0x80) { + unsigned char low = ch3 & 0x3f; + unsigned char mid = ch2 & 0x3f; + unsigned char high = ch1 & 0x0f; + unicode_char = (((high << 6) + mid) << 6) + low; + len = 3; + } else + len = 2; + } + break; + } + + /* update position in utf-text */ + *utf_ptr = (char *) (utf + len); + + return unicode_char; +} + + +/* utf_bytes ******************************************************************* + + Determine number of bytes (aka. octets) in the utf string. + + IN: + u............utf string + + OUT: + The number of octets of this utf string. + There is _no_ terminating zero included in this count. + +*******************************************************************************/ + +u4 utf_bytes(utf *u) +{ + return u->blength; +} + + +/* utf_get_number_of_u2s_for_buffer ******************************************** + + Determine number of UTF-16 u2s in the given UTF-8 buffer + + CAUTION: This function is unsafe for input that was not checked + by is_valid_utf! + + CAUTION: Use this function *only* when you want to convert an UTF-8 buffer + to an array of u2s (UTF-16) and want to know how many of them you will get. + All other uses of this function are probably wrong. + + IN: + buffer........points to first char in buffer + blength.......number of _bytes_ in the buffer + + OUT: + the number of u2s needed to hold this string in UTF-16 encoding. + There is _no_ terminating zero included in this count. + + NOTE: Unlike utf_get_number_of_u2s, this function never throws an + exception. + +*******************************************************************************/ + +u4 utf_get_number_of_u2s_for_buffer(const char *buffer, u4 blength) +{ + const char *endpos; /* points behind utf string */ + const char *utf_ptr; /* current position in utf text */ + u4 len = 0; /* number of unicode characters */ + + utf_ptr = buffer; + endpos = utf_ptr + blength; + + while (utf_ptr < endpos) { + len++; + /* next unicode character */ + utf_nextu2((char **)&utf_ptr); + } + + assert(utf_ptr == endpos); + + return len; +} + + +/* utf_get_number_of_u2s ******************************************************* + + Determine number of UTF-16 u2s in the utf string. + + CAUTION: This function is unsafe for input that was not checked + by is_valid_utf! + + CAUTION: Use this function *only* when you want to convert a utf string + to an array of u2s and want to know how many of them you will get. + All other uses of this function are probably wrong. + + IN: + u............utf string + + OUT: + the number of u2s needed to hold this string in UTF-16 encoding. + There is _no_ terminating zero included in this count. + XXX 0 if a NullPointerException has been thrown (see below) + +*******************************************************************************/ + +u4 utf_get_number_of_u2s(utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + u4 len = 0; /* number of unicode characters */ + + /* XXX this is probably not checked by most callers! Review this after */ + /* the invalid uses of this function have been eliminated */ + if (u == NULL) { + exceptions_throw_nullpointerexception(); + return 0; + } + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + len++; + /* next unicode character */ + utf_nextu2(&utf_ptr); + } + + if (utf_ptr != endpos) { + /* string ended abruptly */ + exceptions_throw_internalerror("Illegal utf8 string"); + return NULL; + } + + return len; +} + + +/* utf8_safe_number_of_u2s ***************************************************** + + Determine number of UTF-16 u2s needed for decoding the given UTF-8 string. + (For invalid UTF-8 the U+fffd replacement character will be counted.) + + This function is safe even for invalid UTF-8 strings. + + IN: + text..........zero-terminated(!) UTF-8 string (may be invalid) + must NOT be NULL + nbytes........strlen(text). (This is needed to completely emulate + the RI). + + OUT: + the number of u2s needed to hold this string in UTF-16 encoding. + There is _no_ terminating zero included in this count. + +*******************************************************************************/ + +s4 utf8_safe_number_of_u2s(const char *text, s4 nbytes) { + register const unsigned char *t; + register s4 byte; + register s4 len; + register const unsigned char *tlimit; + s4 byte1; + s4 byte2; + s4 byte3; + s4 value; + s4 skip; + + assert(text); + assert(nbytes >= 0); + + len = 0; + t = (const unsigned char *) text; + tlimit = t + nbytes; + + /* CAUTION: Keep this code in sync with utf8_safe_convert_to_u2s! */ + + while (1) { + byte = *t++; + + if (byte & 0x80) { + /* highest bit set, non-ASCII character */ + + if ((byte & 0xe0) == 0xc0) { + /* 2-byte: should be 110..... 10...... ? */ + + if ((*t++ & 0xc0) == 0x80) + ; /* valid 2-byte */ + else + t--; /* invalid */ + } + else if ((byte & 0xf0) == 0xe0) { + /* 3-byte: should be 1110.... 10...... 10...... */ + /* ^t */ + + if (t + 2 > tlimit) + return len + 1; /* invalid, stop here */ + + if ((*t++ & 0xc0) == 0x80) { + if ((*t++ & 0xc0) == 0x80) + ; /* valid 3-byte */ + else + t--; /* invalid */ + } + else + t--; /* invalid */ + } + else if ((byte & 0xf8) == 0xf0) { + /* 4-byte: should be 11110... 10...... 10...... 10...... */ + /* ^t */ + + if (t + 3 > tlimit) + return len + 1; /* invalid, stop here */ + + if (((byte1 = *t++) & 0xc0) == 0x80) { + if (((byte2 = *t++) & 0xc0) == 0x80) { + if (((byte3 = *t++) & 0xc0) == 0x80) { + /* valid 4-byte UTF-8? */ + value = ((byte & 0x07) << 18) + | ((byte1 & 0x3f) << 12) + | ((byte2 & 0x3f) << 6) + | ((byte3 & 0x3f) ); + + if (value > 0x10FFFF) + ; /* invalid */ + else if (value > 0xFFFF) + len += 1; /* we need surrogates */ + else + ; /* 16bit suffice */ + } + else + t--; /* invalid */ + } + else + t--; /* invalid */ + } + else + t--; /* invalid */ + } + else if ((byte & 0xfc) == 0xf8) { + /* invalid 5-byte */ + if (t + 4 > tlimit) + return len + 1; /* invalid, stop here */ + + skip = 4; + for (; skip && ((*t & 0xc0) == 0x80); --skip) + t++; + } + else if ((byte & 0xfe) == 0xfc) { + /* invalid 6-byte */ + if (t + 5 > tlimit) + return len + 1; /* invalid, stop here */ + + skip = 5; + for (; skip && ((*t & 0xc0) == 0x80); --skip) + t++; + } + else + ; /* invalid */ + } + else { + /* NUL */ + + if (byte == 0) + break; + + /* ASCII character, common case */ + } + + len++; + } + + return len; +} + + +/* utf8_safe_convert_to_u2s **************************************************** + + Convert the given UTF-8 string to UTF-16 into a pre-allocated buffer. + (Invalid UTF-8 will be replaced with the U+fffd replacement character.) + Use utf8_safe_number_of_u2s to determine the number of u2s to allocate. + + This function is safe even for invalid UTF-8 strings. + + IN: + text..........zero-terminated(!) UTF-8 string (may be invalid) + must NOT be NULL + nbytes........strlen(text). (This is needed to completely emulate + the RI). + buffer........a preallocated array of u2s to receive the decoded + string. Use utf8_safe_number_of_u2s to get the + required number of u2s for allocating this. + +*******************************************************************************/ + +#define UNICODE_REPLACEMENT 0xfffd + +void utf8_safe_convert_to_u2s(const char *text, s4 nbytes, u2 *buffer) { + register const unsigned char *t; + register s4 byte; + register const unsigned char *tlimit; + s4 byte1; + s4 byte2; + s4 byte3; + s4 value; + s4 skip; + + assert(text); + assert(nbytes >= 0); + + t = (const unsigned char *) text; + tlimit = t + nbytes; + + /* CAUTION: Keep this code in sync with utf8_safe_number_of_u2s! */ + + while (1) { + byte = *t++; + + if (byte & 0x80) { + /* highest bit set, non-ASCII character */ + + if ((byte & 0xe0) == 0xc0) { + /* 2-byte: should be 110..... 10...... */ + + if (((byte1 = *t++) & 0xc0) == 0x80) { + /* valid 2-byte UTF-8 */ + *buffer++ = ((byte & 0x1f) << 6) + | ((byte1 & 0x3f) ); + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else if ((byte & 0xf0) == 0xe0) { + /* 3-byte: should be 1110.... 10...... 10...... */ + + if (t + 2 > tlimit) { + *buffer++ = UNICODE_REPLACEMENT; + return; + } + + if (((byte1 = *t++) & 0xc0) == 0x80) { + if (((byte2 = *t++) & 0xc0) == 0x80) { + /* valid 3-byte UTF-8 */ + *buffer++ = ((byte & 0x0f) << 12) + | ((byte1 & 0x3f) << 6) + | ((byte2 & 0x3f) ); + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else if ((byte & 0xf8) == 0xf0) { + /* 4-byte: should be 11110... 10...... 10...... 10...... */ + + if (t + 3 > tlimit) { + *buffer++ = UNICODE_REPLACEMENT; + return; + } + + if (((byte1 = *t++) & 0xc0) == 0x80) { + if (((byte2 = *t++) & 0xc0) == 0x80) { + if (((byte3 = *t++) & 0xc0) == 0x80) { + /* valid 4-byte UTF-8? */ + value = ((byte & 0x07) << 18) + | ((byte1 & 0x3f) << 12) + | ((byte2 & 0x3f) << 6) + | ((byte3 & 0x3f) ); + + if (value > 0x10FFFF) { + *buffer++ = UNICODE_REPLACEMENT; + } + else if (value > 0xFFFF) { + /* we need surrogates */ + *buffer++ = 0xd800 | ((value >> 10) - 0x40); + *buffer++ = 0xdc00 | (value & 0x03ff); + } + else + *buffer++ = value; /* 16bit suffice */ + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else { + *buffer++ = UNICODE_REPLACEMENT; + t--; + } + } + else if ((byte & 0xfc) == 0xf8) { + if (t + 4 > tlimit) { + *buffer++ = UNICODE_REPLACEMENT; + return; + } + + skip = 4; + for (; skip && ((*t & 0xc0) == 0x80); --skip) + t++; + *buffer++ = UNICODE_REPLACEMENT; + } + else if ((byte & 0xfe) == 0xfc) { + if (t + 5 > tlimit) { + *buffer++ = UNICODE_REPLACEMENT; + return; + } + + skip = 5; + for (; skip && ((*t & 0xc0) == 0x80); --skip) + t++; + *buffer++ = UNICODE_REPLACEMENT; + } + else + *buffer++ = UNICODE_REPLACEMENT; + } + else { + /* NUL */ + + if (byte == 0) + break; + + /* ASCII character, common case */ + + *buffer++ = byte; + } + } +} + + +/* u2_utflength **************************************************************** + + Returns the utf length in bytes of a u2 array. + +*******************************************************************************/ + +u4 u2_utflength(u2 *text, u4 u2_length) +{ + u4 result_len = 0; /* utf length in bytes */ + u2 ch; /* current unicode character */ + u4 len; + + for (len = 0; len < u2_length; len++) { + /* next unicode character */ + ch = *text++; + + /* determine bytes required to store unicode character as utf */ + if (ch && (ch < 0x80)) + result_len++; + else if (ch < 0x800) + result_len += 2; + else + result_len += 3; + } + + return result_len; +} + + +/* utf_copy ******************************************************************** + + Copy the given utf string byte-for-byte to a buffer. + + IN: + buffer.......the buffer + u............the utf string + +*******************************************************************************/ + +void utf_copy(char *buffer, utf *u) +{ + /* our utf strings are zero-terminated (done by utf_new) */ + MCOPY(buffer, u->text, char, u->blength + 1); +} + + +/* utf_cat ********************************************************************* + + Append the given utf string byte-for-byte to a buffer. + + IN: + buffer.......the buffer + u............the utf string + +*******************************************************************************/ + +void utf_cat(char *buffer, utf *u) +{ + /* our utf strings are zero-terminated (done by utf_new) */ + MCOPY(buffer + strlen(buffer), u->text, char, u->blength + 1); +} + + +/* utf_copy_classname ********************************************************** + + Copy the given utf classname byte-for-byte to a buffer. + '/' is replaced by '.' + + IN: + buffer.......the buffer + u............the utf string + +*******************************************************************************/ + +void utf_copy_classname(char *buffer, utf *u) +{ + char *bufptr; + char *srcptr; + char *endptr; + char ch; + + bufptr = buffer; + srcptr = u->text; + endptr = UTF_END(u) + 1; /* utfs are zero-terminared by utf_new */ + + while (srcptr != endptr) { + ch = *srcptr++; + if (ch == '/') + ch = '.'; + *bufptr++ = ch; + } +} + + +/* utf_cat ********************************************************************* + + Append the given utf classname byte-for-byte to a buffer. + '/' is replaced by '.' + + IN: + buffer.......the buffer + u............the utf string + +*******************************************************************************/ + +void utf_cat_classname(char *buffer, utf *u) +{ + utf_copy_classname(buffer + strlen(buffer), u); +} + +/* utf_display_printable_ascii ************************************************* + + Write utf symbol to stdout (for debugging purposes). + Non-printable and non-ASCII characters are printed as '?'. + +*******************************************************************************/ + +void utf_display_printable_ascii(utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + + if (u == NULL) { + printf("NULL"); + fflush(stdout); + return; + } + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + /* read next unicode character */ + + u2 c = utf_nextu2(&utf_ptr); + + if ((c >= 32) && (c <= 127)) + printf("%c", c); + else + printf("?"); + } + + fflush(stdout); +} + + +/* utf_display_printable_ascii_classname *************************************** + + Write utf symbol to stdout with `/' converted to `.' (for debugging + purposes). + Non-printable and non-ASCII characters are printed as '?'. + +*******************************************************************************/ + +void utf_display_printable_ascii_classname(utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + + if (u == NULL) { + printf("NULL"); + fflush(stdout); + return; + } + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + /* read next unicode character */ + + u2 c = utf_nextu2(&utf_ptr); + + if (c == '/') + c = '.'; + + if ((c >= 32) && (c <= 127)) + printf("%c", c); + else + printf("?"); + } + + fflush(stdout); +} + + +/* utf_sprint_convert_to_latin1 ************************************************ + + Write utf symbol into c-string (for debugging purposes). + Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield + invalid results. + +*******************************************************************************/ + +void utf_sprint_convert_to_latin1(char *buffer, utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + u2 pos = 0; /* position in c-string */ + + if (!u) { + strcpy(buffer, "NULL"); + return; + } + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) + /* copy next unicode character */ + buffer[pos++] = utf_nextu2(&utf_ptr); + + /* terminate string */ + buffer[pos] = '\0'; +} + + +/* utf_sprint_convert_to_latin1_classname ************************************** + + Write utf symbol into c-string with `/' converted to `.' (for debugging + purposes). + Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield + invalid results. + +*******************************************************************************/ + +void utf_sprint_convert_to_latin1_classname(char *buffer, utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + u2 pos = 0; /* position in c-string */ + + if (!u) { + strcpy(buffer, "NULL"); + return; + } + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + /* copy next unicode character */ + u2 c = utf_nextu2(&utf_ptr); + if (c == '/') c = '.'; + buffer[pos++] = c; + } + + /* terminate string */ + buffer[pos] = '\0'; +} + + +/* utf_strcat_convert_to_latin1 ************************************************ + + Like libc strcat, but uses an utf8 string. + Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield + invalid results. + +*******************************************************************************/ + +void utf_strcat_convert_to_latin1(char *buffer, utf *u) +{ + utf_sprint_convert_to_latin1(buffer + strlen(buffer), u); +} + + +/* utf_strcat_convert_to_latin1_classname ************************************** + + Like libc strcat, but uses an utf8 string. + Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield + invalid results. + +*******************************************************************************/ + +void utf_strcat_convert_to_latin1_classname(char *buffer, utf *u) +{ + utf_sprint_convert_to_latin1_classname(buffer + strlen(buffer), u); +} + + +/* utf_fprint_printable_ascii ************************************************** + + Write utf symbol into file. + Non-printable and non-ASCII characters are printed as '?'. + +*******************************************************************************/ + +void utf_fprint_printable_ascii(FILE *file, utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + + if (!u) + return; + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + /* read next unicode character */ + u2 c = utf_nextu2(&utf_ptr); + + if (c >= 32 && c <= 127) fprintf(file, "%c", c); + else fprintf(file, "?"); + } +} + + +/* utf_fprint_printable_ascii_classname **************************************** + + Write utf symbol into file with `/' converted to `.'. + Non-printable and non-ASCII characters are printed as '?'. + +*******************************************************************************/ + +void utf_fprint_printable_ascii_classname(FILE *file, utf *u) +{ + char *endpos; /* points behind utf string */ + char *utf_ptr; /* current position in utf text */ + + if (!u) + return; + + endpos = UTF_END(u); + utf_ptr = u->text; + + while (utf_ptr < endpos) { + /* read next unicode character */ + u2 c = utf_nextu2(&utf_ptr); + if (c == '/') c = '.'; + + if (c >= 32 && c <= 127) fprintf(file, "%c", c); + else fprintf(file, "?"); + } +} + + +/* is_valid_utf **************************************************************** + + Return true if the given string is a valid UTF-8 string. + + utf_ptr...points to first character + end_pos...points after last character + +*******************************************************************************/ + +/* static unsigned long min_codepoint[6] = {0,1L<<7,1L<<11,1L<<16,1L<<21,1L<<26}; */ + +bool is_valid_utf(char *utf_ptr, char *end_pos) +{ + int bytes; + int len,i; + char c; + unsigned long v; + + if (end_pos < utf_ptr) return false; + bytes = end_pos - utf_ptr; + while (bytes--) { + c = *utf_ptr++; + + if (!c) return false; /* 0x00 is not allowed */ + if ((c & 0x80) == 0) continue; /* ASCII */ + + if ((c & 0xe0) == 0xc0) len = 1; /* 110x xxxx */ + else if ((c & 0xf0) == 0xe0) len = 2; /* 1110 xxxx */ + else if ((c & 0xf8) == 0xf0) len = 3; /* 1111 0xxx */ + else if ((c & 0xfc) == 0xf8) len = 4; /* 1111 10xx */ + else if ((c & 0xfe) == 0xfc) len = 5; /* 1111 110x */ + else return false; /* invalid leading byte */ + + if (len > 2) return false; /* Java limitation */ + + v = (unsigned long)c & (0x3f >> len); + + if ((bytes -= len) < 0) return false; /* missing bytes */ + + for (i = len; i--; ) { + c = *utf_ptr++; + if ((c & 0xc0) != 0x80) /* 10xx xxxx */ + return false; + v = (v << 6) | (c & 0x3f); + } + + if (v == 0) { + if (len != 1) return false; /* Java special */ + + } else { + /* Sun Java seems to allow overlong UTF-8 encodings */ + + /* if (v < min_codepoint[len]) */ + /* XXX throw exception? */ + } + + /* surrogates in UTF-8 seem to be allowed in Java classfiles */ + /* if (v >= 0xd800 && v <= 0xdfff) return false; */ /* surrogates */ + + /* even these seem to be allowed */ + /* if (v == 0xfffe || v == 0xffff) return false; */ /* invalid codepoints */ + } + + return true; +} + + +/* is_valid_name *************************************************************** + + Return true if the given string may be used as a class/field/method + name. (Currently this only disallows empty strings and control + characters.) + + NOTE: The string is assumed to have passed is_valid_utf! + + utf_ptr...points to first character + end_pos...points after last character + +*******************************************************************************/ + +bool is_valid_name(char *utf_ptr, char *end_pos) +{ + if (end_pos <= utf_ptr) return false; /* disallow empty names */ + + while (utf_ptr < end_pos) { + unsigned char c = *utf_ptr++; + + if (c < 0x20) return false; /* disallow control characters */ + if (c == 0xc0 && (unsigned char) *utf_ptr == 0x80) /* disallow zero */ + return false; + } + + return true; +} + +bool is_valid_name_utf(utf *u) +{ + return is_valid_name(u->text, UTF_END(u)); +} + + +/* utf_show ******************************************************************** + + Writes the utf symbols in the utfhash to stdout and displays the + number of external hash chains grouped according to the chainlength + (for debugging purposes). + +*******************************************************************************/ + +#if !defined(NDEBUG) +void utf_show(void) +{ + +#define CHAIN_LIMIT 20 /* limit for seperated enumeration */ + + u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */ + u4 max_chainlength = 0; /* maximum length of the chains */ + u4 sum_chainlength = 0; /* sum of the chainlengths */ + u4 beyond_limit = 0; /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */ + u4 i; + + printf("UTF-HASH:\n"); + + /* show element of utf-hashtable */ + + for (i = 0; i < hashtable_utf->size; i++) { + utf *u = hashtable_utf->ptr[i]; + + if (u) { + printf("SLOT %d: ", (int) i); + + while (u) { + printf("'"); + utf_display_printable_ascii(u); + printf("' "); + u = u->hashlink; + } + printf("\n"); + } + } + + printf("UTF-HASH: %d slots for %d entries\n", + (int) hashtable_utf->size, (int) hashtable_utf->entries ); + + if (hashtable_utf->entries == 0) + return; + + printf("chains:\n chainlength number of chains %% of utfstrings\n"); + + for (i=0;isize; i++) { + + utf *u = (utf*) hashtable_utf->ptr[i]; + u4 chain_length = 0; + + /* determine chainlength */ + while (u) { + u = u->hashlink; + chain_length++; + } + + /* update sum of all chainlengths */ + sum_chainlength+=chain_length; + + /* determine the maximum length of the chains */ + if (chain_length>max_chainlength) + max_chainlength = chain_length; + + /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */ + if (chain_length>=CHAIN_LIMIT) { + beyond_limit+=chain_length; + chain_length=CHAIN_LIMIT-1; + } + + /* update number of hashchains of current length */ + chain_count[chain_length]++; + } + + /* display results */ + for (i=1;ientries)); + + printf(" >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/hashtable_utf->entries); + + + printf("max. chainlength:%5d\n",max_chainlength); + + /* avg. chainlength = sum of chainlengths / number of chains */ + printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (hashtable_utf->size-chain_count[0])); +} +#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: + */ diff --git a/src/vmcore/utf8.h b/src/vmcore/utf8.h new file mode 100644 index 000000000..4e469bd18 --- /dev/null +++ b/src/vmcore/utf8.h @@ -0,0 +1,282 @@ +/* src/vmcore/utf8.h - utf8 string functions + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: utf8.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _UTF_H +#define _UTF_H + +/* forward typedefs ***********************************************************/ + +typedef struct utf utf; + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "vm/global.h" + + +/* data structure for utf8 symbols ********************************************/ + +struct utf { + utf *hashlink; /* link for external hash chain */ + s4 blength; /* text length in bytes */ + char *text; /* pointer to text */ +}; + +/* to determine the end of utf strings */ + +#define UTF_END(u) ((char *) u->text + u->blength) + + +/* utf-symbols for pointer comparison of frequently used strings **************/ + +extern utf *utf_java_lang_Object; + +extern utf *utf_java_lang_Class; +extern utf *utf_java_lang_ClassLoader; +extern utf *utf_java_lang_Cloneable; +extern utf *utf_java_lang_SecurityManager; +extern utf *utf_java_lang_String; +extern utf *utf_java_lang_System; +extern utf *utf_java_lang_ThreadGroup; +extern utf *utf_java_io_Serializable; + +extern utf *utf_java_lang_Throwable; +extern utf *utf_java_lang_Error; +extern utf *utf_java_lang_ClassCircularityError; +extern utf *utf_java_lang_ClassFormatError; +extern utf *utf_java_lang_ExceptionInInitializerError; +extern utf *utf_java_lang_IncompatibleClassChangeError; +extern utf *utf_java_lang_InstantiationError; +extern utf *utf_java_lang_InternalError; +extern utf *utf_java_lang_LinkageError; +extern utf *utf_java_lang_NoClassDefFoundError; +extern utf *utf_java_lang_OutOfMemoryError; +extern utf *utf_java_lang_UnsatisfiedLinkError; +extern utf *utf_java_lang_UnsupportedClassVersionError; +extern utf *utf_java_lang_VerifyError; +extern utf *utf_java_lang_VirtualMachineError; + +#if defined(ENABLE_JAVASE) +extern utf *utf_java_lang_AbstractMethodError; +extern utf *utf_java_lang_NoSuchFieldError; +extern utf *utf_java_lang_NoSuchMethodError; +#endif + +#if defined(WITH_CLASSPATH_GNU) +extern utf *utf_java_lang_VMThrowable; +#endif + +extern utf *utf_java_lang_Exception; +extern utf *utf_java_lang_ArithmeticException; +extern utf *utf_java_lang_ArrayIndexOutOfBoundsException; +extern utf *utf_java_lang_ArrayStoreException; +extern utf *utf_java_lang_ClassCastException; +extern utf *utf_java_lang_ClassNotFoundException; +extern utf *utf_java_lang_CloneNotSupportedException; +extern utf *utf_java_lang_IllegalAccessException; +extern utf *utf_java_lang_IllegalArgumentException; +extern utf *utf_java_lang_IllegalMonitorStateException; +extern utf *utf_java_lang_InstantiationException; +extern utf *utf_java_lang_InterruptedException; +extern utf *utf_java_lang_InvocationTargetException; +extern utf *utf_java_lang_NegativeArraySizeException; +extern utf *utf_java_lang_NullPointerException; +extern utf *utf_java_lang_StringIndexOutOfBoundsException; + +#if defined(ENABLE_JAVASE) +extern utf* utf_java_lang_Void; +#endif + +extern utf* utf_java_lang_Boolean; +extern utf* utf_java_lang_Byte; +extern utf* utf_java_lang_Character; +extern utf* utf_java_lang_Short; +extern utf* utf_java_lang_Integer; +extern utf* utf_java_lang_Long; +extern utf* utf_java_lang_Float; +extern utf* utf_java_lang_Double; + +#if defined(ENABLE_JAVASE) +extern utf *utf_java_lang_StackTraceElement; +extern utf *utf_java_lang_reflect_Constructor; +extern utf *utf_java_lang_reflect_Field; +extern utf *utf_java_lang_reflect_Method; +extern utf *utf_java_util_Vector; +#endif + +extern utf *utf_InnerClasses; +extern utf *utf_ConstantValue; +extern utf *utf_Code; +extern utf *utf_Exceptions; +extern utf *utf_LineNumberTable; +extern utf *utf_SourceFile; + +#if defined(ENABLE_JAVASE) +extern utf *utf_EnclosingMethod; +extern utf *utf_Signature; +extern utf *utf_RuntimeVisibleAnnotations; +extern utf *utf_StackMapTable; +#endif + +extern utf *utf_init; +extern utf *utf_clinit; +extern utf *utf_clone; +extern utf *utf_finalize; +extern utf *utf_run; + +extern utf *utf_add; +extern utf *utf_remove; +extern utf *utf_addThread; +extern utf *utf_removeThread; +extern utf *utf_put; +extern utf *utf_get; +extern utf *utf_value; + +extern utf *utf_fillInStackTrace; +extern utf *utf_getSystemClassLoader; +extern utf *utf_loadClass; +extern utf *utf_printStackTrace; + +extern utf *utf_Z; +extern utf *utf_B; +extern utf *utf_C; +extern utf *utf_S; +extern utf *utf_I; +extern utf *utf_J; +extern utf *utf_F; +extern utf *utf_D; + +extern utf *utf_void__void; +extern utf *utf_boolean__void; +extern utf *utf_byte__void; +extern utf *utf_char__void; +extern utf *utf_short__void; +extern utf *utf_int__void; +extern utf *utf_long__void; +extern utf *utf_float__void; +extern utf *utf_double__void; + +extern utf *utf_void__java_lang_ClassLoader; +extern utf *utf_void__java_lang_Object; +extern utf *utf_void__java_lang_Throwable; +extern utf *utf_java_lang_Object__java_lang_Object; +extern utf *utf_java_lang_String__void; +extern utf *utf_java_lang_String__java_lang_Class; +extern utf *utf_java_lang_Thread__V; +extern utf *utf_java_lang_Throwable__void; + +extern utf *utf_not_named_yet; +extern utf *utf_null; +extern utf *array_packagename; + + +/* function prototypes ********************************************************/ + +/* initialize the utf8 subsystem */ +bool utf8_init(void); + +u4 utf_hashkey(const char *text, u4 length); +u4 utf_full_hashkey(const char *text, u4 length); + +/* determine hashkey of a unicode-symbol */ +u4 unicode_hashkey(u2 *text, u2 length); + +/* create new utf-symbol */ +utf *utf_new(const char *text, u2 length); + +/* make utf symbol from u2 array */ +utf *utf_new_u2(u2 *unicodedata, u4 unicodelength, bool isclassname); + +utf *utf_new_char(const char *text); +utf *utf_new_char_classname(const char *text); + +/* get number of bytes */ +u4 utf_bytes(utf *u); + +/* get next unicode character of a utf-string */ +u2 utf_nextu2(char **utf); + +/* get (number of) unicode characters of a utf string (safe) */ +s4 utf8_safe_number_of_u2s(const char *text, s4 nbytes); +void utf8_safe_convert_to_u2s(const char *text, s4 nbytes, u2 *buffer); + +/* get (number of) unicode characters of a utf string (UNSAFE!) */ +u4 utf_get_number_of_u2s(utf *u); +u4 utf_get_number_of_u2s_for_buffer(const char *buffer, u4 blength); + +/* determine utf length in bytes of a u2 array */ +u4 u2_utflength(u2 *text, u4 u2_length); + +void utf_copy(char *buffer, utf *u); +void utf_cat(char *buffer, utf *u); +void utf_copy_classname(char *buffer, utf *u); +void utf_cat_classname(char *buffer, utf *u); + +/* write utf symbol to file/buffer */ +void utf_display_printable_ascii(utf *u); +void utf_display_printable_ascii_classname(utf *u); + +void utf_sprint_convert_to_latin1(char *buffer, utf *u); +void utf_sprint_convert_to_latin1_classname(char *buffer, utf *u); + +void utf_strcat_convert_to_latin1(char *buffer, utf *u); +void utf_strcat_convert_to_latin1_classname(char *buffer, utf *u); + +void utf_fprint_printable_ascii(FILE *file, utf *u); +void utf_fprint_printable_ascii_classname(FILE *file, utf *u); + +/* check if a UTF-8 string is valid */ +bool is_valid_utf(char *utf_ptr, char *end_pos); + +/* check if a UTF-8 string may be used as a class/field/method name */ +bool is_valid_name(char *utf_ptr, char *end_pos); +bool is_valid_name_utf(utf *u); + +/* show utf-table */ +void utf_show(void); + +#endif /* _UTF_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: + */ diff --git a/src/vmcore/zip.c b/src/vmcore/zip.c new file mode 100644 index 000000000..6aa5eec29 --- /dev/null +++ b/src/vmcore/zip.c @@ -0,0 +1,498 @@ +/* src/vmcore/zip.c - ZIP file handling for bootstrap classloader + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + Edwin Steiner + + $Id: zip.c 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "vm/types.h" + +#include "toolbox/hashtable.h" +#include "mm/memory.h" +#include "vm/global.h" +#include "vmcore/suck.h" +#include "vmcore/utf8.h" +#include "vmcore/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 + + +/* 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; +}; + + +/* 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 */ + + if ((htzfe = zip_find(lce, c->name)) == 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) + assert(0); + + /* decompress the file into buffer */ + + err = inflate(&zs, Z_SYNC_FLUSH); + + if ((err != Z_STREAM_END) && (err != Z_OK)) + assert(0); + + /* finish this inflate run */ + + if (inflateEnd(&zs) != Z_OK) + assert(0); + break; + + case 0: + /* uncompressed file, just copy the data */ + MCOPY(outdata, indata, u1, htzfe->compressedsize); + break; + + default: + assert(0); + } + + /* allocate classbuffer */ + + cb = NEW(classbuffer); + + cb->class = 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: + */ diff --git a/src/vmcore/zip.h b/src/vmcore/zip.h new file mode 100644 index 000000000..97e9e00d6 --- /dev/null +++ b/src/vmcore/zip.h @@ -0,0 +1,79 @@ +/* src/vmcore/zip.c - ZIP file handling for bootstrap classloader + + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + 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. + + $Id: zip.h 7246 2007-01-29 18:49:05Z twisti $ + +*/ + + +#ifndef _ZIP_H +#define _ZIP_H + +#include "config.h" +#include "vm/types.h" + +#include "toolbox/hashtable.h" + +#include "vm/global.h" + +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/suck.h" +#include "vmcore/utf8.h" + + +/* 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 ********************************************************/ + +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); + +#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: + */