pkg://kaffe-rhcn-1.0.b4-1.src.rpm:2270813/kaffe-1.0.b4.tar.gz
info downloads
kaffe-1.0b4/ 777 624 310 0 6703463065 5740 5 kaffe-1.0b4/Makefile.in 644 624 310 36215 6703462461 10027 # Makefile.in generated automatically by automake 1.4a from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = .
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_FLAG =
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
AMTARFLAGS = @AMTARFLAGS@
AS = @AS@
AWT_DIR = @AWT_DIR@
AWT_LIBS = @AWT_LIBS@
CC = @CC@
CONFIG_JIT_MD_H = @CONFIG_JIT_MD_H@
CONFIG_MD_H = @CONFIG_MD_H@
CPP = @CPP@
DIRSEP = @DIRSEP@
DLLTOOL = @DLLTOOL@
DLOPEN_JAVA_LIBS = @DLOPEN_JAVA_LIBS@
ENGINE_NAME = @ENGINE_NAME@
EXEEXT = @EXEEXT@
HAVE_CONFIG_JIT_MD_H = @HAVE_CONFIG_JIT_MD_H@
JAVA_LIBS = @JAVA_LIBS@
JIKES = @JIKES@
KAFFEH = @KAFFEH@
KAFFEVM_ICODE_H = @KAFFEVM_ICODE_H@
KAFFEVM_JIT_DEF = @KAFFEVM_JIT_DEF@
KAFFEVM_MD_C = @KAFFEVM_MD_C@
KAFFEVM_TRAMPOLINES_C = @KAFFEVM_TRAMPOLINES_C@
KAFFE_ARCHOS = @KAFFE_ARCHOS@
KAFFE_LIBS = @KAFFE_LIBS@
KLIBFLAGS = @KLIBFLAGS@
KPREFIX = @KPREFIX@
KVER = @KVER@
KVMLIBFLAGS = @KVMLIBFLAGS@
Kaffe_TRANSF = @Kaffe_TRANSF@
LD = @LD@
LIBLTDL = @LIBLTDL@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LN_S = @LN_S@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MAKE_KAFFEH = @MAKE_KAFFEH@
MATH_LIBS = @MATH_LIBS@
M_LIBS = @M_LIBS@
NET_LIBS = @NET_LIBS@
NM = @NM@
PACKAGE = @PACKAGE@
PATHSEP = @PATHSEP@
RANLIB = @RANLIB@
REGEN_FORWARD = @REGEN_FORWARD@
TAR = @TAR@
THREAD_DIR = @THREAD_DIR@
THREAD_SYSTEM = @THREAD_SYSTEM@
VERSION = @VERSION@
VM_LIBS = @VM_LIBS@
ZIP = @ZIP@
ZIP_LIBS = @ZIP_LIBS@
classdir = @classdir@
host_cpu = @host_cpu@
host_os = @host_os@
kaffe_TRANSF = @kaffe_TRANSF@
nativedir = @nativedir@
with_engine = @with_engine@
# Top-level Makefile for Kaffe OpenVM.
#
# Copyright (c) 1996, 1997, 1998, 1999
# Transvirtual Technologies, Inc. All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file.
AUTOMAKE_OPTIONS = foreign 1.3e
SUBDIRS = . config include libltdl libraries kaffe test
EXTRA_DIST = \
ChangeLog.1 \
WHATSNEW \
license.terms \
FAQ/FAQ.BeOS \
FAQ/FAQ.Known-Bugs \
FAQ/FAQ.amigaos \
FAQ/FAQ.automake \
FAQ/FAQ.awt \
FAQ/FAQ.class-states \
FAQ/FAQ.classlibrary-compile \
FAQ/FAQ.depend \
FAQ/FAQ.gcblock \
FAQ/FAQ.gcstrategy \
FAQ/FAQ.hotjava \
FAQ/FAQ.install-root \
FAQ/FAQ.jsignal \
FAQ/FAQ.libtool \
FAQ/FAQ.linux \
FAQ/FAQ.nativemethods \
FAQ/FAQ.requiredlibraries \
FAQ/FAQ.timing \
FAQ/FAQ.unicode \
FAQ/FAQ.win32 \
developers/JavaClass.pm \
developers/README \
developers/README.unicode \
developers/autogen.sh \
developers/dumpClass.pl \
developers/gdbinit \
developers/sp_offset.c \
developers/update-class-list \
developers/unicode.pl \
developers/utf8munge.pl
CLEANFILES = BUILD_ENVIRONMENT
noinst_SCRIPTS = libtool BUILD_ENVIRONMENT
CLASSDIRS = libraries/javalib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ./config/config.h ./include/jtypes.h
CONFIG_CLEAN_FILES =
SCRIPTS = $(noinst_SCRIPTS)
DIST_COMMON = README AUTHORS ChangeLog INSTALL Makefile.am Makefile.in \
acinclude.m4 aclocal.m4 config.guess config.sub config/config.h.in \
config/stamp-h1.in configure configure.in include/jtypes.h.in \
include/stamp-h2.in install-sh ltconfig ltmain.sh missing mkinstalldirs
DISTFILES = $(DIST_COMMON) $(SOURCES) $(TEXINFOS) $(EXTRA_DIST)
GZIP_ENV = --best
all: all-redirect
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4
cd $(srcdir) && $(ACLOCAL)
config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
cd $(srcdir) && $(AUTOCONF)
config/config.h: config/stamp-h1
@if test ! -f $@; then \
rm -f config/stamp-h1; \
$(MAKE) config/stamp-h1; \
else :; fi
config/stamp-h1: $(srcdir)/config/config.h.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES= CONFIG_HEADERS=config/config.h \
$(SHELL) ./config.status
@echo timestamp > config/stamp-h1 2> /dev/null
$(srcdir)/config/config.h.in: @MAINTAINER_MODE_TRUE@$(srcdir)/config/stamp-h1.in
@if test ! -f $@; then \
rm -f $(srcdir)/config/stamp-h1.in; \
$(MAKE) $(srcdir)/config/stamp-h1.in; \
else :; fi
$(srcdir)/config/stamp-h1.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOHEADER)
@echo timestamp > $(srcdir)/config/stamp-h1.in 2> /dev/null
include/jtypes.h: include/stamp-h2
@if test ! -f $@; then \
rm -f include/stamp-h2; \
$(MAKE) include/stamp-h2; \
else :; fi
include/stamp-h2: $(srcdir)/include/jtypes.h.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES= CONFIG_HEADERS=include/jtypes.h \
$(SHELL) ./config.status
@echo timestamp > include/stamp-h2 2> /dev/null
$(srcdir)/include/jtypes.h.in: @MAINTAINER_MODE_TRUE@$(srcdir)/include/stamp-h2.in
@if test ! -f $@; then \
rm -f $(srcdir)/include/stamp-h2.in; \
$(MAKE) $(srcdir)/include/stamp-h2.in; \
else :; fi
$(srcdir)/include/stamp-h2.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOHEADER)
@echo timestamp > $(srcdir)/include/stamp-h2.in 2> /dev/null
mostlyclean-hdr:
clean-hdr:
distclean-hdr:
-rm -f config/config.h include/jtypes.h
maintainer-clean-hdr:
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
@SET_MAKE@
all-recursive install-data-recursive install-exec-recursive \
installdirs-recursive install-recursive uninstall-recursive \
check-recursive installcheck-recursive info-recursive dvi-recursive:
@set fnord $(MAKEFLAGS); amf=$$2; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive:
@set fnord $(MAKEFLAGS); amf=$$2; \
dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \
if test "$$subdir" = "."; then dot_seen=yes; else :; fi; \
done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$rev; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
done
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
fi; \
done; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
-rm -rf $(distdir)
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(TAR) xf -
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; \
cd $(distdir)/=build \
&& ../configure --srcdir=.. --prefix=$$dc_install_base \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) dist
-rm -rf $(distdir)
@banner="$(distdir).tar.gz is ready for distribution"; \
dashes=`echo "$$banner" | sed s/./=/g`; \
echo "$$dashes"; \
echo "$$banner"; \
echo "$$dashes"
dist: distdir
-chmod -R a+r $(distdir)
tar ch$(AMTARFLAGS)f - $(distdir) | GZIP=$(GZIP_ENV) gzip -c > $(distdir).tar.gz
-rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
tar ch$(AMTARFLAGS)f - $(distdir) | GZIP=$(GZIP_ENV) gzip -c > $(distdir).tar.gz
-rm -rf $(distdir)
distdir: $(DISTFILES)
-rm -rf $(distdir)
mkdir $(distdir)
-chmod 777 $(distdir)
$(mkinstalldirs) $(distdir)/FAQ $(distdir)/developers
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$d/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
for subdir in $(SUBDIRS); do \
if test "$$subdir" = .; then :; else \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
|| exit 1; \
chmod 777 $(distdir)/$$subdir; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
|| exit 1; \
fi; \
done
info-am:
info: info-recursive
dvi-am:
dvi: dvi-recursive
check-am: all-am
check: check-recursive
installcheck-am:
installcheck: installcheck-recursive
install-exec-am:
install-exec: install-exec-recursive
install-data-am:
install-data: install-data-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-recursive
uninstall-am:
uninstall: uninstall-recursive
all-am: Makefile $(SCRIPTS)
all-redirect: all-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
installdirs: installdirs-recursive
installdirs-am:
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-recursive
clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
clean: clean-recursive
distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
-rm -f libtool
distclean: distclean-recursive
-rm -f config.status
maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-recursive
-rm -f config.status
.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
install-data-recursive uninstall-data-recursive install-exec-recursive \
uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
all-recursive check-recursive installcheck-recursive info-recursive \
dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
install-exec install-data-am install-data install-am install \
uninstall-am uninstall all-redirect all-am all install-strip \
installdirs-am installdirs mostlyclean-generic distclean-generic \
clean-generic maintainer-clean-generic clean mostlyclean distclean \
maintainer-clean
depend:
@echo \`make depend\' is no longer needed
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
BUILD_ENVIRONMENT: Makefile
$(MAKE) top_srcdir=`cd $(top_srcdir) >/dev/null; pwd` \
top_builddir=`cd $(top_builddir) >/dev/null; pwd` \
"DEBUG_ENV=$(DEBUG_ENV)" BUILD_ENVIRONMENT-make
BUILD_ENVIRONMENT-make: Makefile
echo CLASSPATH=\$${CLASSPATH-.}\''$(PATHSEP)'\'$(top_srcdir)/libraries/javalib/Klasses.jar\''$(PATHSEP)'\'$(top_srcdir)/libraries/javalib/pizza.jar\; export CLASSPATH > BUILD_ENVIRONMENT; \
echo KAFFELIBRARYPATH=\$${KAFFELIBRARYPATH+\"\$$KAFFELIBRARYPATH\"\''$(PATHSEP)'\'}`for f in $(JAVA_LIBS); do echo "$$f" | sed 's%/[^/]*$$%%'; done | (tr '\012' '$(PATHSEP)'; echo) | sed s/.$$//`\; export KAFFELIBRARYPATH >> BUILD_ENVIRONMENT; \
echo JAVA=$(top_builddir)/kaffe/kaffe/Kaffe$(EXEEXT)\; export JAVA >> BUILD_ENVIRONMENT
.PHONY: Klasses new-classes compile-classes jar-classes build-classes
Klasses new-classes compile-classes jar-classes build-classes:
@if test "$(CLASSDIRS)" = all; then \
$(MAKE) CLASSDIRS="`echo libraries/javalib \
libraries/extensions/*/javalib`" $@; \
else \
for f in $(CLASSDIRS); do \
(cd $$f && $(MAKE) $@); \
done; \
fi
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
kaffe-1.0b4/FAQ/ 755 624 310 0 6703462466 6347 5 kaffe-1.0b4/FAQ/FAQ.BeOS 644 624 310 5361 6677531004 7470 NOTES ABOUT THE BeOS PORT
=========================
The BeOS port requires BeOS R4 or higher. It uses its own threading
system designated "beos-native". The "unix-jthreads" system can be
made to work for the most part; however, that system relies on
asynchronous I/O notifications, as well as virtual timer alarms, both
of which are absent on BeOS R4.
beos-native was modeled upon the oskit-pthreads system, which relies
on mutexes and condition variables. BeOS has the former, but not the
latter, so I defined a condition variable type based upon an article I
found posted on the Web [1].
To build Kaffe for BeOS, you must configure Kaffe as follows:
./configure --disable-shared --prefix=<insert-your-prefix-here>
as there is a known problem with building shared libs on R4 (yes, I
realize that the fix is documented in the R4 release notes, but I'll
let someone else muck with the Makefiles accordingly).
As of 26 March 1999, Kaffe has not been built or tested with AWT at all.
Also, the following entry points in the jthread interface have yet to be
implemented:
jthread_suspendall
jthread_unsuspendall
jthread_spinon
jthread_spinoff
KNOWN PROBLEMS
==============
The jthread interface requires that the macros GET_JTHREAD/SET_JTHREAD
and GET_COOKIE/SET_COOKIE store and retrieve per-thread information.
Right now, this information is maintained in a large BeOS "area" containing
an array of per_thread_info_t structures. The info for a given thread
with thread id 'T' is simply (T % MAX_THREADS). Naturally, since
successive calls to spawn_thread (invoked by jthread_create) will not
necessarily yield contiguous thread ids, the maximum number of jthreads
that can be successfully created will be somewhat less than MAX_THREADS.
The implementation of forkexec() in beos-native/syscalls.c makes use of
fork() instead of the recommended technique that uses load_image().
The gethostbyname() and gethostbyaddr() wrappers in beos-native/syscalls.c
are not thread-safe.
The test 'GCTest' gets stuck when executed from within the TestScript
on a machine with 32MB of memory; it passes, though, when run from the
command line.
The BeanBug test in the regression test suite fails because it requires AWT.
REFERENCES
==========
[1] "Locks and Condition Variables",
http://www.cs.umd.edu/~hollings/cs412/s96/synch/locks.html
REV HISTORY
===========
27 Jan 99 -- Submitted for inclusion into Kaffe, alanlb@cs.vt.edu
08 Feb 99 -- Fixed various segmentation violations
18 Mar 99 -- Implemented jcondvar_wait timeout, forkexec;
fixed jthread_interrupt
22 Mar 99 -- Fixed socket read/write in beos-native/syscalls.c, redid
thread cancellation (i.e., stoppage)
24 Mar 99 -- Fixed forkexec; ProcessTest now passes
26 Mar 99 -- Implemented most socket timeouts; SoTimeout now passes
kaffe-1.0b4/FAQ/FAQ.Known-Bugs 644 624 310 15344 6677531004 10714 **********************************************************************
NOTE:
Kaffe has its own jitterbug bug tracking system now.
See www.kaffe.org and http://www.kaffe.org/cgi-bin/kaffe
We will note new bugs only there.
**********************************************************************
This file is a list of known bugs, short-comings and oddities.
Treat it as an TODO list. This file is divided in three sections.
MISSING AND/OR BROKEN FEATURES
---------------------------------------------------------------------------
* reflection: when reporting fields of a class, kaffe wrongly does not include
public static final fields of the interfaces that this class implements.
* File.getCanonicalPath() is not properly implemented.
This needs a native implementation.
* java.net.Socket:
Gerhard Paulus <gpaulus@stud.uni-frankfurt.de> reports:
+ a host name "" is not taken as local host (as in JDK)
+ if a socket is closed and a thread is reading from the socket's input
stream then this thread should be able to catch the SocketException
"Socket closed" (as in JDK) This might be fixed now.
* Kaffe does not currently provide its own implementation of RMI.
* Kaffe's java.lang.Character class does not conform to Sun's spec. The
handling of unicode characters is incomplete.
* Some run-time classes may not serialize or deserialize according to their
serial forms.
* java.math.* is incomplete. java.math.BigInteger is mostly written and
relies on the GNU Multi-precision math package (GMP). BigDecimal is
completely incomplete (?) and will just throw exceptions when used.
* The conversion of floats or doubles to strings does not completely
conform to Sun's spec. For example, Double.toString() will display
the double 0x400B333333333333 as "3.3999999999999999" instead of "3.4".
* DecimalFormat is broken : no formatting at all and decimals are cut off.
There are problems with date & calendar.
Reported by: Gerhard Paulus <gpaulus@stud.uni-frankfurt.de>
See http://rufus.w3.org/tools/Kaffe/messages/3785.html,
http://rufus.w3.org/tools/Kaffe/messages/3784.html
* Runtime.runFinalizersOnExit() does not run the finalizers of all objects
on exit, but only of those objects that are finalizable at the time. It
hadn't even occurred to us that Sun wants us to run the finalizers of live
objects when exiting, but this is what the 1.2 JDK doc says:
Enable or disable finalization on exit; doing so specifies that the
finalizers of all objects that have finalizers that have not yet been
automatically invoked are to be run before the Java runtime exits.
By default, finalization on exit is disabled.
Deprecated. This method is inherently unsafe. It may result in
finalizers being called on live objects while other threads are
concurrently manipulating those objects, resulting in erratic behavior
or deadlock.
ARCHITECTURE-SPECIFIC PROBLEMS
---------------------------------------------------------------------------
* Kaffe fails to work for several people under SunOS 4.1.3. The error
message seems to be "Can not find native library in path". This problem
is unclear: either a problem in the kaffe script that use @libdir@ and set
LD_LIBRARY_PATH (less likely), or a problem in the dynamic linking
mechanisms on this system. Check the mailing list archive for more info.
* There have been reports of problems with exception handling on Linux 2.1.
These problems have to do with libc versions. Unfortunately, no patches
have been submitted. As a matter of precautious, make sure you run your
kaffe binary on the system on which it was compiled, that is, don't run
Linux 2.0 binaries on 2.1 or vice versa. The test LostFrame in
test/regression (and possibly others) should fail if you're affected
by this problem. We would really appreciate a mechanism that would
allow us to detect and handle different libc versions at run-time.
* On netbsd1.3/arm32, the % operator for long data types is broken.
This means that the sign of such an operation may come out wrong.
Java says it must be equal to the sign of the dividend. This is
mostly due to a bug in __moddi3. FreeBSD <=2.2.8 and <=3.0 have
the same problem, but there it's only in libc, not in libgcc, so
we instruct configure to explicitly link with libgcc.
THINGS WHERE KAFFE'S BEHAVIOR DIFFERS
---------------------------------------------------------------------------
* Class.getFields() returns Fields in reverse order compared to Sun's jdk.
Apparently, this causes some software such Cygnus's kawa to fail in
certain circumstances. It seems like they should fix that.
MISCELLANEOUS & TODO
---------------------------------------------------------------------------
* Add some architecture-specific stack pointer alignment macro. Currently,
alignment is sizeof (jlong); apparently, some architectures require more
specific alignments.
* While Kaffe currently doesn't compile with other compilers than Cygnus
cygwin32 gcc compiler, we do know that people are trying to compile it
with compilers such as Visual C++. Jongwon Kim <freefish@chollian.net>
reports that FIELD_OFFSET in classMethod.h conflicts with winnt.h.
* JNI incompatibilities pointed out by Johannes Deisenhofer
<joe@dillingen.baynet.de>:
- NewXXXArray() should return jXXXArray instead of jarray
This is a problem in C++, since these types are not simply casted to jref
Note kaffe's jni.h doesn't even define these array types as of yet.
* The call to `native' in external.c is unprotected in the interpreter.
In the jitter, this call is protected by locking the class.
* When verifying a method, we lock the whole class. This means that other
threads attempting the call other methods may be blocked until the
verification succeeds. This could lead to deadlock.
* OutOfMemoryErrors are not handled properly. Don't even try to write
applications that attempt catch and recover from them. Running out of
memory may cause seemingly unrelated assertion failures, such as
"Assertion `jitting == 0 || !!!"reentered jitter"' failed."
Try increasing the total heap size using "-mx" in this case.
* Stopping threads at inopportune times may corrupt the VM.
* Classloaders don't keep classes alive if they are only an initiating loader of
that class, but did not define that class. This will cause problems with
class gc in the face of delegation if the loader to which the loading was
delegated becomes unreachable before the loader that delegated it.
A possible fix is to walk the centry for each loader; this would also
allows us to get rid of the loadedClasses hashtable in
java/lang/ClassLoader.java.
* kaffeh leaves incomplete output files around if it bails because it cannot
find the class file.
kaffe-1.0b4/FAQ/FAQ.amigaos 644 624 310 14335 6552662340 10341 KAFFE COMMON PROBLEMS
===========================================================================
Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996-97.
Ported to AmigaOS by Matthias Hopf <mshopf@informatik.uni-erlangen.de>
NOTES ABOUT THE AMIGAOS PORT
============================
The Amiga port has been done in a relatively straightforward way using the
Geek Gadgets (abbreviated GG in this document) developer environment,
formerly known as ADE (Amiga Developer Environment). Thus to work properly
it needs at least version 45.0 of ixemul.library, available from any GG
mirror.
The needed Sun java classes are not included due to legal reasons. They are
available as a seperate archive, e.g. kaffe-0.9.0-sun.tgz. If you get an
'Cannot find essential class 'java/lang/Object' in class library ...', you
probably do not have the Sun classes included in your CLASSPATH (see
below). Note that begining with kaffe-0.9.0 you will need the JDK-1.1.1
version of classes.zip.
To set up kaffe, do 'make install' in an GG environment, set up the
environment variables as stated in the file ENVIRONMENT and make sure that
kaffe can be found in your path as well as in the sh 'PATH' environment
variable.
Try 'kaffe HelloWorldApp' in the test/ directory. Guess what it does :-)
Try 'javac HelloWorldApp.java' in the test/ directory. But be prepared
- the javac compiler class is relatively slow...
Try 'make test' in the main directory. This will run a number of test
suites. Most tests should work by now. This test takes a lot of time...
When kaffe does not work properly, please read the COMMON CONFIGURATION
PROBLEMS and KNOWN BUGS sections below before sending any bug reports to
me, or even better to the mailing list gg-java@ninemoons.com. When I ask
you to, please fill out the system configuration report you can find in
config/m68k/amigaos/REPORT.amiga and send it to me. It will help debugging.
COMMON CONFIGURATION PROBLEMS
=============================
- 'version ixemul.library'
You will need at least V44.0 of ixemul.library. The kaffe binaries that
can be fetched from ftp.ninemoons.com need at least V45.0 of
ixemul.library.
- Sun's classes.zip file.
For kaffe to work properly you will need the JDK 1.1.1 classes.zip file
from Sun, available from Sunsoft or from any kaffe-sun-* archive from
ftp.ninemoons.com.
*NOTE* The JDK classes.zip files from earlier releases will not work with
kaffe! Guavac seems to be shipped with the old Sun classes.
- 'echo "$CLASSPATH"'
The classpath has to include at least '.' (the current directory) and
Sun's classes.zip file (the file itself, not the directory where it is
located). A valid classpath may be set with e.g.
setenv CLASSPATH ".;GG:share/kaffe/classes.zip"
Don't forget the doublequotes (';' is the comment specifier in AmigaDos).
And do not forget the trailing dot when specifying the current directory
or volumes (e.g. 'kaffe:.'). Of course the CLASSPATH specification is
also affected by your ixprefs settings!
- 'ixprefs -i 0'
Either you will have to make ixemul.library recognize global environment
variables, or you will have to set the local environment variable
set CLASSPATH="$CLASSPATH"
Again, don't forget the doublequotes.
- 'EMT Trap.'
When kaffe simply aborts with 'EMT Trap', then you have probably an
executable compiled for Amigas with coprozessors (versions before 0.7.1
from GG were compiled with -m68881 by accident).
It is possible, that you have the wrong ixemul.library installed, too.
If you do not get this problem regulary, it may well be that you just
encountered a problem inherrited to several IDE drives which cannot
handle high MaxTransfer settings (if any is set up at all...).
If you run kaffe from a SCSI drive, it can also be a drive and/or host
adaptor with reselection problems. In that case disable reselection.
KNOWN BUGS
==========
KNOWN BUGS of the current version
- Not all pointer access are checked for null pointer accesses. However,
kaffe should work better now than in the last few versions.
KNOWN BUGS of former versions
* distributions before V0.9.0
- NullPointerExceptions were not generated at all. The kaffe code relied on
SIGSEGV signals for NULL pointer access, which cannot work on AmigaOS.
*NOTE* On NULL pointer access you *will* encounter Enforcer hits.
These can even crash your computer...
* distributions before V0.7.1
- When kaffe simply aborts with 'EMT Trap', then you have probably an
executable compiled for Amigas with coprocessors (binary archives from
GG were compiled with -m68881 by accident and the configure script
added the options -m68020-40 and -m68881).
* distributions before V0.7.0
- kaffeh produced loads of (most times harmless) Enforcer hits and
generated wrong files sometimes.
- kaffeh liked to abort with 'Bus error' when invoked without the
'-stubs' option.
* distributions before V0.6.0
- kaffeh of distributions before V0.6.0 used a different CLASSPATH scheme
(':' as seperator).
- kaffevm/thread.c did not compile without warnings because of the thread
switching macros.
- kaffe-0.5p4 aborted with an 'Exception thrown on NULL object' when the
classes.zip file (see below) couldn't be found. kaffe-0.5.5 simply
crashes, however. Begining with kaffe-0.6.0 this abnormal exception is
caught.
KNOWN COMPILATION BUGS of former versions
* distributions before V0.7.1
- Kaffe was compiled with -m68020-40 and -m68881 by accident.
- Several version did not compile when fetched from Tim's original kaffe
site. The GG versions had several bug fixes.
NONWORKING CLASSES
- some tests in regression still fail
* distributions before V0.9.0
- exception/NullTest (see BUGS)
- exception/StackDump
- some more...
OTHER NOTES
* distributions before V0.7.1
- The thread switching code was not perfect. However, you should not notice
that except when compiling kaffe...
That's it, folks :)
Matthias Hopf
<mshopf@informatik.uni-erlangen.de>
----
* Java and Javasoft are registered trademark of Sun Microsystems, Inc.
kaffe-1.0b4/FAQ/FAQ.automake 644 624 310 6311 6703446343 10503 **************************************************************************
IMPORTANT NOTE:
- in order to modify the Makefiles and configure.in, you need rather
recent versions of autoconf and automake: autoconf 2.13 and automake
1.4. automake is supposed to work with perl4, but it apparently
doesn't, which means you probably need perl5 as well.
**************************************************************************
Kaffe has adopted GNU automake to ease the maintenance of Makefiles.
Changes were mostly straightforward, and nothing really important has
changed in the build environment. I could list a few changes here:
- EXTRA_CFLAGS is no longer used; you can now use AM_CFLAGS and
AM_CPPFLAGS. Prefer the latter for preprocessor definitions such as
-DDEBUG.
- using automake means editing Makefile.am instead of Makefile.in, and
that it will take care of rebuilding autoconf/automake-related files
whenever they become out-of-date, but only if you
--enable-maintainer-mode at configure time. If not, you'll have to
run "aclocal; automake; autoconf; autoheader -l config" (or just
developers/autogen.sh) manually in the top-level source directory.
- you also have to specify which files should go in a distribution
(make dist): they should either be listed as sources to some binary or
library or be listed in the EXTRA_DIST variable. In order to avoid
missing some file, you should run `make distcheck' instead of just
`make dist'. distcheck runs make dist, builds the dist tree and runs
make check on it.
- since automake 1.4 doesn't accept sources from other directories, I
have created some makefiles in subdirectories such as jit, intrp and
system/unix-*. A special kind of temporary library, called libtool
convenience library, is created to hold files from each of these
directories, and then the convenience library is included in
libkaffevm. In other cases, such as gc-mem.c, I have preferred to
just create a gc-mem.c forwarder (a file that #includes mem/gc-mem.c)
within kaffe/kaffevm. If we later decide that it was not a good idea,
it is very easy to create a Makefile.am within kaffevm/mem and create
a convenience library there.
- `make depend' is now implicit, but it only works with gcc and GNU
make. A distribution file with portable makefiles should be created
with `make dist'
- `make test' is now called `make check', which is much more standard
- I added a new flag, --with-staticvm, to make only the VM library
static. --with-includes and --with-libraries were also introduced, to
allow the user to specify a list of directories to search for
include-files and libraries. --with-rtlibraries can be used to
hard-code run-time library search paths into the Kaffe program, so
that it can find libraries such as X11, libungif, etc, that happen to
be installed in non-standard places. This option does not affect the
search path for native libraries loaded from Java code.
- you may miss one or other make target that I may have eliminated
from the Makefiles, for example, recursive `make classes' and `make
derived-files'. It should be straightforward to re-create them within
Makefile.am's, but I'd prefer to avoid these, and create actual
dependencies to ensure that derived files are re-created as needed.
--
oliva
kaffe-1.0b4/FAQ/FAQ.awt 644 624 310 1443 6604574126 7472 FAQ for the AWT
===============
1.0.2 Event Model
-----------------
We do *not* support the old 1.0.2 Event Model since this has been deprecated.
Beware that code exists which 'claims' to be JDK 1.1 compatiable but still
uses some of the 1.0.2 features.
1.0.2 Deprecated methods
------------------------
We're adding in missing deprecated methods as we find them. If you come
across a missing one, send us a patch.
Swing
-----
Whatever Sun may tell you about Swing being 100% pure Java - just don't
believe them. Swing make a number of assumptions about the underlying AWT
implementation and makes calls to a number of "banned" methods - oh and it
makes extensive use of deprecates. We're working toward Swing compatibility
but since this stuff is *all* undocumented it may take a little time.
kaffe-1.0b4/FAQ/FAQ.class-states 644 624 310 3702 6631343020 11270
The new state graph for class loading.
PRELOADED
|
V
UNLOADED --- read bytecode ---> LOADED
+------------------------------|
| V
| DOING_PREPARE -- go "PREPARE" --> ClassCircularity
| |
| bring superclass to LINKED
| build interface table
| resolveObjectFields
| resolveStaticFields
| buildDispatchTable -- any fail -------------------+
| | |
L | V |
| PREPARED |
O | | |
| V |
C | verify2 |
| verify3 -- any fail -------------------|
K | | |
| V |
| LINKED |
| | |
| V |
| resolveConstants -- fail -------------------|
| | |
| V |
| DOING_SUPER --> on go wait |
| | |
+------------------------------| |
| |
bring superclass to COMPLETE --> fail --> FAILED
| |
| v
L +------------------------------| return false
O | | ^
C | V |
K | USABLE/DOING_INIT --> on go wait | go
| | | "CO
+------------------------------| | MPL
| | ETE"
call static {} |
| |
L +------------------------------| |
| V |
O | |--- static {} FAILS --> INIT_FAILED ---+
| | |
C | static {} returns okay |
| | |
K | V |
+---------------------------COMPLETE |
| |
+-----------------------------|
|
V
return true
PRELOADED COMPLETE(*)
\ /
LOADED -> DOING_PREPARE -...-> DOING_SUPER -> USABLE/DOING_INIT
/ \
UNLOADED INIT_FAILED(*)
FAILED(*)
(*) final state
kaffe-1.0b4/FAQ/FAQ.classlibrary-compile 644 624 310 2355 6703446074 13022
How do I compile the class library?
-----------------------------------
Cd to your build directory (the same as the source directory if you
did ./configure), then cd to libraries/javalib.
Type "make Klasses".
This will build the java libraries, put them in a Klasses.jar file
and overwrite the version in your source tree. Type "make install"
to install the jar file in your target prefix.
If you have added or removed files from the javalib tree, you may have
to run "make new-classes" first. This will update Makefile.am, but
not Makefile.in nor Makefile. In order to update these other files,
for the changes to take effect, you'll need automake 1.4 or newer, and
you'll have to configure with --enable-maintainer-mode or run automake
by hand.
If you want to rebuild not only Klasses.jar, but also the jar-files of
Kaffe extensions, type "make CLASSDIRS=all Klasses".
What compilers are known to work?
---------------------------------
As of 4/1/99, the pizza in Kaffe's pizza.jar should work,
as well as Sun's 1.1.5 javac (according to Peter).
jikes Version 0.47 also works, and is quite speedy.
jikes is available from http://www.ibm.com/research/jikes
Sun's 1.1.7 or 1.2 javac does not work. (Somebody wants to file
a bug report with them?)
kaffe-1.0b4/FAQ/FAQ.depend 644 624 310 333 6663635727 10125 Kaffe's build environment no longer has a depend target; automake
takes care of it with the developer's version of the makefiles. After
`make dist', dependencies are hard-coded into the Makefiles.
--
Alexandre Oliva
kaffe-1.0b4/FAQ/FAQ.gcblock 644 624 310 4723 6645025361 10304 The new gc_block allocation scheme optimizes virtual memory and
cache behavior.
Previously, each page of the heap had a header, struct gc_block.
The conservative GC tested whether a pointer pointed into the heap by
searching a simple hash table called gc_object_hash. The new
allocation scheme allows faster conservative object marking by
eliminating gc_object_hash, and reduces cache conflict misses and
paging by placing struct gc_blocks in an array.
Since gc_blocks are not part of the pages they describe further memory
optimizations are possible: Free pages anywhere in the heap can be
marked as low priority with madvise. And, free pages can be made
unreadable, as is done when compiled with -DDEBUG. Madvise is not
currently used, since it seems to have a negligible effect.
Rather than searching a hash table to find a gc_block structure,
markObject simply needs to subtract the heap base from a pointer, and
use the difference in pages to index the gc_block array.
There are some complications: The java heap is not really an array of
pages: Pages allocated by malloc and gc_system_alloc may be interleaved.
There are three ways to deal with this:
1. Allocate the entire heap up front, which needlessly ties up
resources.
2. Allocate some address space, then fill in the heap and gc_block
array as needed (using mmap). On systems which support the
MAP_NORESERVE flag, mmap can allocate address space without
allocating backing store. But, on other systems a strange trick
would be required: Call mmap(0) to find out where mmap wants to
place memory, add an arbitrary constant, and start the heap there.
This trick is less than reliable. And, neither approach works on
systems that don't have mmap.
3. Allocate the full gc_block array up front. Compensate for holes in
the heap address range, but be prepared to realloc the gc_block
array if neeeded.
I have taken the third approach. Kaffe initially allocates an array
of max-heap-pages * 1.25 gc_block structures using malloc. If this
array turns out to be too small (because quite a few memory
allocation requests are bypassing gc_malloc), the array is
realloc'ed to a better guess at its maximum size. Pointers to
gc_blocks (both inside gc_blocks and in variables such as
gc_prim_freelist) are relocated.
This adds a wrinkle to any work on a concurrent GC: There can be no
gc_block *'s on any stack when the array is realloced (inside
gc_heap_malloc).
Jason Baker <jbaker@cs.utah.edu>
Jan 6, 1999
kaffe-1.0b4/FAQ/FAQ.gcstrategy 644 624 310 16344 6644562251 11101
Kaffe's garbage collector is a classical conservative collector that follows
the tricolor scheme, and it is not very sophisticated. However, by tweaking
its parameters, it is sometimes possible to speed up applications
significantly.
This FAQ explains an gc strategy I implemented for Kaffe and it should
answer the following questions:
+ How does Kaffe decide when to garbage collect and when to get more memory
from the operating system instead?
+ How does Kaffe use the parameters specified by the -ms and -mx switches?
What's that -as switch for? What values should I choose for what
applications?
Kaffe recognizes the following three switches, which can be followed by
a numerical argument (either immediately following the switch, as in
``-mx32M'', or separated by a space as in ``-mx 32M'') specifying a byte amount.
K/k and M/m suffixes denote Kilo and Mega bytes, respectively.
Default
-ms: 5M This value specifies the initial heap size. When Kaffe
starts up, it will request this amount of memory upfront
from the operating system and add it to the heap it
manages.
-mx: 64M This value specifies the maximum heap size. Kaffe will
never request more memory than that from the operating
system. Note that the total memory usage of kaffe may be
higher since libraries such as Xlib may obtain memory from
the operating system without consulting Kaffe's allocator.
Note further that Kaffe's internal data structures will
be allocated from that heap as well (not only the garbage
collectable objects produced by your application.)
-as: 1M This value specifies the heap increment. The heap increment
is the amount of memory Kaffe will request from the operating
system to add to the heap it manages if it decides to postpone
a collection. See below what ``postponing'' means.
If kaffe's allocator is asked to provide some memory, it follows a simple
strategy. First, it checks whether there is some free memory of the
corresponding size in the heap it manages. If so, this memory is returned.
This means that kaffe won't ever invoke the garbage collector until it
uses more memory than the initial heap size specified using the -ms switch!
Therefore, increasing the initial heap size using -ms will make short-lived
applications, such as pizza, run faster. Garbage collection can be avoided
if an application does not allocate more memory than the initial heap size
during its lifetime.
If there is no memory left in the heap when an allocation is attempted,
Kaffe will invoke the garbage collector. The collector uses a heuristics to
decide whether it should perform a collection or whether it should postpone it.
Postponing a collection means that Kaffe asks the operating system for
more memory, growing its heap. Every time it decides to postpone a collection,
it will ask for the amount of memory specified by the heap increment (-as)
cmdline switch, which defaults to 1MB. Of course, postponing gc is only an
option if the current size of the heap is less than the maximum heap size
specified. If the maximum heap size has already been reached, a collection
will be performed.
If the maximum heap size has not been reached, how does Kaffe decide whether
to grow its heap or whether to garbage collect? Like many things in CS,
it's a classical space-time trade-off. Consider the two extremes:
First, suppose Kaffe always postponed collection until it obtained the
maximum amount of memory from the system. This would mean that collections
would occur less frequently, but it would also mean that most long-running
applications will actually require the full amount of memory specified as
the maximum heap size. This would mean to trade memory for speed.
Trading memory for speed is not always desirable, for instance if the
machine on which you're running has little memory, or if you can't afford
to set the necessary amount of memory aside. In systems using virtual
memory, specifying heap sizes that are too large may lead to the well-known
thrashing effect.
On the other hand, if Kaffe always collected if it ran out, it would collect
more often, but it won't ever use much more memory than the amount of memory
occupied by long-lived and fixed data. This would mean to trade speed for
memory.
Let's look at a hypothetical example:
Suppose an application uses 16MB of long-lived data, and produces
160 MB of short-lived data. Suppose the initial heap size is 5MB and the
maximum heap size is 64MB. The heap increment is also the default, 1MB.
If we always collected, then this application won't ever take more than
17MB, but it will perform 160/(17-16) = 160 collections! On the other hand, if
we used all the available memory, then the application would use 64MB, but
only perform 160/(64-16) = 4 collections.
[ You might say: but wait, the cost of each of the 160 collections will be
lower than the cost of the 4 collections in the second case. This is not
true, however. The costs of Kaffe's mark-and-sweep algorithm is the sum
of the costs of marking the heap and sweeping it. The costs of sweeping
is linear in the total number of objects freed --- which is the same no
matter how frequently you collect. However, the costs of marking only
depends on the amount of live data, which is roughly equivalent to the
amount of long-lived data. Hence, this cost is the same in both cases,
but since this cost must be paid per collection, fewer collections will
be faster. ]
So, what does Kaffe do to find the sweet spot between not collecting too
often and not using too much memory? It looks at how much memory has been
allocated since the last time a collection happened. If this amount of
memory is less than 1/3 of the total amount of memory in use, then the
collection is skipped. In our hypothetical example above, Kaffe would
use 24MB (since it will grow to 24MB in 1MB increments.) Every time 8MB
of short-lived data have been added to the long-lived data occupying 16MB,
kaffe will collect and free 8MB. Hence, it will perform 160/(24-16) = 20
collections instead of 160 or 4.
Of course, if you have 64MB to spare, running Kaffe with '-ms 64M' is
always your option and will require only 4 collections.
Why 1/3? It's just a number I pulled out of my hat. Asymptotically, the
number means that Kaffe's heap will always have 33% free memory after a
gc. Using the -verbosegc option will tell you how much it actually is.
If you know of a better heuristics --- maybe one that takes other factors
than the amount of memory allocated since the last collection into account,
we'd certainly all like to know about it. Possible candidates for such
factors are the time elapsed since the start of the program, the time it
takes to mark the heap, the time it takes to sweep freed objects, the length
of the finalizer list, and the phase of the moon.
Note that the discussion and the number in this FAQ are somewhat hypothetical
and do not take various overheads into account. In particular, they do not
account for Kaffe's unfortunate tendency to keep more temporary garbage afloat
than it probably should. However, we're still working on improving Kaffe's
collector.
Thanks to Jason Baker and Archie Cobbs for contributing to the discussion
above. Any comments and suggestions for improvements are welcome.
- Godmar Back <gback@cs.utah.edu>
1/5/99
kaffe-1.0b4/FAQ/FAQ.hotjava 644 624 310 1330 6654133704 10324
HotJava does not currently run with kaffe and it is very unlikely that
the current HotJava version (1.1.5) ever will.
The reason is that HotJava is not 100% pure Java. It relies upon
classes from the proprietary sun.* hierarchy. References to such classes
are hardcoded in HotJava's code.
To make matters worse, it not only relies on classes that have
native methods (which would allow the kaffe user to simply use Sun's
classes.zip by appending it to the CLASSPATH), but it relies on classes
that have undocumented native methods, for instance for gif image
processing or inqueries about the state of the VM.
HotJava even bypasses equivalent, documented interfaces provided by
classes in the java.awt hierarchy.
kaffe-1.0b4/FAQ/FAQ.install-root 644 624 310 2705 6646471716 11337
Setting an "install root" directory
-----------------------------------
If you want to build and package kaffe on one machine, but actually
run it on another machine, you may want to set an "install root"
directory.
Setting an install root directory only affects "make install". It
causes every install target directory to be prefixed with the install
root directory. The default install root directory is just /.
For example, if you say:
$ ./configure --prefix=/usr/local
$ make
$ make install
this does two things:
1. Kaffe is compiled in such a way that it expects to live in
/usr/local, and this is where it will look for certain files
at runtime.
2. The "make install" step will install everything under /usr/local.
Setting an install root affects step #2 only -- not step #1.
To set the install root directory to /tmp/kaffe-build, for example,
add the "DESTDIR=/tmp/kaffe-build" argument to `make install':
$ ./configure --prefix=/usr/local
$ make
$ make install DESTDIR=/tmp/kaffe-build
If you do the above steps, then kaffe will still expect to live in
/usr/local, but "make install" will install everything under
/tmp/kaffe-build/usr/local instead of just /usr/local. Note, however,
that this may break libtool shared libraries on some platforms.
Then you can tar up the /tmp/kaffe-build directory, take it to your
target machine and install it, etc.
-Archie Cobbs <archie@whistle.com>, Alexandre Oliva <oliva@dcc.unicamp.br>
kaffe-1.0b4/FAQ/FAQ.jsignal 644 624 310 17202 6654123053 10340
Kaffe: Signals & jthreads
-------------------------
by Patrick Tullmann and Godmar Back
<tullmann@cs.utah.edu> and <gback@cs.utah.edu>.
This document is an attempt to describe the behavior of signals and
threads in Kaffe, specifically in the jthread threading system. Other
threading systems in Kaffe should be similar. It is hoped that folks
trying to port Kaffe to other operating systems will use this document
to figure out just what Kaffe needs in terms of signal and
setjmp/longjmp support so they can match it to what their OS provides.
Kaffe uses signals for:
Timeslice expiration for pre-emption (SIGVTALRM).
Timeouts on Object.wait()s, Thread.sleep()s (SIGALRM).
Asynchronous notification of I/O readiness (SIGIO).
Synchronous processor errors (SIGFPE, SIGSEGV, SIGBUS).
Asynchronous notification of a child's death (SIGCHLD).
Cleaning up fds before dying (SIGINT, SIGTERM).
SIGPIPE is ignored (see initExceptions() in baseClasses.c).
All other signals have their default behavior.
Neither of the user signals (SIGUSR1 and SIGUSR2) are used for
anything in jthreads. (In Godmar's Linux threads port for
Kaffe, the user signals are used for stopping kernel threads.)
(Oh, and Godmar once used SIGUSR1 for prompting the VM to
dump all sorts of thread info when its received.)
Signals can be grouped into two categories: asynchronous and
synchronous. Synchronous signals are a direct result of the current
thread's immediate action: SIGFPE, SIGSEGV, and SIGBUS. Asynchronous
signals are those that are not a direct and immediate result of the
currently executing thread's actions: SIGVTALRM, SIGALRM, SIGIO,
SIGCHLD. SIGINT and SIGTERM are terminal signals and are not
classified as either synchronous nor asynchronous.
Signals are handled by whatever thread is currently executing.
Signals are handled on the currently executing thread's stack.
Several operating systems support a separate "signal stack" for
handling signals. Kaffe does not use separate signal stacks because
the GC thread-stack-walk function requires that the registers in
use when the signal arrived be visible. In the current scheme those
registers are pushed onto the thread's stack, so they are directly
visible to the stack walking code. This is believed to be the only
barrier to using a separate signal stack.
In this document "signal state" refers to whatever OS state is saved
and restored when sigsetjmp() is given a non-zero second argument. We
assume that this signal state only includes the mask of blocked
signals. If a system includes other information in its signal state,
the signal handlers will have to clean that state up before
longjmp()'ing anywhere.
Synchronous Signals
-------------------
For synchronous signals, the handling thread is the thread which
caused the problem. How the signal is transformed into a Java
exception is different in the interpreter and the JIT. The important
point is that for synchronous signals, the signal handler *never*
returns, it unilaterally jumps directly to the exception handler.
For the interpreter, a setjmp() point was created for each exception
handler entry point as the first bytecode covered by the handler was
executed. The signal handler will longjmp() to this point to handle
the exception. All of the setjmp()'s occur in the context of the
virtualMachine() function in intrp/machine.c; virtualMachine()
recurses for each Java method invocation, so the context of the
setjmp() is always valid. The longjmp() to the handler deals with
"unwinding" the stack, if necessary. The setjmp() need not include
signal state as the signal handler will clean up the signal state
before longjmp()'ing to the exception handler.
The JIT keeps information on code ranges covered by each exception
handler in a method. When a synchronous exception is dispatched out
of the signal handler, the appropriate location is looked up in the
per-method exception tables, and CALL_KAFFE_EXCEPTION() is invoked.
This method (on FreeBSD, at least) does an (asm) jmp to the
appropriate native code to handle the exception after "unwinding" the
stack. Since the signal handler for synchronous signals in the JIT
never returns, the signal handler must clean up the current signal
state before jumping off into the exception handler. This entails
(potentially) restoring the signal handler and (potentially)
unblocking the signal. (Some OS's disable the signal handler on first
use, others don't. Some OS's block signals before entering a signal
handler, others don't.)
Asynchronous Signals
--------------------
Asynchronous signals are handled by a thread which is not necessarily
involved in the action which triggered the signal. For example, if a
SIGIO comes in, the handler might put threads which are blocked on the
appropriate I/O channel onto the runnable queue, and then return. As
another example if thread A is running and a SIGVTALRM signal is
delivered, thread A might enter the thread scheduling code, pick a
new thread, B, and longjmp() to B's setjmp() point from when it was
preempted or blocked. Eventually, thread A will be rescheduled and
will return from the signal handler into the context where the
original SIGVTALRM interrupted it. (Note that rescheduling might
happen as a result of a SIGIO---for example, if a higher priority
thread was waiting on the IO channel.)
Because a signal handler might longjmp() into any thread, the signal
state of the Kaffe process must be clean before the longjmp(). If we
jumped into a thread and left all the asynchronous signals blocked,
the system would grind to a halt.
The Optimization
----------------
When a thread blocks (for example on a mutex, in a wait(), due to
yield(), or in a sleep()) the thread has no interesting signal state
associated with it. Saving and restoring this state is potentially a
great waste of time. (On FreeBSD the cost of a context switch
decreases from 1,400 cycles to 240 cycles on a P2-300 when signal
state is appropriately ignored.) Thus, we make sure that the process
signal state is clean before longjmp()'ing out of a signal handler.
Signals, Setjmp() and Platform Dependencies
---------------------------------
Some platforms need to re-install a signal after it arrives. By
default, Kaffe calls reinstallSignalHandler() when it feels safe in
re-enabling the signal. On some platforms this call may be no-op'd.
For integrity, Kaffe requires that when handling any asynchronous
signal *all* other asynchronous signals are delayed. Asynchronous
signals should be delayed until the signal handler returns, or the
signal handler explictly unblocks them (unblockAsyncSignals()). (The
set of signals to delay while handling signal X is specified by the
sa_mask field used in the sigaction() call for signal X---see
registerAsychSignalHandler() in exception.c.) (NOTE: If delay of all
asynchronous signals cannot be guaranteed, the race condition between
checking blockints and disabling interrupts in interrupt() will have
to be solved in some other fashion.)
For synchronous signals, no signals should be delayed during the
execution of the signal handler. Most systems will always delay
signal X when handling signal X. The system must support explicitly
re-enabling the signal as the synchronous signal handlers never return
(thus, the OS will not get a chance to restore the signal state).
Kaffe requires that sigsetjmp() and siglongjmp() save and restore
signal state when indicated (the second parameter on the sigsetjmp is
non-zero). It is sufficient for correctness if all setjmp/longjmp
calls save and restore signal state, its just overkill. It should be
true that the second parameter to sigsetjmp() is always zero, so the
system should never have to save or restore signal state for a setjmp
or longjmp.
kaffe-1.0b4/FAQ/FAQ.libtool 644 624 310 6070 6703447375 10351 Kaffe has adopted GNU libtool to ease the creation of shared
libraries, where available, and static libraries, where shared
libraries are unavailable or undesirable. Whether a library is shared
or static is totally transparent to the application that uses libtool
and to the user.
Any libtool library can be made static by adding -static to its link
command. You can do that manually by removing the .la file in the
corresponding directory and running `make AM_CFLAGS=-static' within
that directory, then running make in the top-level directory.
In order to provide dynamic linking, or simulate it, Kaffe uses
libltdl, a library that is part of libtool. It currently supports the
following dlopening mechanisms: dlopen, shl_load, GNU DLD, BeOS'
load_add_on and MS-Windows' LoadLibrary.
Additionally, it supports dlopening simulation for platforms that lack
shared libraries (or have shared libraries disabled) through the
dlpreopen mechanism, in which a symbol table is created when the
program is linked and it -dlopens a set of libraries. If any of these
libraries is static, libtool will link the library into the program
and add its symbols to the dlpreopening symbol table. It's that
simple.
In order to implement this dlpreopening mechanism, libltdl needs some
help from the main application. Therefore, a call to
lt_dlpreopen_default() was added to kaffe/kaffe/main.c. In order to
support dlopening simulation, any other application that links with
libkaffevm should also be linked using libtool, and it should be
created with the flag -export-dynamic, so that the symbol table is
created.
By default, on platforms that lack dlopening mechanisms, Kaffe will be
linked with its own libraries only. You may extend this list of
libraries by setting the JAVA_LIBS flag to a list of libtool (.la) or
regular (.a/.so/.sl/.lib) libraries.
If the same symbol is defined in more than one library, it is possible
that linking (either static or dynamic) fails. If it does not fail,
which symbol libltdl will select for a given name depends on the
sequence of dlopening of the libraries, and the mechanism libltdl uses
to dlopen them.
By default, libtool compiles each file that may become part of a
library twice. It does so because a file must be compiled with PIC
(position independent code) in order to become part of a shared
library, but this sometimes imposes some overhead, and libtool
believes that a static library shouldn't impose this overhead.
Therefore, libtool uses an object file with PIC to build a shared
library, and one without PIC for static libraries.
Kaffe changes this libtool default so as to avoid double compilation,
so you'll get only PIC object files if shared libraries are supported
and not disabled, and only non-PIC ones otherwise. You may force
non-PIC objects to be created with --enable-static; you may force
libtool not to create shared libraries by configuring
--disable-shared. In fact, --disable-shared is almost equivalent to
--with-staticlib --with-staticvm; the only difference is that
--with-staticlib does not affect libltdl, whereas --disable-shared
does.
--
oliva
kaffe-1.0b4/FAQ/FAQ.linux 644 624 310 1520 6552662340 10030 FAQ for Linux
=============
Doesn't work on Linux 1.2.13
----------------------------
Kaffe is no longer supported on Linux 1.2.13. This is because of a limitation
in the shared library implementation on this system. You should still
be able to use Kaffe in static library mode however (but don't quote me).
No 'dlopen' and 'dlsym'
-----------------------
Some verison of Linux fail to locate the dynamic library loading code
during configure. This fault usually manifests itself during linking
as a failure to find 'dlopen' and 'dlsym'. To fix this problem you will
need to create a sybolic link as follows:
ln -s libdl.so.xx.xx /lib/libdl.so
Where 'xx.xx' is the version number of this library (ls -l /lib/libdl.so.*
should tell you this).
Once this has been done rebuild as follows:
make distclean
./configure
make
make install
kaffe-1.0b4/FAQ/FAQ.nativemethods 644 624 310 1324 6552662340 11545 From: Paul M Reilly <pmr@preilly.bbn.com>
Q. What's it take to get native code running in Kaffe?
A. For the most part, follow the steps described in various Java texts
(e.g. ``teach yourself Java in 21 days'', Chapter 20, or Chapter 13 of
``Programming with Java!''). The major gotcha is in the naming of the
shared library. If you are building a library to handle display
functions, loading it with the following Java code,
public class Display {
public native void toScreen();
static {
System.loadLibrary("Display");
}
}
then make sure to name the library "libDisplay.so" and put the
library in a directory that is listed in the LD_LIBRARY_PATH
environment variable.
kaffe-1.0b4/FAQ/FAQ.requiredlibraries 644 624 310 1426 6661347022 12411
To use all functionality provided by Kaffe, you need some freely available
libraries installed on your system.
Some of these libraries are absolutely required, in other cases, the
configure script detects whether the library is available and uses it
if so. If your library is installed is not installed in a standard
place where your compiler and linker finds it, you need to tell
configure where to find it.
<Alexandre explains how you do that with an example>
libungif 4.0: You need libungif 4.0 if you want Kaffe's awt to be
able to decompress gif images. Note that earlier versions will not
work. You can get libgif from:
http://prtr-13.ucsc.edu/~badger/software/libungif.shtml
libz: You need libz to use the functionality in java.util.zip
<Complete this list>
kaffe-1.0b4/FAQ/FAQ.timing 644 624 310 1503 6631360040 10147 The new timing mechanism allows arbitrary portions of vm execution to
be measured. When configured --with-timing, kaffe will print a
summary of all timings measured on exit.
Usage is simple:
#include "support.h"
foo()
{
static timespent spent;
startTiming(&spent, "foo");
...
stopTiming(&spent);
}
When kaffe is configured for timing, the macro TIMING is defined and
this code does something useful. When not configured for timing,
these statements are mostly harmless:
/* We either can't or wont perform timing: The first macro suppresses
unused variable warnings. */
typedef char timespent;
#define startTiming(C,N) (*(C) = 0)
#define stopTiming(C)
The timing mechanism counts the number of calls to startTiming for
each timespent structure, and measures user time with getrusage.
kaffe-1.0b4/FAQ/FAQ.unicode 644 624 310 4627 6700347457 10336 Kaffe Unicode Database.
Kaffe use a compressed form of the Unicode 2.1 database for
the java.lang.Character class.
The Unicode 2.1 database, have lot of usefull compression properties.
The class java.lang.Character uses a subset of the the Unicode properties:
. The category [getType()]
. The decimal digit value [digit()]
. The numeric value [getNumericValue()]
. The uppercase, lowercase and titlecase equivalent [toUpperCase(),
toLowerCase(), toTitleCase()]
Unicode compression properties:
. few characters have a titlecase equivalent different than the uppercase.
[uppercase and titlecase of true titlecase character, category "Lt"]
. few characters have a numeric value and a case equivalent.
[roman numeric letters, category "Nl"]
. all digit number "Nd" have the same decimal digit value than the numeric
value.
Then, we define two character properties format, small and extended.
Small character proteries format:
. the category
. whitch field (none, numeric value, uppercase, lowercase)
. the generic value
xFFCCCCC GGGGGGGG GGGGGGGG
Extended character properties format:
. the category
. the numeric value
. the uppercase equivalent
. the lowercase equivalent
. the titlecase equivalent
xxxCCCCC NNNNNNNN NNNNNNNN UUUUUUUU UUUUUUUU
LLLLLLLL LLLLLLLL TTTTTTTT TTTTTTTT
Consecutives entries in the Unicode 2.1 database could be grouped with
the following rules:
. not compressed
consecutive entries don't have the same category or the same field
or the same value nor one increment.
[U+0028 - U+002D]
. compressed same value:
consecutive entries have the same category, the same field and the
same generic value.
[U+0000 - U+001F, control, no field]
. compressed one increment:
consecutive entries have the same category, the same field and the
same increment (one) for the generic value.
[U+0041 - U+005A (A-Z) uppercase letter, one increment for lowercase]
. not compressed, extended entry:
consecutive entried that have more than one field.
[U+2160 - U+216F (Roman number)]
To handle all these range, we create an index with the format:
SSSSSSSS SSSSSSSS EEEEEEEE EEEEEEEE xxMMOOOO OOOOOOOO OOOOOOOO
S: start unicode value for this range
E: end unicode value for this range
M: compression method
O: offset in the properties table.
The Perl script unicode.pl creates two files
. unicode.idx the ranges index
. unicode.tbl the properties tables
Edouard G. Parmelan <egp@quadratec.fr>
March 27, 1999
kaffe-1.0b4/FAQ/FAQ.win32 644 624 310 763 6552662340 7623 FAQ for Cygnus Win32
====================
I don't in general to get into debugging installations of Cygnus's Win32
environment. However a few problems come up often:
Failure to create temporary files during configuration
------------------------------------------------------
Often the configuration doesn't work correctly and reports the failure
to create odd files, usually with names like 921345. This means you don't
have the expected temp. directory. Make sure you have created 'c:\tmp'.
kaffe-1.0b4/developers/ 755 624 310 0 6703462467 10111 5 kaffe-1.0b4/developers/JavaClass.pm 644 624 310 63054 6660670355 12345 #
# Functions for reading in and writing out a Java .class file.
# Also does a bit of consistency checking of the file.
#
# The only really nasty thing I've done (because of poor perl skils more
# than anything else) is to make the %class a local() in a number of
# places so that the check routines can see it.
#
# Class structure: Generally references to hashes. Tables are implemented as arrays.
#
# TODO:
# make a &checkClass() function.
# change a lot of 'local's to 'my's. (not local(%class), though)
# Make CLASSIN and CLASSOUT parameters to read/write functions.
# POD documentation
# Cannot handle modifying float values. I can read and decode, but don't
# have the math to convert back to a binary format (both floats and doubles).
#
# Copyright (c) 1999 University of Utah CSL.
#
# This file is distributed under the terms of the GNU Public License.
#
package JavaClass;
###
### Define constants for Java Classes
###
*classMagic = \0xcafebabe; # The magic header every .class file starts with
## The magic identifiers for entries in the .class Constant Table.
*CONSTANT_Class = \7;
*CONSTANT_FieldRef = \9;
*CONSTANT_MethodRef = \10;
*CONSTANT_InterfaceMethodRef = \11;
*CONSTANT_String = \8;
*CONSTANT_Integer = \3;
*CONSTANT_Float = \4;
*CONSTANT_Long = \5;
*CONSTANT_Double = \6;
*CONSTANT_NameAndType = \12;
*CONSTANT_Utf8 = \1;
## String names associated with each type of Constant Table entry.
%CONSTANTNames = (
$CONSTANT_Class => "Class",
$CONSTANT_FieldRef => "Field",
$CONSTANT_MethodRef => "Method",
$CONSTANT_InterfaceMethodRef => "Inteface Method",
$CONSTANT_String => "String",
$CONSTANT_Float => "Float",
$CONSTANT_Integer => "Integer",
$CONSTANT_Double => "Double",
$CONSTANT_Long => "Long",
$CONSTANT_NameAndType => "Name&Type",
$CONSTANT_Utf8 => "Utf8"
);
## String names for the shorthand used in signatures
$sig{'V'} = 'void';
$sig{'I'} = 'int';
$sig{'J'} = 'long';
$sig{'Z'} = 'boolean';
$sig{'F'} = 'float';
$sig{'D'} = 'double';
$sig{'B'} = 'byte';
$sig{'S'} = 'short';
$sig{'C'} = 'char';
## Access control flags for classes, methods and fields.
*ACC_PUBLIC = \0x0001;
*ACC_PRIVATE = \0x0002;
*ACC_PROTECTED = \0x0004;
*ACC_STATIC = \0x0008;
*ACC_FINAL = \0x0010;
*ACC_SUPER = \0x0020;
*ACC_VOLATILE = \0x0040;
*ACC_TRANSIENT = \0x0080;
*ACC_INTERFACE = \0x0200;
*ACC_ABSTRACT = \0x0400;
*ACC_NATIVE = \0x0100;
*ACC_UNKNOWN = \0xF800;
###
### Global variables
###
# Control the verbosity of &printClass()
$detailedFields = 0;
$detailedMethods = 0;
###
### Conversion functions
###
## parseJavaSig() takes a single argument, a single Java-internal
## method signature and returns a list ($package, $return, $class,
## $method, @args) where the items have been converted to a more
## source-like format (e.g., english).
sub parseJavaSig() {
## Parameters
my $jsig = shift;
## Local variables
my $class = '';
my $package = '';
my $method = '';
my @args = ();
my $ret = '';
## Temporaries
my $depth = 0;
my $repct = 0;
my $arg = '';
### First is the class (all chars until a ".")
$jsig =~ s/^([^.]*).//;
$class = $1;
$class =~ s,/,.,g; # / -> .
# Peel the package name out of the class name (everything before last ".")
if ($class =~ m/(.*)\.[^\.]*$/) {
$package = $1;
}
### Second comes the method name (all chars until a left paren)
$jsig =~ s/^([^\(]*)\(//;
$method = $1;
### Now the arguments
SIGPARSE:
while(1) {
$repct = $jsig =~ s/^(I|J|Z|F|D|B|S|C|L|\[|\))//; ## No V types
die "badly formed signature at $jsig" if ($repct == 0);
$arg = $1;
## Stop if we hit the end paren
last SIGPARSE if $arg eq "\)";
if ($arg eq '[') {
$depth++;
# continue parsing array type...
next SIGPARSE;
} elsif ($arg eq 'L') {
$jsig =~ s/^([^;]*);//;
$arg = $1;
$arg =~ s,/,.,g;
} else {
## convert single-char identifier to english
$arg = $sig{$arg};
}
## If we hit an array, tack the array depth on the end
if ($depth > 0) {
$arg = $arg . "[]" x $depth;
$depth = 0;
}
# Put the arg at the end of the list of args
push (@args, $arg)
}
### Last is the return type
$depth = 0;
$repct = $jsig =~ s/^(I|J|Z|F|D|B|S|C|L|V|\[)//; ## Adds V over argument types
die "badly formed return type: \'$jsig\'" if ($repct == 0);
$ret = $1;
# If its an array, eat the [ and re-set $ret
if ($ret eq '[') {
$depth = 1;
while ($jsig =~ s/\[//) {
$depth++;
}
$jsig =~ s/^(I|J|Z|F|D|B|S|C|L)//; ## No [ or V
die "badly formed return type: \'$jsig\'" if ($repct == 0);
$ret = $1;
}
if ($ret eq 'L') {
$jsig =~ s/^([^;]*);//;
$ret = $1;
$ret =~ s,/,.,g;
} else {
## Convert single char identifier to english
$ret = $sig{"$ret"};
}
# Tack the array brackets on
if ($depth > 0) {
$ret = $ret . "[]" x $depth;
}
### Return the info in an easy-to-use list
return ($package, $ret, $class, $method, @args);
}
###
### Print functions
###
sub printClass {
my $r_cl = shift;
my %class = %{$r_cl};
my $flStr = &ACCFlagsToString($class{accessFlags});
print "$flStr\n";
&printConstantPool($r_cl);
## Print 'this_class'
my $thisClName = %{$class{constantPool}[$class{thisClass}]}->{nameIndex};
$thisClName = %{$class{constantPool}[$thisClName]}->{val};
print "this_class @ $class{thisClass} ($thisClName)\n";
## Print 'super_class'
if ($class{superClass} != 0) {
my $superClName = %{$class{constantPool}[$class{superClass}]}->{nameIndex};
$superClName = %{$class{constantPool}[$superClName]}->{val};
print "super_class @ $class{superClass} ($superClName)\n";
} else {
print "No super class\n";
}
## Print direct super interfaces
&printInterfaces($r_cl);
## Print fields
&printFields($r_cl);
## Print methods
&printMethods($r_cl);
## Print attributes
&printAttributes("", $r_cl, $class{attributes});
}
sub printMethods {
my $r_cl = shift;
local(%class) = %{$r_cl};
if ($class{methodCt} == 0) {
print "No fields.\n";
} else {
$i = 0;
print "Methods:\n";
while ($i < $class{methodCt}) {
my %method = %{$class{methods}[$i]};
my $accflags = ACCFlagsToString($method{accessFlags});
my $name = $class{constantPool}[$method{nameIndex}]->{val};
my $desc = $class{constantPool}[$method{descriptorIndex}]->{val};
if ($detailedMethods) {
print ("\t$i: ");
print (".accessFlags=$accflags; ");
print (".name @ $method{nameIndex} ($name); ");
print (".descriptor @ $method{descriptorIndex} ($desc); ");
print (".attrCt = $method{attributesCt};\n");
&printAttributes("\t\t", \%class, $method{attributes});
} else {
print ("\t$accflags $name $desc\n");
}
} continue {
$i++;
}
}
}
sub printFields {
my $r_cl = shift;
local(%class) = %{$r_cl};
if ($class{fieldCt} == 0) {
print "No fields.\n";
} else {
$i = 0;
print "Fields:\n";
while ($i < $class{fieldCt}) {
my %field = %{$class{fields}[$i]};
my $accflags = ACCFlagsToString($field{accessFlags});
my $name = $class{constantPool}[$field{nameIndex}]->{val};
my $desc = $class{constantPool}[$field{descriptorIndex}]->{val};
if ($detailedFields) {
print ("\t$i: ");
print (".accessFlags=$accflags; ");
print (".name @ $field{nameIndex} ($name); ");
print (".descriptor @ $field{descriptorIndex} ($desc); ");
print (".attrCt = $field{attributesCt};\n");
&printAttributes("\t\t", \%class, $field{attributes});
} else {
print ("\t$accflags $desc $name\n");
}
} continue {
$i++;
}
}
}
sub printInterfaces {
my $r_cl = shift;
local(%class) = %{$r_cl};
if ($class{interfaceCt} == 0) {
print "No interfaces.\n";
} else {
my $i = 0;
print "Interfaces:\n";
while ($i < $class{interfaceCt}) {
my $iClass = $class{interfaces}[$i];
my %iClassConst = %{$class{constantPool}[$iClass]};
my $iClassName = $iClassConst{nameIndex};
my $interfaceName = %{$class{constantPool}[$iClassName]}->{val};
print "\t$i] @ $iClass ($interfaceName)\n";
} continue {
$i++;
}
}
}
sub ACCFlagsToString {
my $flags = shift;
my @flags = ();
push(@flags, "public") if $flags & $ACC_PUBLIC;
push(@flags, "private") if $flags & $ACC_PRIVATE;
push(@flags, "protected") if $flags & $ACC_PROTECTED;
push(@flags, "static") if $flags & $ACC_STATIC;
push(@flags, "final") if $flags & $ACC_FINAL;
push(@flags, "super") if $flags & $ACC_SUPER;
push(@flags, "volatile") if $flags & $ACC_VOLATILE;
push(@flags, "transient") if $flags & $ACC_TRANSIENT;
push(@flags, "interface") if $flags & $ACC_INTERFACE;
push(@flags, "abstract") if $flags & $ACC_ABSTRACT;
push(@flags, "native") if $flags & $ACC_NATIVE;
push(@flags, "UNKNOWN") if $flags & $ACC_UNKNOWN;
return join(',', @flags);
}
sub printConstantPool {
my $r_cl = shift;
local(%class) = %{$r_cl}; # cvt the class reference to the class hash
print("Constant Pool Entries: $class{constantPoolCt}\n");
$i = 1;
while ($i < $class{constantPoolCt}) {
my %cpEntry = %{$class{constantPool}[$i]};
print "$i] $CONSTANTNames{$cpEntry{tag}}: ";
if ($cpEntry{tag} eq $CONSTANT_Class) {
my $ni = $cpEntry{nameIndex};
&checkIndex($ni, "Name", $CONSTANT_Utf8);
my $nm = $class{constantPool}[$ni]->{val};
print (".name @ $ni ($nm);");
} elsif (($cpEntry{tag} eq $CONSTANT_FieldRef)
|| ($cpEntry{tag} eq $CONSTANT_MethodRef)
|| ($cpEntry{tag} eq $CONSTANT_InterfaceMethodRef)) {
&checkIndex($cpEntry{classIndex}, "Class", $CONSTANT_Class);
&checkIndex($cpEntry{nameTypeIndex}, "Name & Type", $CONSTANT_NameAndType);
print (".class @ $cpEntry{classIndex}; .name&type @ $cpEntry{nameTypeIndex};");
} elsif ($cpEntry{tag} eq $CONSTANT_String) {
my $si = $cpEntry{stringIndex};
&checkIndex($si, "String", $CONSTANT_Utf8);
my $str = $class{constantPool}[$si]->{val};
print (".string @ $cpEntry{stringIndex} ($str);");
} elsif ($cpEntry{tag} eq $CONSTANT_NameAndType) {
my $ni = $cpEntry{nameIndex};
my $di = $cpEntry{descriptorIndex};
&checkIndex($ni, "Name", $CONSTANT_Utf8);
&checkIndex($di, "Descriptor", $CONSTANT_Utf8);
my $nstr = $class{constantPool}[$ni]->{val};
my $dstr = $class{constantPool}[$di]->{val};
print (".name @ $ni ($nstr); .descriptor @ $di ($dstr); ");
} elsif ($cpEntry{tag} eq $CONSTANT_Integer) {
print (".value = $cpEntry{val}");
} elsif ($cpEntry{tag} eq $CONSTANT_Utf8) {
print (".length=$cpEntry{len}; ");
print (".val=$cpEntry{val}; ");
} elsif ($cpEntry{tag} eq $CONSTANT_Float) {
print (".val=$cpEntry{strVal}; ");
} elsif ($cpEntry{tag} eq $CONSTANT_Double) {
print (".val=$cpEntry{strVal}; ");
$i++; ## Ick. 8-byte entries take two constant pool entries
} elsif ($cpEntry{tag} eq $CONSTANT_Long) {
print (".val=$cpEntry{strVal}; ");
$i++; ## Ick. 8-byte entries take two constant pool entries
} else {
&fatal("Unknown Constant type $cpEntry{tag}!\n");
}
print ("\n");
$i++;
}
}
sub printAttributes {
my ($prefix, $r_class, $r_attrs) = @_;
return if (!defined($r_attrs));
my $i = 0;
my %class = %{$r_class};
print ("${prefix}Attributes:\n");
foreach $r_attr (@{$r_attrs}) {
my $name = $class{constantPool}[$r_attr->{nameIndex}]->{val};
print ("${prefix}\t.name=$name; ");
print (".length=" . $r_attr->{len} . ";");
if ($name eq 'SourceFile') {
if ($r_attr->{len} != 2) {
print ("!Badly formed SourceFile Attribute, must be 2!");
} else {
my ($high, $low) = unpack("CC", $r_attr->{attr});
my $idx = ($high * 256) + $low;
my $name = $class{constantPool}[$idx]->{val};
print (" @ " . $idx . " (\"" . $name . "\")");
}
}
print ("\n");
}
}
###
### Read Class function
###
sub readClass {
my $classFile = shift;
local(%class) = (());
open(CLASSIN, $classFile)
|| open(CLASSIN, "${classFile}.class")
|| die ("Cannot open $classFile for reading");
###
### Header Magic
###
$class{magic} = read_u4();
if ($class{magic} != $classMagic) {
fatal("Bad class magic '$class{magic}' --expected '$classMagic'. $classFile is probably not a Java class file.");
}
## Read in the major and minor version numbers
$class{minorVersion} = &read_u2();
$class{majorVersion} = &read_u2();
print("Version: $class{majorVersion}.$class{minorVersion} (expected 45.3)\n")
if ($class{minorVersion} ne 3) || ($class{majorVersion} ne 45);
###
### Constant Pool
###
$class{constantPoolCt} = &read_u2();
$class{constantPool} = [];
$i = 1; # constant pool actually starts with entry 1...
while ($i < $class{constantPoolCt}) {
my %cpEntry;
$cpEntry{tag} = &read_u1();
if ($cpEntry{tag} eq $CONSTANT_Class) {
$cpEntry{nameIndex} = &read_u2();
&checkIndex($cpEntry{nameIndex}, "Name");
} elsif ($cpEntry{tag} eq $CONSTANT_FieldRef) {
$cpEntry{classIndex} = &read_u2();
$cpEntry{nameTypeIndex} = &read_u2();
&checkIndex($cpEntry{classIndex}, "Class");
&checkIndex($cpEntry{nameTypeIndex}, "Name & Type");
} elsif ($cpEntry{tag} eq $CONSTANT_MethodRef) {
$cpEntry{classIndex} = &read_u2();
$cpEntry{nameTypeIndex} = &read_u2();
&checkIndex($cpEntry{classIndex}, "Class");
&checkIndex($cpEntry{nameTypeIndex}, "Name & Type");
} elsif ($cpEntry{tag} eq $CONSTANT_InterfaceMethodRef) {
$cpEntry{classIndex} = &read_u2();
$cpEntry{nameTypeIndex} = &read_u2();
&checkIndex($cpEntry{classIndex}, "Class");
&checkIndex($cpEntry{nameTypeIndex}, "Name & Type");
} elsif ($cpEntry{tag} eq $CONSTANT_String) {
$cpEntry{stringIndex} = &read_u2();
&checkIndex($cpEntry{stringIndex}, "String");
} elsif ($cpEntry{tag} eq $CONSTANT_NameAndType) {
$cpEntry{nameIndex} = &read_u2();
$cpEntry{descriptorIndex} = &read_u2();
&checkIndex($cpEntry{nameIndex}, "Name");
&checkIndex($cpEntry{descriptorIndex}, "Descriptor");
} elsif ($cpEntry{tag} eq $CONSTANT_Integer) {
$cpEntry{val} = &read_u4();
} elsif ($cpEntry{tag} eq $CONSTANT_Utf8) {
$cpEntry{len} = &read_u2();
$cpEntry{val} = &read_utf8($cpEntry{len});
} elsif ($cpEntry{tag} eq $CONSTANT_Float) {
$cpEntry{val} = &read_u4();
$cpEntry{strVal} = &read_float($cpEntry{val});
} elsif ($cpEntry{tag} eq $CONSTANT_Double) {
$cpEntry{val} = &read_u8();
$cpEntry{strVal} = &read_double($cpEntry{val});
} elsif ($cpEntry{tag} eq $CONSTANT_Long) {
$cpEntry{val} = &read_u8();
$cpEntry{strVal} = "<Unknown>";
} else {
&fatal("Unknown Constant type $cpEntry{tag}!\n");
}
$class{constantPool}[$i] = \%cpEntry;
## Ick. 8-byte entries take two constant pool entries
$i++ if (($cpEntry{tag} == $CONSTANT_Long)
|| ($cpEntry{tag} == $CONSTANT_Double));
} continue {
$i++;
}
###
### Misc. Class Info
###
$class{accessFlags} = &read_u2();
$class{thisClass} = &read_u2();
&checkIndex($class{thisClass}, "this_class", $CONSTANT_Class);
$class{superClass} = &read_u2();
if ($class{superClass} != 0) {
&checkIndex($class{superClass}, "super_class", $CONSTANT_Class);
} else {
print ("Warning: class has no super class. Must be java.lang.Object\n");
}
###
### Direct super-interfaces
###
$class{interfaceCt} = &read_u2();
$class{interfaces} = [];
$i = 0;
while ($i < $class{interfaceCt}) {
$class{interfaces}[$i] = &read_u2();
&checkIndex($class{interfaces}[$i], "Interface \#$i", $CONSTANT_Class);
} continue {
$i++;
}
###
### Fields
###
$class{fieldCt} = &read_u2();
$class{fields} = [];
$i = 0;
while ($i < $class{fieldCt}) {
my %field;
$field{accessFlags} = &read_u2();
$field{nameIndex} = &read_u2();
$field{descriptorIndex} = &read_u2();
$field{attributesCt} = &read_u2();
$field{attributes} = &readAttributes($field{attributesCt});
&checkIndex($field{nameIndex}, "Field Name", $CONSTANT_Utf8);
&checkIndex($field{descriptorIndex}, "Field Descriptor", $CONSTANT_Utf8);
$class{fields}[$i] = \%field;
} continue {
$i++;
}
###
### Methods
###
$class{methodCt} = &read_u2();
$class{methods} = [];
$i = 0;
while ($i < $class{methodCt}) {
my %method;
$method{accessFlags} = &read_u2();
$method{nameIndex} = &read_u2();
$method{descriptorIndex} = &read_u2();
$method{attributesCt} = &read_u2();
$method{attributes} = &readAttributes($method{attributesCt});
&checkIndex($method{nameIndex}, "Method Name", $CONSTANT_Utf8);
&checkIndex($method{descriptorIndex}, "Method Descriptor", $CONSTANT_Utf8);
$class{methods}[$i] = \%method;
} continue {
$i++;
}
###
### Class attributes
###
$class{attributesCt} = &read_u2();
$class{attributes} = &readAttributes($class{attributesCt});
###
### End of .class file
###
return \%class;
}
###
### Write Class function
###
sub writeClass {
my $r_class = shift;
my $classFile = shift;
local(%class) = %{$r_class};
if ($classFile =~ /\.class$/) {
open(CLASSOUT, ">$classFile")
|| die ("Cannot open $classFile for writing");
} else {
open(CLASSOUT, ">$classFile.class")
|| die ("Cannot open $classFile.class for writing");
}
###
### Header Magic
###
if ($class{magic} != $classMagic) {
fatal("Bad class magic '$class{magic}' --expected '$classMagic'. Not writing class file.");
}
&write_u4($class{magic});
## Write major/minor version numbers
&write_u2($class{minorVersion});
&write_u2($class{majorVersion});
###
### Constant Pool
###
&write_u2($class{constantPoolCt});
$i = 1; # constant pool actually starts with entry 1...
while ($i < $class{constantPoolCt}) {
my %cpEntry = %{$class{constantPool}[$i]};
&write_u1($cpEntry{tag});
if ($cpEntry{tag} eq $CONSTANT_Class) {
&checkIndex($cpEntry{nameIndex}, "Name", $CONSTANT_Utf8);
&write_u2($cpEntry{nameIndex});
} elsif (($cpEntry{tag} eq $CONSTANT_FieldRef)
|| ($cpEntry{tag} eq $CONSTANT_MethodRef)
|| ($cpEntry{tag} eq $CONSTANT_InterfaceMethodRef)) {
&checkIndex($cpEntry{classIndex}, "Class", $CONSTANT_Class);
&checkIndex($cpEntry{nameTypeIndex}, "Name & Type", $CONSTANT_NameAndType);
&write_u2($cpEntry{classIndex});
&write_u2($cpEntry{nameTypeIndex});
} elsif ($cpEntry{tag} eq $CONSTANT_String) {
&checkIndex($cpEntry{stringIndex}, "String", $CONSTANT_Utf8);
&write_u2($cpEntry{stringIndex});
} elsif ($cpEntry{tag} eq $CONSTANT_NameAndType) {
&checkIndex($cpEntry{nameIndex}, "Name", $CONSTANT_Utf8);
&checkIndex($cpEntry{descriptorIndex}, "Descriptor", $CONSTANT_Utf8);
&write_u2($cpEntry{nameIndex});
&write_u2($cpEntry{descriptorIndex});
} elsif ($cpEntry{tag} eq $CONSTANT_Integer) {
&write_u4($cpEntry{val});
} elsif ($cpEntry{tag} eq $CONSTANT_Utf8) {
&write_u2($cpEntry{len});
&write_utf8($cpEntry{val});
} elsif ($cpEntry{tag} eq $CONSTANT_Float) {
&write_u4($cpEntry{val});
} elsif ($cpEntry{tag} eq $CONSTANT_Double) {
&write_u8($cpEntry{val});
$i++; ## Ick. 8-byte entries take two constant pool entries
} elsif ($cpEntry{tag} eq $CONSTANT_Long) {
&write_u8($cpEntry{val});
$i++; ## Ick. 8-byte entries take two constant pool entries
} else {
&fatal("Unknown Constant type $cpEntry{tag}!\n");
}
} continue {
$i++;
}
###
### Misc. Class Info
###
&write_u2($class{accessFlags});
&write_u2($class{thisClass});
&write_u2($class{superClass});
###
### Direct super-interfaces
###
&write_u2($class{interfaceCt});
$i = 0;
while ($i < $class{interfaceCt}) {
&write_u2($class{interfaces}[$i]);
} continue {
$i++;
}
###
### Fields
###
&write_u2($class{fieldCt});
$i = 0;
while ($i < $class{fieldCt}) {
my %field = %{$class{fields}[$i]};
&write_u2($field{accessFlags});
&write_u2($field{nameIndex});
&write_u2($field{descriptorIndex});
&write_u2($field{attributesCt});
&writeAttributes($field{attributes});
} continue {
$i++;
}
###
### Methods
###
&write_u2($class{methodCt});
$i = 0;
while ($i < $class{methodCt}) {
my %method = %{$class{methods}[$i]};
&write_u2($method{accessFlags});
&write_u2($method{nameIndex});
&write_u2($method{descriptorIndex});
&write_u2($method{attributesCt});
&writeAttributes($method{attributes});
} continue {
$i++;
}
###
### Class attributes
###
&write_u2($class{attributesCt});
&writeAttributes($class{attributes});
###
### End of .class file
###
return \%class;
}
###
### Integrity check functions
###
sub checkIndex {
my ($val, $name, $type) = @_;
# $class is a global
if ($val == 0) {
&fatal("ERROR: Found constant pool index 0 for $name. (Expecting a CONSTANT_$CONSTANTNames{$type} entry.)");
}
if ($val >= $class{constantPoolCt}) {
&fatal("ERROR: $name index for current constant is $val, must be less than $class{constantPoolCt}\n");
}
if (defined($type)) {
my $actualTag = $class{constantPool}[$val]{tag};
if ($actualTag != $type) {
&fatal("ERROR: $name expects a CONSTANT_$CONSTANTNames{$type} entry at $val, but found a CONSTANT_$CONSTANTNames{$actualTag} entry\n");
}
}
}
###
### Read primitives
###
sub read_u8 {
my $long = 0;
(read(CLASSIN, $long, 8) == 8) || die ("premature eof in read_u8()\n");
my ($b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8) = unpack("CCCCCCCC", $long);
return (($b1 << 56) + ($b2 << 48) + ($b3 << 40) + ($b4 << 32)
+ ($b5 << 24) + ($b6 << 16) + ($b7 << 8) + $b4);
}
sub read_u4 {
my $long = 0;
(read(CLASSIN, $long, 4) == 4) || die ("premature eof in read_u4()\n");
my ($top, $highmid, $lowmid, $low) = unpack("CCCC", $long);
return ($top * (256*256*256)) + ($highmid * (256*256)) + ($lowmid * 256) + $low;
}
sub read_u2 {
my $short = 0;
(read(CLASSIN, $short, 2) == 2) || die ("premature eof in read_u2()\n");
my ($high, $low) = unpack("CC", $short);
#print("read_u2: $high, $low\n");
return ($high * 256) + $low;
}
sub read_u1 {
my $byte = 0;
(read(CLASSIN, $byte, 1) == 1) || die ("premature eof in read_u1()\n");
my $val = unpack("C", $byte);
return $val;
}
sub read_n {
my $byteCt = shift;
my $foo = '';
(read(CLASSIN, $foo, $byteCt) == $byteCt) || die ("premature eof in read_n($byteCt)\n");
return $foo;
}
sub read_float {
my $intVal = shift;
return "+INF" if ($intVal == 0x7f800000);
return "-INF" if ($intVal == 0xff800000);
if ((($intVal >= 0x7f800001) && ($intVal <= 0x7fffffff))
|| (($intVal >= 0xff800001) && ($intVal <= 0xffffffff))) {
return "NaN";
}
## Otherwise, convert to a floating point number
$sign = (($intVal >> 31) == 0) ? 1 : -1;
$exponent = (($intVal >> 23) & 0xFF);
$mantissa = ($exponent == 0) ? ($intVal & 0x7fffff) << 1 : ($intVal & 0x7fffff) | 0x800000;
return $sign * $mantissa * 2 ** ($exponent - 150);
}
sub read_double {
my $intVal = shift;
return "+INF" if ($intVal == 0x7f800000);
return "-INF" if ($intVal == 0xff800000);
if ((($intVal >= 0x7f800001) && ($intVal <= 0x7fffffff))
|| (($intVal >= 0xff800001) && ($intVal <= 0xffffffff))) {
return "NaN";
}
## Otherwise, convert to a floating point number
$sign = (($intVal >> 31) == 0) ? 1 : -1;
$exponent = (($intVal >> 23) & 0xFF);
$mantissa = ($exponent == 0) ? ($intVal & 0x7fffff) << 1 : ($intVal & 0x7fffff) | 0x800000;
return $sign * $mantissa * 2 ** ($exponent - 150);
}
sub read_utf8 {
my $byteCt = shift;
my $utf = '';
(read(CLASSIN, $utf, $byteCt) == $byteCt) || die ("premature eof in read_utf8($byteCt)\n");
my $str = unpack("A$byteCt", $utf);
return $str;
}
sub readAttributes {
my ($ct) = @_;
my @attrs = [];
return undef if ($ct < 1);
my $i = 0;
while ($i < $ct) {
my %attribute;
$attribute{nameIndex} = &read_u2();
$attribute{len} = &read_u4();
$attribute{attr} = &read_n($attribute{len});
&checkIndex($attribute{nameIndex}, "Attribute Name", $CONSTANT_Utf8);
$attrs[$i] = \%attribute;
} continue {
$i++;
}
return \@attrs;
}
###
### Write primitives
###
sub write_u4 {
my $val = shift;
print CLASSOUT pack("N", $val);
}
sub write_u2 {
my $val = shift;
print CLASSOUT pack("n", $val);
}
sub write_u1 {
my $byte = shift;
print CLASSOUT pack("C", $byte);
}
sub write_n {
my $val = shift;
print CLASSOUT $val; # XXX assumes $val."length" is 'n'
}
sub write_utf8 {
my $utf8 = shift;
print CLASSOUT $utf8
}
sub writeAttributes {
my $r_attrs = shift;
return if (!defined $r_attrs);
my $i = 0;
foreach $r_attr (@{$r_attrs}) {
my %attribute = %{$r_attr};
&write_u2($attribute{nameIndex});
&write_u4($attribute{len});
&write_n($attribute{attr});
}
}
sub fatal {
print STDERR @_;
print STDERR "\n";
exit 11;
}
1;
# eof
kaffe-1.0b4/developers/README 644 624 310 1277 6700442501 10760
This directory contains various files useful for Kaffe developers.
sp_offset.c: a program that guesses the correct offset of the sp in a
jmpbuf for the jthread threading system.
gdbinit: a gdb macro file to help in debugging kaffe
JavaClass.pm: Perl 5 module for .class file manipulation.
Used by dumpClass.pl and utf8munge.pl
dumpClass.pl: dump the content of a .class file
utf8munge.pl: change the values of utf8 constants of a .class file
Note that both .pl scripts require /usr/local/bin/perl
(or change the first line in the script)
autogen.sh: script to run all of the various auto* programs
in the correct order
unicode.pl: Perl script to generate unicode.idx and unicode.tbl
kaffe-1.0b4/developers/README.unicode 644 624 310 12776 6700347460 12443 From kaffe-core@rufus.w3.org Mon Mar 29 05:07:50 1999
Date: Mon, 29 Mar 1999 15:02:53 +0200
From: Edouard Parmelan <Edouard.Parmelan@quadratec.fr>
To: Kaffe Core Team <kaffe-core@rufus.w3.org>
Subject: Re: Kaffe Unicode Database
Hi,
I have finish it :)
Following, a tar ball with the new java.lang.Character, a FAQ.unicode that
explain the database, the database generator unicode.pl and the generated
database unicode.idx and unicode.tbl.
The inner class CharacterPropetries load the database with the native
method ClassLoader.getSystemResourceAsBytes0() in the same package.
The database files should be places in Klasses.jar under kaffe/lang/.
I don't change any Makefile.am to incorporate them :(
As promiss, I run Mauve for java.lang.Character:
Mauve results for java.lang.Character: 156 of 3579141 tests failed
Let's me explain the 156 failed test:
getNumericValue test:
* FAIL: gnu.testlet.java.lang.Character.getNumericValue (number 6)
It's getNumericValue('A'), see getNumericValue() in unicode test.
unicode test:
getNumericValue()
* 52 characters ``wrong numeric value''
Mauve:
It is not stated that A-Z and a-z should
have getNumericValue() (as it is in digit())
JDK1.2
public static int getNumericValue(char ch)
Returns the Unicode numeric value of the character as a nonnegative
integer. If the character does not have a numeric value, then -1 is
returned. If the character has a numeric value that cannot be
represented as a nonnegative integer (for example, a fractional value),
then -2 is returned.
Kaffe
as JDK1.2 says :)
isLowerCase()
* 68 characters ``incorectly reported as lowercase''
* 1 character ``incorectly reported as not-lowercase''
Mauve
// NOTE: JLS doesn't say anything about `Ll'
// category. And Unicode 2.1.8 has some
// characters which might be considered
// lowercase by all the other rules, but which
// are not marked Ll -- e.g., 0x0345. So we
JDK1.2
public static boolean isLowerCase(char ch)
Determines if the specified character is a lowercase character.
A character is lowercase if it is not in the range '\u2000'
through '\u2FFF', the Unicode attribute table does not specify
a mapping to lowercase for the character, and at least one of
the following is true:
+ The attribute table specifies a mapping to uppercase for the character.
+ The name for the character contains the words "SMALL LETTER".
+ The name for the character contains the words "SMALL LIGATURE".
A character is considered to be lowercase if and only if it is
specified to be lowercase by the Unicode 2.0 standard (category
"Ll" in the Unicode specification data file).
Kaffe
use the category "Ll".
isUpperCase()
* 31 characters ``incorectly reported as uppercase''
Mauve
// NOTE: JLS doesn't say anything about `Lu'
// category. And Unicode 2.1.8 has some
// characters which might be considered
// uppercase by all the other rules, but which
// are not marked Lu -- e.g., 0x03d2. So we
// don't check for this.
JDK1.2
public static boolean isUpperCase(char ch)
Determines if the specified character is an uppercase character.
A character is uppercase if it is not in the range '\u2000'
through '\u2FFF', the Unicode attribute table does not specify
a mapping to uppercase for the character, and at least one of
the following is true:
+ The attribute table specifies a mapping to lowercase for the character.
+ The name for the character contains the words "CAPITAL LETTER".
+ The name for the character contains the words "CAPITAL LIGATURE".
[ says nothing about category "Lu" in Unicode 2.0 :( ]
Kaffe
use category "Lu".
isWhitespace()
* 1 character ``incorectly reported as not-whitespace''
JDK1.2 says:
+ It is a Unicode space separator (category "Zs"), but is not a
no-break space (\u00A0 or \uFEFF).
In Unicode 2.1.8:
U+00A0 Zs, noBreak
U+2007 Zs, noBreak
but
U+FEFF Cf (Other, Format)
Kaffe
use category "Zs" and decomposition <noBreak> from Unicode 2.1.8
toTitleCase()
* 2 characters ``has wrong titlecase form''
Mauve
use the uppercase if the caracter don't have titlecase in
the Unicode database.
JDK1.2
Converts the character argument to titlecase. A character has a
titlecase equivalent if and only if a titlecase mapping is
specified for the character in the Unicode attribute table.
Note that some Unicode characters in the range '\u2000' through
'\u2FFF' have titlecase mappings; this method does map such
characters to their titlecase equivalents even though the
method isTitleCase does not return true for such characters.
There are only four Unicode characters that are truly titlecase
forms that are distinct from uppercase forms. As a rule, if a
character has no true titlecase equivalent but does have an
uppercase mapping, then the Unicode 2.0 attribute table
specifies a titlecase mapping that is the same as the uppercase
mapping.
Unicode 2.1.8
U+0345 and U+1EFB don't have titlecase mapping.
Kaffe
return U+0000 for toTitleCase(U+0345) and toTitleCase(U+1EFB)
TODO:
Run mauve java.lang.Character with Sun JDK, as I don't have it any more,
I can't run it :(
Comments are wellcome,
Edouard
--
Edouard G. Parmelan Ingenieur Developpeur
Quadratec - Parc Club "Orsay Universite" - 14/16,rue Jean Rostand
91893 Orsay Cedex - FRANCE Phone (+33)1 69 33 20 80
Email: edouard.parmelan@quadratec.fr
kaffe-1.0b4/developers/autogen.sh 644 624 310 275 6672266257 12077 #! /bin/sh
# This script runs all of the various auto* programs in the correct order.
# Written by Mo DeJong.
aclocal -I .
autoheader -l config
automake --add-missing --verbose
autoconf
kaffe-1.0b4/developers/dumpClass.pl 755 624 310 1666 6660670355 12414 #!/usr/local/bin/perl -w
#
# Dump a java .class file to stdout
#
#
# Copyright (c) 1999 University of Utah CSL.
#
# This file 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.
#
# Written by Patrick Tullmann <tullmann@cs.utah.edu>
#
use JavaClass;
# Control the verbosity of &printClass()
$JavaClass::detailedFields = 0;
$JavaClass::detailedMethods = 0;
## Parse the command line
my $classFile = shift || &usage();
## Read/parse the class file
my $class = &JavaClass::readClass($classFile);
## Print the class filea
&JavaClass::printClass($class);
###
###
###
sub usage() {
print STDOUT "Usage:\n";
print STDOUT " dumpClass.pl