From 3a5f5900ebb2b3f0fc418b5a6a0d551db494fc12 Mon Sep 17 00:00:00 2001 From: cacao Date: Sat, 3 Oct 1998 19:18:05 +0000 Subject: [PATCH] Initial revision --- COPYRIGHT | 30 + Makefile | 159 ++ README | 31 + alpha/asmpart.c | 1125 ++++++++++++++ alpha/calling.doc | 182 +++ alpha/cray.c | 358 +++++ alpha/defines.h | 19 + alpha/disass.c | 301 ++++ alpha/gen.c | 1847 +++++++++++++++++++++++ alpha/native-math.h | 38 + alpha/ngen.c | 2725 ++++++++++++++++++++++++++++++++++ alpha/ngen.h | 328 ++++ alpha/sigcontext.h | 37 + alpha/threads.h | 72 + alpha/types.h | 58 + asmpart.h | 41 + builtin.c | 1621 ++++++++++++++++++++ builtin.h | 125 ++ callargs.h | 1 + comp/block.c | 405 +++++ comp/defines.c | 772 ++++++++++ comp/local.c | 104 ++ comp/mcode.c | 325 ++++ comp/parse.c | 1662 +++++++++++++++++++++ comp/pcmd.c | 706 +++++++++ comp/reg.c | 525 +++++++ comp/regalloc.c | 148 ++ comp/stack.c | 241 +++ comp/tools.c | 208 +++ comp/var.c | 361 +++++ compiler.c | 429 ++++++ compiler.h | 85 ++ doc/collect.doc | 212 +++ doc/gen.doc | 602 ++++++++ global.h | 542 +++++++ headers.c | 465 ++++++ loader.c | 1994 +++++++++++++++++++++++++ loader.h | 53 + main.c | 750 ++++++++++ nat/io.c | 473 ++++++ nat/lang.c | 918 ++++++++++++ nat/util.c | 121 ++ native.c | 340 +++++ native.h | 35 + ncomp/mcode.c | 331 +++++ ncomp/nblock.c | 87 ++ ncomp/ncomp.h | 93 ++ ncomp/ncompdef.h | 1103 ++++++++++++++ ncomp/nparse.c | 979 ++++++++++++ ncomp/nreg.c | 976 ++++++++++++ ncomp/nstack.c | 1498 +++++++++++++++++++ ncomp/ntools.c | 170 +++ newcomp.c | 437 ++++++ src/cacao/cacao.c | 750 ++++++++++ src/cacaoh/headers.c | 465 ++++++ src/mm/memory.c | 458 ++++++ src/mm/memory.h | 121 ++ src/native/native.c | 340 +++++ src/native/native.h | 35 + src/threads/green/locks.c | 576 +++++++ src/threads/green/locks.h | 141 ++ src/threads/green/threadio.c | 358 +++++ src/threads/green/threadio.h | 26 + src/threads/green/threads.c | 681 +++++++++ src/threads/green/threads.h | 151 ++ src/toolbox/chain.c | 243 +++ src/toolbox/chain.h | 92 ++ src/toolbox/list.c | 107 ++ src/toolbox/list.h | 97 ++ src/toolbox/tree.c | 166 +++ src/toolbox/tree.h | 45 + src/vm/builtin.c | 1621 ++++++++++++++++++++ src/vm/builtin.h | 125 ++ src/vm/global.h | 542 +++++++ src/vm/jit/asmpart.h | 41 + src/vm/loader.c | 1994 +++++++++++++++++++++++++ src/vm/loader.h | 53 + src/vm/tables.c | 1558 +++++++++++++++++++ src/vm/tables.h | 63 + tables.c | 1558 +++++++++++++++++++ tables.h | 63 + tests/JavaPerformance.java | 396 +++++ tests/a.java | 5 + tests/array.java | 7 + tests/b.java | 4 + tests/counter.java | 20 + tests/extest.java | 18 + tests/filter.java | 29 + tests/fintest.java | 30 + tests/fp.java | 33 + tests/fptest.java | 268 ++++ tests/ftest.java | 19 + tests/hello.java | 5 + tests/helper.java | 3 + tests/hi.java | 12 + tests/intsieve.java | 52 + tests/jctest.java | 1245 ++++++++++++++++ tests/leaf.java | 13 + tests/longtest.java | 8 + tests/main.java | 44 + tests/mem.java | 28 + tests/memtest.java | 25 + tests/n.java | 7 + tests/nan.java | 11 + tests/prop.java | 5 + tests/scribble.java | 29 + tests/sieve.java | 50 + tests/sum.java | 22 + tests/sum2.java | 26 + tests/suml.java | 25 + tests/sumlempty.java | 21 + tests/t.java | 43 + tests/tst.java | 13 + tests/x.java | 71 + threads/Makefile | 27 + threads/locks.c | 576 +++++++ threads/locks.h | 141 ++ threads/notyet.c | 110 ++ threads/thread.c | 681 +++++++++ threads/thread.h | 151 ++ threads/threadio.c | 358 +++++ threads/threadio.h | 26 + toolbox/Makefile | 28 + toolbox/chain.c | 243 +++ toolbox/chain.h | 92 ++ toolbox/list.c | 107 ++ toolbox/list.h | 97 ++ toolbox/loging.c | 136 ++ toolbox/loging.h | 53 + toolbox/memory.c | 458 ++++++ toolbox/memory.h | 121 ++ toolbox/tree.c | 166 +++ toolbox/tree.h | 45 + 133 files changed, 45921 insertions(+) create mode 100644 COPYRIGHT create mode 100644 Makefile create mode 100644 README create mode 100644 alpha/asmpart.c create mode 100644 alpha/calling.doc create mode 100644 alpha/cray.c create mode 100644 alpha/defines.h create mode 100644 alpha/disass.c create mode 100644 alpha/gen.c create mode 100644 alpha/native-math.h create mode 100644 alpha/ngen.c create mode 100644 alpha/ngen.h create mode 100644 alpha/sigcontext.h create mode 100644 alpha/threads.h create mode 100644 alpha/types.h create mode 100644 asmpart.h create mode 100644 builtin.c create mode 100644 builtin.h create mode 100644 callargs.h create mode 100644 comp/block.c create mode 100644 comp/defines.c create mode 100644 comp/local.c create mode 100644 comp/mcode.c create mode 100644 comp/parse.c create mode 100644 comp/pcmd.c create mode 100644 comp/reg.c create mode 100644 comp/regalloc.c create mode 100644 comp/stack.c create mode 100644 comp/tools.c create mode 100644 comp/var.c create mode 100644 compiler.c create mode 100644 compiler.h create mode 100644 doc/collect.doc create mode 100644 doc/gen.doc create mode 100644 global.h create mode 100644 headers.c create mode 100644 loader.c create mode 100644 loader.h create mode 100644 main.c create mode 100644 nat/io.c create mode 100644 nat/lang.c create mode 100644 nat/util.c create mode 100644 native.c create mode 100644 native.h create mode 100644 ncomp/mcode.c create mode 100644 ncomp/nblock.c create mode 100644 ncomp/ncomp.h create mode 100644 ncomp/ncompdef.h create mode 100644 ncomp/nparse.c create mode 100644 ncomp/nreg.c create mode 100644 ncomp/nstack.c create mode 100644 ncomp/ntools.c create mode 100644 newcomp.c create mode 100644 src/cacao/cacao.c create mode 100644 src/cacaoh/headers.c create mode 100644 src/mm/memory.c create mode 100644 src/mm/memory.h create mode 100644 src/native/native.c create mode 100644 src/native/native.h create mode 100644 src/threads/green/locks.c create mode 100644 src/threads/green/locks.h create mode 100644 src/threads/green/threadio.c create mode 100644 src/threads/green/threadio.h create mode 100644 src/threads/green/threads.c create mode 100644 src/threads/green/threads.h create mode 100644 src/toolbox/chain.c create mode 100644 src/toolbox/chain.h create mode 100644 src/toolbox/list.c create mode 100644 src/toolbox/list.h create mode 100644 src/toolbox/tree.c create mode 100644 src/toolbox/tree.h create mode 100644 src/vm/builtin.c create mode 100644 src/vm/builtin.h create mode 100644 src/vm/global.h create mode 100644 src/vm/jit/asmpart.h create mode 100644 src/vm/loader.c create mode 100644 src/vm/loader.h create mode 100644 src/vm/tables.c create mode 100644 src/vm/tables.h create mode 100644 tables.c create mode 100644 tables.h create mode 100644 tests/JavaPerformance.java create mode 100644 tests/a.java create mode 100644 tests/array.java create mode 100644 tests/b.java create mode 100644 tests/counter.java create mode 100644 tests/extest.java create mode 100644 tests/filter.java create mode 100644 tests/fintest.java create mode 100644 tests/fp.java create mode 100644 tests/fptest.java create mode 100644 tests/ftest.java create mode 100644 tests/hello.java create mode 100644 tests/helper.java create mode 100644 tests/hi.java create mode 100644 tests/intsieve.java create mode 100644 tests/jctest.java create mode 100644 tests/leaf.java create mode 100644 tests/longtest.java create mode 100644 tests/main.java create mode 100644 tests/mem.java create mode 100644 tests/memtest.java create mode 100644 tests/n.java create mode 100644 tests/nan.java create mode 100644 tests/prop.java create mode 100644 tests/scribble.java create mode 100644 tests/sieve.java create mode 100644 tests/sum.java create mode 100644 tests/sum2.java create mode 100644 tests/suml.java create mode 100644 tests/sumlempty.java create mode 100644 tests/t.java create mode 100644 tests/tst.java create mode 100644 tests/x.java create mode 100755 threads/Makefile create mode 100644 threads/locks.c create mode 100644 threads/locks.h create mode 100644 threads/notyet.c create mode 100644 threads/thread.c create mode 100644 threads/thread.h create mode 100644 threads/threadio.c create mode 100644 threads/threadio.h create mode 100755 toolbox/Makefile create mode 100644 toolbox/chain.c create mode 100644 toolbox/chain.h create mode 100644 toolbox/list.c create mode 100644 toolbox/list.h create mode 100644 toolbox/loging.c create mode 100644 toolbox/loging.h create mode 100644 toolbox/memory.c create mode 100644 toolbox/memory.h create mode 100644 toolbox/tree.c create mode 100644 toolbox/tree.h diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 000000000..faa46f3d6 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,30 @@ +CACAO is currently under development and unfinished. The current version +is not allowed to be distributed. Copies of CACAO source can be obtained +from the authors on request for educational and research purposes free +of charge. We will make available the sources under GNU licences in the +future when the sources are stable. Commercial licences can be obtained +via andi@complang.tuwien.ac.at. + + NO WARRANTY + + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..a1bcca496 --- /dev/null +++ b/Makefile @@ -0,0 +1,159 @@ +################################################################################ +# Makefile for the JavaVM - compiler CACAO # +################################################################################ +# +# Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst +# +# See file COPYRIGHT for information on usage and disclaimer of warranties +# +# Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at +# Andreas Krall EMAIL: cacao@complang.tuwien.ac.at +# +# Last Change: 1997/10/30 +# +# +# ATTENTION: This version of the makefile only works with gmake. +# This Makefile not only generates object files, but also additional +# files needed during compilation: +# nativetypes.hh +# nativetables.hh +# All object files and the *.hh can be deleted savely. They will be +# generated automatically. +# +################################################################################ + +##################### generation of the excutable ############################## + +# Enabling/disabling thread support +USE_THREADS = YES +#USE_THREADS = NO + +ifeq ($(USE_THREADS),YES) +THREAD_OBJ = threads/threads.a +THREAD_CFLAGS = -DUSE_THREADS -DEXTERNAL_OVERFLOW -DDONT_FREE_FIRST +else +THREAD_OBJ = +THREAD_CFLAGS = +endif + +CC = cc +#CFLAGS = -g -mieee -Wall $(THREAD_CFLAGS) +CFLAGS = -mieee -O3 -Wall $(THREAD_CFLAGS) + +#CC = cc +#CFLAGS = -g3 -ieee $(THREAD_CFLAGS) +#CFLAGS = -O3 -ieee $(THREAD_CFLAGS) + +OBJ = main.o tables.o loader.o compiler.o newcomp.o builtin.o asmpart.o \ + toolbox/toolbox.a native.o $(THREAD_OBJ) +OBJH = headers.o tables.o loader.o builtin.o toolbox/toolbox.a $(THREAD_OBJ) + +cacao: $(OBJ) + $(CC) $(CFLAGS) -o cacao $(OBJ) -lm +cacaoh: $(OBJH) + $(CC) $(CFLAGS) -o cacaoh $(OBJH) -lm + +main.o: main.c global.h tables.h compiler.h ncomp/ncomp.h loader.h \ + asmpart.h builtin.h native.h + +headers.o: headers.c global.h tables.h loader.h + +loader.o: loader.c global.h loader.h tables.h native.h asmpart.h + +compiler.o: builtin.h compiler.h global.h loader.h tables.h native.h \ + asmpart.h compiler.c comp/*.c sysdep/gen.c sysdep/disass.c + +newcomp.o: builtin.h ncomp/ncomp.h global.h loader.h tables.h native.h \ + asmpart.h ncomp/ncompdef.h ncomp/*.c sysdep/ngen.h sysdep/ngen.c sysdep/disass.c + +builtin.o: builtin.c global.h loader.h builtin.h tables.h sysdep/native-math.h + +native.o: native.c global.h tables.h native.h asmpart.h builtin.h \ + nativetypes.hh nativetable.hh nat/*.c + +tables.o: tables.c global.h tables.h + +global.h: sysdep/types.h toolbox/*.h + touch global.h + +toolbox/toolbox.a: toolbox/*.c toolbox/*.h + cd toolbox; make toolbox.a "CFLAGS=$(CFLAGS)" "CC=$(CC)" + +ifeq ($(USE_THREADS),YES) +threads/threads.a: threads/*.c threads/*.h sysdep/threads.h + cd threads; make threads.a "USE_THREADS=$(USE_THREADS)" "CFLAGS=$(CFLAGS)" "CC=$(CC)" +endif + +asmpart.o: sysdep/asmpart.c + rm -f asmpart.s + $(CC) -E sysdep/asmpart.c > asmpart.s + $(CC) -c -o asmpart.o asmpart.s + rm -f asmpart.s + + +########################### support targets #################################### + +clean: + rm -f *.o cacao cacaoh cacao.tgz nativetable.hh nativetypes.hh \ + core tst/core + cd toolbox; make clean + cd threads; make clean + +tar: + rm -f cacao.tgz cacao.tar + tar -cvf cacao.tar Makefile */Makefile README COPYRIGHT tst/*.java \ + doc/*.doc html/*.html *.[ch] comp/*.[ch] ncomp/*.[ch] alpha/*.doc alpha/*.[ch] \ + nat/*.[ch] toolbox/*.[ch] threads/*.[ch] # sparc/*.[ch] + ls -l cacao.tar + gzip -9 cacao.tar + mv cacao.tar.gz cacao.tgz + ls -l cacao.tgz + + +########################## supported architectures ############################# + +config-alpha: + rm -f sysdep + ln -s alpha sysdep + rm -f threads/sysdep + ln -s ../sysdep threads/sysdep + make clean + +config-sparc: + rm -f sysdep + ln -s sparc sysdep + rm -f threads/sysdep + ln -s ../sysdep threads/sysdep + make clean + + + +##################### generation of NATIVE - header files ###################### + +nativetypes.hh nativetable.hh : cacaoh + ./cacaoh java.lang.Object \ + java.lang.String \ + java.lang.Class \ + java.lang.ClassLoader \ + java.lang.Compiler \ + java.lang.Double \ + java.lang.Float \ + java.lang.Math \ + java.lang.Runtime \ + java.lang.SecurityManager \ + java.lang.System \ + java.lang.Thread \ + java.lang.ThreadGroup \ + java.lang.Throwable \ +\ + java.io.File \ + java.io.FileDescriptor \ + java.io.FileInputStream \ + java.io.FileOutputStream \ + java.io.PrintStream \ + java.io.RandomAccessFile \ +\ + java.util.Properties \ + java.util.Date + + \ No newline at end of file diff --git a/README b/README new file mode 100644 index 000000000..aa706ccbf --- /dev/null +++ b/README @@ -0,0 +1,31 @@ +************************* README for CACAO version 0.15 ************************ + +The current sources of CACAO version 0.15 are a snapshot during development. +They will change in the near future and are badly documented. This version +is not intended for public distribution. It is made available only for +educational and research purposes. + +To use the CACAO sources put the cacao015.tgz file in a newly created +directory and uncompress it using gzip and extract the files using tar. +Make sure you have installed gmake. Enter: + +make config-alpha +make + +After this you should have a working version of cacao and cacaoh. How to +invoke cacao and which class library has to be used is described at the +CACAO home page (http://www.complang.tuwien.ac.at/java/cacao/index.html). + +Under Linux this version currently works only using the option -cf. +If you want to use the Digital Unix C-compiler change the variable $CC +in the Makefile from gcc to cc. + +The Sparc port is unfinished and not working. So typing "make config-sparc" +makes no sense in the moment. Threads are currently also not supported. + +For questions mail me at cacao@complang.tuwien.ac.at, for very urgent +questions mail me at andi@complang.tuwien.ac.at. + +Have fun with CACAO + + Andreas Krall diff --git a/alpha/asmpart.c b/alpha/asmpart.c new file mode 100644 index 000000000..bd565a46f --- /dev/null +++ b/alpha/asmpart.c @@ -0,0 +1,1125 @@ +/****************************** asmpart.c ************************************** +* * +* is an assembly language file, but called .c to fake the preprocessor. * +* It contains the Java-C interface functions for Alpha processors. * +* * +* Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst * +* * +* See file COPYRIGHT for information on usage and disclaimer of warranties * +* * +* Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at * +* Andreas Krall EMAIL: cacao@complang.tuwien.ac.at * +* * +* Last Change: 1997/04/26 * +* * +*******************************************************************************/ + + +#define v0 $0 + +#define t0 $1 +#define t1 $2 +#define t2 $3 +#define t3 $4 +#define t4 $5 +#define t5 $6 +#define t6 $7 +#define t7 $8 + +#define s0 $9 +#define s1 $10 +#define s2 $11 +#define s3 $12 +#define s4 $13 +#define s5 $14 +#define s6 $15 + +#define a0 $16 +#define a1 $17 +#define a2 $18 +#define a3 $19 +#define a4 $20 +#define a5 $21 + +#define t8 $22 +#define t9 $23 +#define t10 $24 +#define t11 $25 +#define ra $26 +#define t12 $27 + +#define pv t12 +#define AT $at +#define gp $29 +#define sp $30 +#define zero $31 + +#define itmp1 $25 +#define itmp2 $28 +#define itmp3 $29 + +#define xptr itmp1 +#define xpc itmp2 + +#define sf0 $f2 +#define sf1 $f3 +#define sf2 $f4 +#define sf3 $f5 +#define sf4 $f6 +#define sf5 $f7 +#define sf6 $f8 +#define sf7 $f9 + +#define fzero $f31 + + +#define PAL_imb 134 + +#define offobjarr 24 +#define offarrsize 8 + + .text + .set noat + .set noreorder + + +/********************* exported functions and variables ***********************/ + + .globl has_no_x_instr_set + .globl synchronize_caches + .globl asm_calljavamethod + .globl asm_call_jit_compiler + .globl asm_dumpregistersandcall + .globl asm_handle_exception + .globl asm_handle_nat_exception + .globl asm_signal_exception + .globl new_builtin_checkcast + .globl new_builtin_checkarraycast + .globl new_builtin_aastore + .globl new_builtin_monitorenter + .globl new_builtin_monitorexit + .globl new_builtin_idiv + .globl new_builtin_irem + .globl new_builtin_ldiv + .globl new_builtin_lrem + .globl perform_alpha_threadswitch + .globl initialize_thread_stack + .globl used_stack_top + + +/*************************** imported variables *******************************/ + + .globl newcompiler + + +/*************************** imported functions *******************************/ + + .globl compiler_compile + .globl builtin_monitorexit + .globl builtin_throw_exception + .globl builtin_trace_exception + .globl class_java_lang_Object + +/*********************** function has_no_x_instr_set *************************** +* * +* determines if the byte support instruction set (21164a and higher) * +* is available. * +* * +*******************************************************************************/ + + .ent has_no_x_instr_set +has_no_x_instr_set: + + .long 0x47e03c20 # amask 1,$0 + jmp zero,(ra) # return + + .end has_no_x_instr_set + + +/********************* function synchronize_caches ****************************/ + + .ent synchronize_caches +synchronize_caches: + + call_pal PAL_imb # synchronise instruction cache + jmp zero,(ra) # return + + .end synchronize_caches + + +/********************* function asm_calljavamethod ***************************** +* * +* This function calls a Java-method (which possibly needs compilation) * +* with up to 4 parameters. * +* * +* This functions calls the JIT-compiler which eventually translates the * +* method into machine code. * +* * +* An possibly throwed exception will be returned to the caller as function * +* return value, so the java method cannot return a fucntion value (this * +* function usually calls 'main' and '' which do not return a * +* function value). * +* * +* C-prototype: * +* javaobject_header *asm_calljavamethod (methodinfo *m, * +* void *arg1, void *arg2, void *arg3, void *arg4); * +* * +*******************************************************************************/ + +#define MethodPointer -8 +#define FrameSize -12 +#define IsSync -16 +#define IsLeaf -20 +#define IntSave -24 +#define FltSave -28 +#define ExTableSize -32 +#define ExTableStart -32 + +#define ExEntrySize -32 +#define ExStartPC -8 +#define ExEndPC -16 +#define ExHandlerPC -24 +#define ExCatchType -32 + + .ent asm_calljavamethod + +call_name: + .ascii "calljavamethod\0\0" + + .align 3 + .quad 0 # catch type all + .quad calljava_xhandler # end pc + .quad calljava_xhandler # end pc + .quad asm_calljavamethod # start pc + .long 1 # extable size + .long 0 # fltsave + .long 0 # intsave + .long 0 # isleaf + .long 0 # IsSync + .long 32 # frame size + .quad 0 # method pointer (pointer to name) @@@@@ + +asm_calljavamethod: + + ldgp gp,0(pv) + lda sp,-32(sp) # allocate stack space + stq gp,24(sp) # save global pointer + stq ra,0(sp) # save return address + + stq $16,16(sp) # save method pointer for compiler + lda $0,16(sp) # pass pointer to method pointer via $0 + + bis $17,$17,$16 # pass the remaining parameters + bis $18,$18,$17 + bis $19,$19,$18 + bis $20,$20,$19 + + lda $28,asm_call_jit_compiler # fake virtual function call + stq $28,8(sp) # store function address + bis sp,sp,$28 # set method pointer + + ldq pv,8($28) # method call as in Java + jmp ra,(pv) # call JIT compiler +calljava_jit: + lda pv,-64(ra) # asm_calljavamethod-calljava_jit(ra) !!!!!! + +calljava_return: + + ldq ra,0(sp) # restore return address + ldq gp,24(sp) # restore global pointer + lda sp,32(sp) # free stack space + ldl $0,newcompiler # load newcompiler flag + subq $0,1,$0 # negate for clearing $0 + beq $0,calljava_ret # if newcompiler skip ex copying + bis $1,$1,$0 # pass exception to caller (C) +calljava_ret: + jmp zero,(ra) + +calljava_xhandler: + + ldq gp,24(sp) # restore global pointer + mov itmp1,a0 + jsr ra,builtin_throw_exception + ldq ra,0(sp) # restore return address + lda sp,32(sp) # free stack space + jmp zero,(ra) + .end asm_calljavamethod + + +/****************** function asm_call_jit_compiler ***************************** +* * +* invokes the compiler for untranslated JavaVM methods. * +* * +* Register R0 contains a pointer to the method info structure (prepared * +* by createcompilerstub). Using the return address in R26 and the * +* offset in the LDA instruction or using the value in methodptr R28 the * +* patching address for storing the method address can be computed: * +* * +* method address was either loaded using * +* M_LDQ (REG_PV, REG_PV, a) # invokestatic/special ($27) * +* M_LDA (REG_PV, REG_RA, low) * +* M_LDAH(REG_PV, REG_RA, high) # optional * +* or * +* M_LDQ (REG_PV, REG_METHODPTR, m) # invokevirtual/interface ($28) * +* in the static case the method pointer can be computed using the * +* return address and the lda function following the jmp instruction * +* * +*******************************************************************************/ + + + .ent asm_call_jit_compiler +asm_call_jit_compiler: + + ldgp gp,0(pv) + ldl $22,-8(ra) # load instruction LDQ PV,xxx($yy) + srl $22,16,$22 # shift right register number $yy + and $22,31,$22 # isolate register number + subl $22,28,$22 # test for REG_METHODPTR + beq $22,noregchange + ldl $22,0(ra) # load instruction LDA PV,xxx(RA) + sll $22,48,$22 + sra $22,48,$22 # isolate offset + addq $22,ra,$28 # compute update address + ldl $22,4(ra) # load instruction LDAH PV,xxx(PV) + srl $22,16,$22 # isolate instruction code + lda $22,-0x177b($22) # test for LDAH + bne $22,noregchange + ldl $22,0(ra) # load instruction LDA PV,xxx(RA) + sll $22,16,$22 # compute high offset + addl $22,0,$22 # sign extend high offset + addq $22,$28,$28 # compute update address +noregchange: + lda sp,-14*8(sp) # reserve stack space + stq $16,0*8(sp) # save all argument registers + stq $17,1*8(sp) # they could be used by method + stq $18,2*8(sp) + stq $19,3*8(sp) + stq $20,4*8(sp) + stq $21,5*8(sp) + stt $f16,6*8(sp) + stt $f17,7*8(sp) + stt $f18,8*8(sp) + stt $f19,9*8(sp) + stt $f20,10*8(sp) + stt $f21,11*8(sp) + stq $28,12*8(sp) # save method pointer + stq ra,13*8(sp) # save return address + + ldq $16,0($0) # pass 'methodinfo' pointer to + jsr ra,compiler_compile # compiler + ldgp gp,0(ra) + + call_pal PAL_imb # synchronise instruction cache + + ldq $16,0*8(sp) # load argument registers + ldq $17,1*8(sp) + ldq $18,2*8(sp) + ldq $19,3*8(sp) + ldq $20,4*8(sp) + ldq $21,5*8(sp) + ldt $f16,6*8(sp) + ldt $f17,7*8(sp) + ldt $f18,8*8(sp) + ldt $f19,9*8(sp) + ldt $f20,10*8(sp) + ldt $f21,11*8(sp) + ldq $28,12*8(sp) # load method pointer + ldq ra,13*8(sp) # load return address + lda sp,14*8(sp) # deallocate stack area + + ldl $22,-8(ra) # load instruction LDQ PV,xxx($yy) + sll $22,48,$22 + sra $22,48,$22 # isolate offset + + addq $22,$28,$22 # compute update address via method pointer + stq $0,0($22) # save new method address there + + bis $0,$0,pv # load method address into pv + + jmp zero, (pv) # and call method. The method returns + # directly to the caller (ra). + + .end asm_call_jit_compiler + + +/****************** function asm_dumpregistersandcall ************************** +* * +* This funtion saves all callee saved registers and calls the function * +* which is passed as parameter. * +* * +* This function is needed by the garbage collector, which needs to access * +* all registers which are stored on the stack. Unused registers are * +* cleared to avoid interferances with the GC. * +* * +* void asm_dumpregistersandcall (functionptr f); * +* * +*******************************************************************************/ + + .ent asm_dumpregistersandcall +asm_dumpregistersandcall: + lda sp,-16*8(sp) # allocate stack + stq ra,0(sp) # save return address + + stq $9,1*8(sp) # save all callee saved registers + stq $10,2*8(sp) # intialize the remaining registers + stq $11,3*8(sp) + stq $12,4*8(sp) + stq $13,5*8(sp) + stq $14,6*8(sp) + stq $15,7*8(sp) + stt $f2,8*8(sp) + stt $f3,9*8(sp) + stt $f4,10*8(sp) + stt $f5,11*8(sp) + stt $f6,12*8(sp) + stt $f7,13*8(sp) + stt $f8,14*8(sp) + stt $f9,15*8(sp) + + bis zero,zero,$0 # intialize the remaining registers + bis zero,zero,$1 + bis zero,zero,$2 + bis zero,zero,$3 + bis zero,zero,$4 + bis zero,zero,$5 + bis zero,zero,$6 + bis zero,zero,$7 + bis zero,zero,$8 + bis zero,zero,$17 + bis zero,zero,$18 + bis zero,zero,$19 + bis zero,zero,$20 + bis zero,zero,$21 + bis zero,zero,$22 + bis zero,zero,$23 + bis zero,zero,$24 + bis zero,zero,$25 + bis zero,zero,$26 + bis zero,zero,$27 + bis zero,zero,$28 + bis zero,zero,$29 + cpys $f31,$f31,$f0 + cpys $f31,$f31,$f1 + cpys $f31,$f31,$f10 + cpys $f31,$f31,$f11 + cpys $f31,$f31,$f12 + cpys $f31,$f31,$f13 + cpys $f31,$f31,$f14 + cpys $f31,$f31,$f15 + cpys $f31,$f31,$f16 + cpys $f31,$f31,$f17 + cpys $f31,$f31,$f18 + cpys $f31,$f31,$f19 + cpys $f31,$f31,$f20 + cpys $f31,$f31,$f21 + cpys $f31,$f31,$f22 + cpys $f31,$f31,$f23 + cpys $f31,$f31,$f24 + cpys $f31,$f31,$f25 + cpys $f31,$f31,$f26 + cpys $f31,$f31,$f27 + cpys $f31,$f31,$f28 + cpys $f31,$f31,$f29 + cpys $f31,$f31,$f30 + + bis $16,$16,pv # load function pointer + jmp ra,(pv) # and call function + + ldq ra,0(sp) # load return address + lda sp,16*8(sp) # deallocate stack + jmp zero,(ra) # return + + .end asm_dumpregistersandcall + + +/********************* function asm_handle_exception *************************** +* * +* This function handles an exception. It does not use the usual calling * +* conventions. The exception pointer is passed in REG_ITMP1 and the * +* pc from the exception raising position is passed in REG_ITMP2. It searches * +* the local exception table for a handler. If no one is found, it unwinds * +* stacks and continues searching the callers. * +* * +* void asm_handle_exception (exceptionptr, exceptionpc); * +* * +*******************************************************************************/ + + .ent asm_handle_nat_exception +asm_handle_nat_exception: + + ldl t0,0(ra) # load instruction LDA PV,xxx(RA) + sll t0,48,t0 + sra t0,48,t0 # isolate offset + addq t0,ra,pv # compute update address + ldl t0,4(ra) # load instruction LDAH PV,xxx(PV) + srl t0,16,t0 # isolate instruction code + lda t0,-0x177b(t0) # test for LDAH + bne t0,asm_handle_exception + ldl t0,0(ra) # load instruction LDA PV,xxx(RA) + sll t0,16,t0 # compute high offset + addl t0,0,t0 # sign extend high offset + addq t0,pv,pv # compute update address + + .aent asm_handle_exception +asm_handle_exception: + + lda sp,-18*8(sp) # allocate stack + stq t0,0*8(sp) # save possible used registers + stq t1,1*8(sp) # also registers used by builtin_checkcast + stq t2,2*8(sp) + stq t3,3*8(sp) + stq t4,4*8(sp) + stq t5,5*8(sp) + stq t6,6*8(sp) + stq t7,7*8(sp) + stq t8,8*8(sp) + stq t9,9*8(sp) + stq t10,10*8(sp) + stq v0,11*8(sp) + stq a0,12*8(sp) + stq a1,13*8(sp) + stq a2,14*8(sp) + stq a3,15*8(sp) + stq a4,16*8(sp) + stq a5,17*8(sp) + + lda t3,1(zero) # set no unwind flag +ex_stack_loop: + lda sp,-5*8(sp) # allocate stack + stq xptr,0*8(sp) # save used register + stq xpc,1*8(sp) + stq pv,2*8(sp) + stq ra,3*8(sp) + stq t3,4*8(sp) + + mov xptr,a0 + ldq a1,MethodPointer(pv) + mov xpc,a2 + mov t3,a3 + br ra,ex_trace # set ra for gp loading +ex_trace: + ldgp gp,0(ra) # load gp + jsr ra,builtin_trace_exception # builtin_trace_exception(xptr,methodptr) + + ldq xptr,0*8(sp) # restore used register + ldq xpc,1*8(sp) + ldq pv,2*8(sp) + ldq ra,3*8(sp) + ldq t3,4*8(sp) + lda sp,5*8(sp) # deallocate stack + + ldl t0,ExTableSize(pv) # t0 = exception table size + beq t0,empty_table # if empty table skip + lda t1,ExTableStart(pv) # t1 = start of exception table + +ex_table_loop: + ldq t2,ExStartPC(t1) # t2 = exception start pc + cmple t2,xpc,t2 # t2 = (startpc <= xpc) + beq t2,ex_table_cont # if (false) continue + ldq t2,ExEndPC(t1) # t2 = exception end pc + cmplt xpc,t2,t2 # t2 = (xpc < endpc) + beq t2,ex_table_cont # if (false) continue + ldq a1,ExCatchType(t1) # arg1 = exception catch type + beq a1,ex_handle_it # NULL catches everything + mov xptr,a0 # arg0 = exception pointer + + lda sp,-7*8(sp) # allocate stack + stq t0,0*8(sp) # save used register + stq t1,1*8(sp) + stq t3,2*8(sp) + stq xptr,3*8(sp) + stq xpc,4*8(sp) + stq pv,5*8(sp) + stq ra,6*8(sp) + + br ra,ex_gpload # set ra for gp loading +ex_gpload: + ldgp gp,0(ra) # load gp + jsr ra,builtin_checkcast # builtin_checkcast(xptr,catchtype) + + ldq t0,0*8(sp) # restore used register + ldq t1,1*8(sp) + ldq t3,2*8(sp) + ldq xptr,3*8(sp) + ldq xpc,4*8(sp) + ldq pv,5*8(sp) + ldq ra,6*8(sp) + lda sp,7*8(sp) # deallocate stack + + beq v0,ex_table_cont # if (false) continue + +ex_handle_it: + + ldq xpc,ExHandlerPC(t1) # xpc = exception handler pc + + beq t3,ex_jump # if (!(no stack unwinding) skip + + ldq t0,0*8(sp) # restore possible used registers + ldq t1,1*8(sp) # also registers used by builtin_checkcast + ldq t2,2*8(sp) + ldq t3,3*8(sp) + ldq t4,4*8(sp) + ldq t5,5*8(sp) + ldq t6,6*8(sp) + ldq t7,7*8(sp) + ldq t8,8*8(sp) + ldq t9,9*8(sp) + ldq t10,10*8(sp) + ldq v0,11*8(sp) + ldq a0,12*8(sp) + ldq a1,13*8(sp) + ldq a2,14*8(sp) + ldq a3,15*8(sp) + ldq a4,16*8(sp) + ldq a5,17*8(sp) + lda sp,18*8(sp) # deallocate stack + +ex_jump: + jmp zero,(xpc) # jump to the handler + +ex_table_cont: + lda t1,ExEntrySize(t1) # next exception table entry + subl t0,1,t0 # decrement entry counter + bgt t0,ex_table_loop # if (t0 > 0) next entry + +empty_table: + beq t3,ex_already_cleared # if here the first time, then + lda sp,18*8(sp) # deallocate stack and + clr t3 # clear the no unwind flag +ex_already_cleared: + ldl t0,IsSync(pv) # t0 = SyncOffset + beq t0,no_monitor_exit # if zero no monitorexit + addq sp,t0,t0 # add Offset to stackptr + ldq a0,-8(t0) # load monitorexit pointer + + lda sp,-7*8(sp) # allocate stack + stq t0,0*8(sp) # save used register + stq t1,1*8(sp) + stq t3,2*8(sp) + stq xptr,3*8(sp) + stq xpc,4*8(sp) + stq pv,5*8(sp) + stq ra,6*8(sp) + + br ra,ex_mon_load # set ra for gp loading +ex_mon_load: + ldgp gp,0(ra) # load gp + jsr ra,builtin_monitorexit # builtin_monitorexit(objectptr) + + ldq t0,0*8(sp) # restore used register + ldq t1,1*8(sp) + ldq t3,2*8(sp) + ldq xptr,3*8(sp) + ldq xpc,4*8(sp) + ldq pv,5*8(sp) + ldq ra,6*8(sp) + lda sp,7*8(sp) # deallocate stack + +no_monitor_exit: + ldl t0,FrameSize(pv) # t0 = frame size + addq sp,t0,sp # unwind stack + mov sp,t0 # t0 = pointer to save area + ldl t1,IsLeaf(pv) # t1 = is leaf procedure + bne t1,ex_no_restore # if (leaf) skip + ldq ra,-8(t0) # restore ra + lda t0,-8(t0) # t0-- +ex_no_restore: + mov ra,xpc # the new xpc is ra + ldl t1,IntSave(pv) # t1 = saved int register count + br t2,ex_int1 # t2 = current pc +ex_int1: + lda t2,44(t2) # lda t2,ex_int2-ex_int1(t2) !!!!!!!!!!!!!!! + negl t1,t1 # negate register count + s4addq t1,t2,t2 # t2 = ex_int_sav - 4 * register count + jmp zero,(t2) # jump to save position + ldq s0,-56(t0) + ldq s1,-48(t0) + ldq s2,-40(t0) + ldq s3,-32(t0) + ldq s4,-24(t0) + ldq s5,-16(t0) + ldq s6,-8(t0) +ex_int2: + s8addq t1,t0,t0 # t0 = t0 - 8 * register count + + ldl t1,FltSave(pv) # t1 = saved flt register count + br t2,ex_flt1 # t2 = current pc +ex_flt1: + lda t2,48(t2) # lda t2,ex_flt2-ex_flt1(t2) !!!!!!!!!!!!!!! + negl t1,t1 # negate register count + s4addq t1,t2,t2 # t2 = ex_flt_sav - 4 * register count + jmp zero,(t2) # jump to save position + ldt $f2,-64(t0) + ldt $f3,-56(t0) + ldt $f4,-48(t0) + ldt $f5,-40(t0) + ldt $f6,-32(t0) + ldt $f7,-24(t0) + ldt $f8,-16(t0) + ldt $f9,-8(t0) +ex_flt2: + ldl t0,0(ra) # load instruction LDA PV,xxx(RA) + sll t0,48,t0 + sra t0,48,t0 # isolate offset + addq t0,ra,pv # compute update address + ldl t0,4(ra) # load instruction LDAH PV,xxx(PV) + srl t0,16,t0 # isolate instruction code + lda t0,-0x177b(t0) # test for LDAH + bne t0,ex_stack_loop + ldl t0,0(ra) # load instruction LDA PV,xxx(RA) + sll t0,16,t0 # compute high offset + addl t0,0,t0 # sign extend high offset + addq t0,pv,pv # compute update address + br ex_stack_loop + + .end asm_handle_exception + + +/********************* function asm_signal_exception *************************** +* * +* This function handles an exception which was catched by a signal. * +* * +* void asm_signal_exception (exceptionptr, signalcontext); * +* * +*******************************************************************************/ + +#define sigctxstack 0*8 /* sigstack state to restore */ +#define sigctxmask 1*8 /* signal mask to restore */ +#define sigctxpc 2*8 /* pc at time of signal */ +#define sigctxpsl 3*8 /* psl to retore */ +#define sigctxr00 4*8 /* processor regs 0 to 31 */ +#define sigctxr01 5*8 +#define sigctxr02 6*8 +#define sigctxr03 7*8 +#define sigctxr04 8*8 +#define sigctxr05 9*8 +#define sigctxr06 10*8 +#define sigctxr07 11*8 +#define sigctxr08 12*8 +#define sigctxr09 13*8 +#define sigctxr10 14*8 +#define sigctxr11 15*8 +#define sigctxr12 16*8 +#define sigctxr13 17*8 +#define sigctxr14 18*8 +#define sigctxr15 19*8 +#define sigctxr16 20*8 +#define sigctxr17 21*8 +#define sigctxr18 22*8 +#define sigctxr19 23*8 +#define sigctxr20 24*8 +#define sigctxr21 25*8 +#define sigctxr22 26*8 +#define sigctxr23 27*8 +#define sigctxr24 28*8 +#define sigctxr25 29*8 +#define sigctxr26 30*8 +#define sigctxr27 31*8 +#define sigctxr28 32*8 +#define sigctxr29 33*8 +#define sigctxr30 34*8 +#define sigctxr31 35*8 + +#define sigctxfpuse 36*8 /* fp has been used */ +#define sigctxf00 37*8 /* fp regs 0 to 31 */ +#define sigctxf01 38*8 +#define sigctxf02 39*8 +#define sigctxf03 40*8 +#define sigctxf04 41*8 +#define sigctxf05 42*8 +#define sigctxf06 43*8 +#define sigctxf07 44*8 +#define sigctxf08 45*8 +#define sigctxf09 46*8 +#define sigctxf10 47*8 +#define sigctxf11 48*8 +#define sigctxf12 49*8 +#define sigctxf13 50*8 +#define sigctxf14 51*8 +#define sigctxf15 52*8 +#define sigctxf16 53*8 +#define sigctxf17 54*8 +#define sigctxf18 55*8 +#define sigctxf19 56*8 +#define sigctxf20 57*8 +#define sigctxf21 58*8 +#define sigctxf22 59*8 +#define sigctxf23 60*8 +#define sigctxf24 61*8 +#define sigctxf25 62*8 +#define sigctxf26 63*8 +#define sigctxf27 64*8 +#define sigctxf28 65*8 +#define sigctxf29 66*8 +#define sigctxf30 67*8 +#define sigctxf31 68*8 + +#define sigctxhfpcr 69*8 /* floating point control register */ +#define sigctxsfpcr 70*8 /* software fpcr */ + + .ent asm_signal_exception +asm_signal_exception: + + mov a0,xptr + mov a1,sp + ldq xpc,sigctxpc(sp) + ldq v0,sigctxr00(sp) # restore possible used registers + ldq t0,sigctxr01(sp) + ldq t1,sigctxr02(sp) + ldq t2,sigctxr03(sp) + ldq t3,sigctxr04(sp) + ldq t4,sigctxr05(sp) + ldq t5,sigctxr06(sp) + ldq t6,sigctxr07(sp) + ldq t7,sigctxr08(sp) + ldq s0,sigctxr09(sp) + ldq s1,sigctxr10(sp) + ldq s2,sigctxr11(sp) + ldq s3,sigctxr12(sp) + ldq s4,sigctxr13(sp) + ldq s5,sigctxr14(sp) + ldq s6,sigctxr15(sp) + ldq a0,sigctxr16(sp) + ldq a1,sigctxr17(sp) + ldq a2,sigctxr18(sp) + ldq a3,sigctxr19(sp) + ldq a4,sigctxr20(sp) + ldq a5,sigctxr21(sp) + ldq t8,sigctxr22(sp) + ldq t9,sigctxr23(sp) + ldq t10,sigctxr24(sp) + ldq ra,sigctxr26(sp) + ldq pv,sigctxr27(sp) + ldq sp,sigctxr30(sp) + br asm_handle_nat_exception + .end asm_signal_exception + + +/********************* function new_builtin_monitorenter *********************** +* * +* Does null check and calls monitorenter or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_monitorenter +new_builtin_monitorenter: + + ldgp gp,0(pv) + lda pv,builtin_monitorenter + beq a0,nb_monitorenter # if (null) throw exception + jmp zero,(pv) # else call builtin_monitorenter + +nb_monitorenter: + ldq xptr,proto_java_lang_NullPointerException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_monitorenter + + +/********************* function new_builtin_monitorexit ************************ +* * +* Does null check and calls monitorexit or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_monitorexit +new_builtin_monitorexit: + + ldgp gp,0(pv) + lda pv,builtin_monitorexit + beq a0,nb_monitorexit # if (null) throw exception + jmp zero,(pv) # else call builtin_monitorexit + +nb_monitorexit: + ldq xptr,proto_java_lang_NullPointerException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_monitorenter + + +/************************ function new_builtin_idiv **************************** +* * +* Does null check and calls idiv or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_idiv +new_builtin_idiv: + + ldgp gp,0(pv) + lda pv,builtin_idiv + beq a1,nb_idiv # if (null) throw exception + jmp zero,(pv) # else call builtin_idiv + +nb_idiv: + ldq xptr,proto_java_lang_ArithmeticException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_idiv + + +/************************ function new_builtin_ldiv **************************** +* * +* Does null check and calls ldiv or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_ldiv +new_builtin_ldiv: + + ldgp gp,0(pv) + lda pv,builtin_ldiv + beq a1,nb_ldiv # if (null) throw exception + jmp zero,(pv) # else call builtin_ldiv + +nb_ldiv: + ldq xptr,proto_java_lang_ArithmeticException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_ldiv + + +/************************ function new_builtin_irem **************************** +* * +* Does null check and calls irem or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_irem +new_builtin_irem: + + ldgp gp,0(pv) + lda pv,builtin_irem + beq a1,nb_irem # if (null) throw exception + jmp zero,(pv) # else call builtin_irem + +nb_irem: + ldq xptr,proto_java_lang_ArithmeticException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_irem + + +/************************ function new_builtin_lrem **************************** +* * +* Does null check and calls lrem or throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_lrem +new_builtin_lrem: + + ldgp gp,0(pv) + lda pv,builtin_lrem + beq a1,nb_lrem # if (null) throw exception + jmp zero,(pv) # else call builtin_lrem + +nb_lrem: + ldq xptr,proto_java_lang_ArithmeticException + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_lrem + + +/*********************** function new_builtin_checkcast ************************ +* * +* Does the cast check and eventually throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_checkcast +new_builtin_checkcast: + + ldgp gp,0(pv) + lda sp,-16(sp) # allocate stack space + stq ra,0(sp) # save return address + stq a0,8(sp) # save object pointer + jsr ra,builtin_checkcast # builtin_checkcast + ldgp gp,0(ra) + beq v0,nb_ccast_throw # if (false) throw exception + ldq ra,0(sp) # restore return address + ldq v0,8(sp) # return object pointer + lda sp,16(sp) # free stack space + jmp zero,(ra) + +nb_ccast_throw: + ldq xptr,proto_java_lang_ClassCastException + ldq ra,0(sp) # restore return address + lda sp,16(sp) # free stack space + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_checkcast + + +/******************* function new_builtin_checkarraycast *********************** +* * +* Does the cast check and eventually throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_checkarraycast +new_builtin_checkarraycast: + + ldgp gp,0(pv) + lda sp,-16(sp) # allocate stack space + stq ra,0(sp) # save return address + stq a0,8(sp) # save object pointer + jsr ra,builtin_checkarraycast # builtin_checkarraycast + ldgp gp,0(ra) + beq v0,nb_carray_throw # if (false) throw exception + ldq ra,0(sp) # restore return address + ldq v0,8(sp) # return object pointer + lda sp,16(sp) # free stack space + jmp zero,(ra) + +nb_carray_throw: + ldq xptr,proto_java_lang_ClassCastException + ldq ra,0(sp) # restore return address + lda sp,16(sp) # free stack space + lda xpc,-4(ra) # faulting address is return adress - 4 + br asm_handle_nat_exception + .end new_builtin_checkarraycast + + +/******************* function new_builtin_aastore ****************************** +* * +* Does the cast check and eventually throws an exception * +* * +*******************************************************************************/ + + .ent new_builtin_aastore +new_builtin_aastore: + + ldgp gp,0(pv) + beq a0,nb_aastore_null # if null pointer throw exception + ldl t0,offarrsize(a0) # load size + lda sp,-24(sp) # allocate stack space + stq ra,0(sp) # save return address + s8addq a1,a0,t1 # add index*8 to arrayref + cmpult a1,t0,t0 # do bound check + beq t0,nb_aastore_bound # if out of bounds throw exception + mov a2,a1 # object is second argument + stq t1,8(sp) # save store position + stq a1,16(sp) # save object + jsr ra,builtin_canstore # builtin_canstore(arrayref,object) + ldgp gp,0(ra) + ldq ra,0(sp) # restore return address + ldq a0,8(sp) # restore store position + ldq a1,16(sp) # restore object + lda sp,24(sp) # free stack space + beq v0,nb_aastore_throw # if (false) throw exception + stq a1,offobjarr(a0) # store objectptr in array + jmp zero,(ra) + +nb_aastore_null: + ldq xptr,proto_java_lang_NullPointerException + mov ra,xpc # faulting address is return adress + br asm_handle_nat_exception + +nb_aastore_bound: + ldq xptr,proto_java_lang_ArrayIndexOutOfBoundsException + lda sp,24(sp) # free stack space + mov ra,xpc # faulting address is return adress + br asm_handle_nat_exception + +nb_aastore_throw: + ldq xptr,proto_java_lang_ArrayStoreException + mov ra,xpc # faulting address is return adress + br asm_handle_nat_exception + + .end new_builtin_aastore + + +/********************** function initialize_thread_stack *********************** +* * +* initialized a thread stack * +* * +*******************************************************************************/ + + .ent initialize_thread_stack +initialize_thread_stack: + + lda a1,-128(a1) + stq zero, 0(a1) + stq zero, 8(a1) + stq zero, 16(a1) + stq zero, 24(a1) + stq zero, 32(a1) + stq zero, 40(a1) + stq zero, 48(a1) + stt fzero, 56(a1) + stt fzero, 64(a1) + stt fzero, 72(a1) + stt fzero, 80(a1) + stt fzero, 88(a1) + stt fzero, 96(a1) + stt fzero, 104(a1) + stt fzero, 112(a1) + stq a0, 120(a1) + mov a1, v0 + jmp zero,(ra) + .end initialize_thread_stack + + +/******************* function perform_alpha_threadswitch *********************** +* * +* performs a threadswitch * +* * +*******************************************************************************/ + + .ent perform_alpha_threadswitch +perform_alpha_threadswitch: + + subq sp,128,sp + stq s0, 0(sp) + stq s1, 8(sp) + stq s2, 16(sp) + stq s3, 24(sp) + stq s4, 32(sp) + stq s5, 40(sp) + stq s6, 48(sp) + stt sf0, 56(sp) + stt sf1, 64(sp) + stt sf2, 72(sp) + stt sf3, 80(sp) + stt sf4, 88(sp) + stt sf5, 96(sp) + stt sf6, 104(sp) + stt sf7, 112(sp) + stq ra, 120(sp) + stq sp, 0(a0) + ldq sp, 0(a1) + ldq s0, 0(sp) + ldq s1, 8(sp) + ldq s2, 16(sp) + ldq s3, 24(sp) + ldq s4, 32(sp) + ldq s5, 40(sp) + ldq s6, 48(sp) + ldt sf0, 56(sp) + ldt sf1, 64(sp) + ldt sf2, 72(sp) + ldt sf3, 80(sp) + ldt sf4, 88(sp) + ldt sf5, 96(sp) + ldt sf6, 104(sp) + ldt sf7, 112(sp) + ldq ra, 120(sp) + mov ra, t12 + addq sp, 128, sp + jmp zero,(ra) + .end perform_alpha_threadswitch + + +/*********************** function used_stack_top ******************************* +* * +* returns $sp * +* * +*******************************************************************************/ + + .ent used_stack_top +used_stack_top: + + mov sp, v0 + jmp zero,(ra) + .end used_stack_top diff --git a/alpha/calling.doc b/alpha/calling.doc new file mode 100644 index 000000000..ab27b901d --- /dev/null +++ b/alpha/calling.doc @@ -0,0 +1,182 @@ +/***************************** calling.doc ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Das ist eine kurze Dokumentation "uber die internen Aufrufskonventionen + der Java-Methoden in der DEC-ALHPA-Version. + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/02/05 + +*******************************************************************************/ +FILE: calling.doc + +Das ist eine kurze Dokumentation "uber die internen Aufrufskonventionen +der Java-Methoden in der DEC-ALHPA-Version. + +------------------------------------------------------------------------------- + + +Die Aufrufskonventionen halten sich weitgehende an die Konventionen +f"ur normale C-Funktionen, allerdings mit einigen zus"atzlichen +Registerbelegungen: + +R28 ..... enth"alt bei einem Methodenaufruf auf jeden Fall den Zeiger + auf die zugeh"orige 'methodinfo'-Struktur, die gegebenenfalls an + den JIT-Compiler weitergegeben werden muss. + + Wenn von Java-Methoden aus direkt C-Funktionen aufgerufen werden, + (f"ur die nat"urlich auch keine 'methodinfo'-Struktur existiert), + dann hat dieses Register keinen definierten Wert (Alle von der + JavaVM verwendeten Funktionen, z. B. 'builtin_new', etc. werden + so aufgerufen) + +R1 ...... enth"alt nach Methodenbeendigung entweder NULL oder einen Zeiger + auf ein Objekt vom Typ java.lang.Throwable (oder einem davon + abgeleiteten Typ). + Wenn das der Fall ist, dann wurde in der Methode eine Exception + geworfen, die nicht abgefangen werden konnte, und jetzt beim + Aufrufer weiter bearbeitet werden muss. + + + +Die restlichen Register folgen den normalen Konventionen, aber ich gebe +hier noch einmal eine kurze "Ubersicht: + + +INTEGER-REGISTER: + +R0 ........ R"uckgabewert von den Methoden f"ur die Typen: + INT,LONG,ADDRESS + +R1 ........ Adresse der geworfenen Exception (oder NULL) + +R2-R8 ..... tempor"are Register (werden im Unterprogram zerst"ort) + +R9-R15 .... gesicherte Register (werden im Unterprogramm nicht ver"andert) + +R16-R21 ... Argumentregister 1 - 6 (hier werden die ersten sechs Methoden- + Argumente eingetragen, sofern sie von den Typen INT,LONG,ADDRESS + sind. Diese Argumentregister werden im Unterprogramm zerst"ort + +R22-R24 ... tempor"are Register + (werden im Unterprogramm zerst"ort) + +R25 ....... tempor"ares Register f"ur kurzfristige Zwischenergebnisse + (wird im Unterprogramm zerst"ort) + +R26 (ra) .. R"ucksprungadresse (bleibt im Unterprogramm erhalten) + +R27 (pv) .. Prozedurzeiger. Dieses Register muss auf jeden Fall einen Zeiger + auf die aufgerufene Prozedur enthalten (damit die Zugriffe + auf das Datensegment funktionieren k"onnen). + (der Wert bleibt im Unterprogramm erhalten) + +R28 ....... Zeiger auf die 'methodinfo' - Struktur. Muss auf jeden Fall bei + allen Methodenaufrufen richtig gesetzt sein (wegen eines eventuellen + Compiler-Aufrufs) + (wird im Unterprogramm zerst"ort) + +R29 ....... tempor"ares Register f"ur kurzfristige Zwischenergebnisse + (wird im Unterprogramm zerst"ort) + +R30 (sp) .. Zeiger auf die Untergrenze des Stack (der Stack w"achst von + oben nach unten) + +R31 ....... enth"alt immer NULL + + + +FLIESSKOMMA-REGISTER: + + +F0 ........ enth"alt die R"uckgabewert der Methoden vom Typ: + FLOAT, DOUBLE +F1 ........ enth"alt den Imagin"aranteil von einem komplexen Funktionswert + (wird von mir nicht benutzt) + +F2-F9 ..... gesicherte Register (werden im Unterprogramm nicht ver"andert) + +F10-F15 ... tempor"are Register (werden im Unterprogramm zerst"ort) + +F16-F21 ... Argumentregister f"ur die ersten 6 Parameter, sofern diese + vom den Typen FLOAT oder DOUBLE sind + +F22-F24 ... tempor"are Register (werden im Unterprogramm zerst"ort) + +F25-F31 ... tempor"are Register f"ur kurzfristige Zwischenergebnisse + (werden im Unterprogramm zerst"ort) + +F31 ....... enth"alt immer 0.0 + + + +PARAMETER"UBERGABE AM STACK: + +Bei mehr als sechs Parametern reicht der Platz in den Registern nicht mehr +aus, daf"ur werden alle Parameter ab dem Siebenten am Stack "ubergeben, +und zwar nach folgendem Muster: + + + | ..... | + -------------------------------------------------- + | Parameter 9 ( 64 bit, egal bei welchem Typ) | + -------------------------------------------------- + | Parameter 8 ( 64 bit, egal bei welchem Typ | + -------------------------------------------------- + R30 (sp) ---> | Parameter 7 ( 64 bit, egal bei welchem Typ) | + -------------------------------------------------- + +Der Stackpointer zeigt dabei auf die Untergrenze des Parameterbereichs. + + + + + +VOLLST"ANDIGES LAYOUT EINES STACKFRAMES: + +Jede Methode muss (wenn es keine Leaf-Methode ist, auf jeden Fall) gewisse +Registerinhalte am Stack sichern. +Eventuell werden auch noch lokale Werte, die nicht mehr in Registern +Platz finden, ebenfalls am Stack aufbewahrt, und die Parameter"ubergabe +bei mehr als 6 Parametern ben"otigt ebenfalls Platz am Stack. + +Ein vollst"andiger Stackframe hat also dieses Aussehen (jeder Eintrag +im Stackframe ist unabh"angig vom Typ auf jedem Fall 64 bit lang, die +Gr"ossenangaben der Bereiche sind in solchen Einheiten von 64 Bit +angegeben): + + --------------------------------------------- + | Parameter n (vom Aufrufer) | + --------------------------------------------- + | Parameter n-1 | + --------------------------------------------- + | ... | + --------------------------------------------- + SP vorher -> | Parameter 7 | + ============================================= --- + | gesichertes RA | savedregs_num + --------------------------------------------- + | andere gesicherte Register | + ============================================= --- + | Platz f"ur lokale Werte, die nicht mehr | localvars_num + | in Register passen | + ============================================= --- + | .... | arguments_num + --------------------------------------------- + | Parameter 8 | + --------------------------------------------- + SP ---> | Parameter 7 (f"ur aufgerufenen Methoden) | + ============================================= --- + + +Damit die Anf"ange der einzelnen Bereiche (im Codegenerator) leichter +ausgedr"uckt werden k"onnen, sind ein paar Hilfsvariablen vorgesehen, die +die Adressierung der einzelnen Bereiche vereinfachen: + localvars_base = arguments_num + savedregs_base = localvars_base + localvars_num + parentargs_base = savedregs_base + savedregs_num + diff --git a/alpha/cray.c b/alpha/cray.c new file mode 100644 index 000000000..b585bc428 --- /dev/null +++ b/alpha/cray.c @@ -0,0 +1,358 @@ +/****************************** asmpart.c ************************************** +* * +* is an assembly language file, but called .c to fake the preprocessor. * +* It contains the Java-C interace functions for Alpha processors. * +* * +* Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst * +* * +* See file COPYRIGHT for information on usage and disclaimer of warranties * +* * +* Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at * +* Andreas Krall EMAIL: cacao@complang.tuwien.ac.at * +* * +* Last Change: 1997/04/26 * +* * +*******************************************************************************/ + +#define v0 r0 + +#define t0 r1 +#define t1 r2 +#define t2 r3 +#define t3 r4 +#define t4 r5 +#define t5 r6 +#define t6 r7 +#define t7 r8 + +#define s0 r9 +#define s1 r10 +#define s2 r11 +#define s3 r12 +#define s4 r13 +#define s5 r14 +#define s6 r15 + +#define a0 r16 +#define a1 r17 +#define a2 r18 +#define a3 r19 +#define a4 r20 +#define a5 r21 + +#define t8 r22 +#define t9 r23 +#define t10 r24 +#define t11 r25 +#define ra r26 +#define t12 r27 + +#define pv t12 +#define AT . +#define gp r29 +#define sp r30 +#define zero r31 + +#define PAL_imb 134 + + +/* .set noat + .set noreorder +*/ + + +/********************* exported functions and variables ***********************/ + +/* .globl has_no_x_instr_set + .globl synchronize_caches + .globl asm_calljavamethod + .globl asm_call_jit_compiler + .globl asm_dumpregistersandcall +*/ + +/*************************** imported functions *******************************/ + +/* .globl compiler_compile +*/ + +/*********************** function has_no_x_instr_set *************************** +* * +* determines if the byte support instruction set (21164a and higher) * +* is available. * +* * +*******************************************************************************/ + zero <- t0 + + .ident has_no_x_instr_set + .psect code_sec, code +has_no_x_instr_set:: + +/* .long 0x47e03c20 ; amask 1,r0 +*/ + + zap r0,1,r0 + + jmp zero,(ra) ; return + + .end has_no_x_instr_set + + +/********************* function synchronize_caches ****************************/ + + .ident synchronize_caches + .psect code_sec, code +synchronize_caches:: + + call_pal PAL_imb ; synchronise instruction cache + jmp zero,(ra) ; return + + .end synchronize_caches + + + +/********************* function asm_calljavamethod ***************************** +* * +* This function calls a Java-method (which possibly needs compilation) * +* with up to 4 parameters. * +* * +* This functions calls the JIT-compiler which eventually translates the * +* method into machine code. * +* * +* An possibly throwed exception will be returned to the caller as function * +* return value, so the java method cannot return a fucntion value (this * +* function usually calls 'main' and '' which do not return a * +* function value). * +* * +* C-prototype: * +* javaobject_header *asm_calljavamethod (methodinfo *m, * +* void *arg1, void *arg2, void *arg3, void *arg4); * +* * +*******************************************************************************/ + + .ident asm_calljavamethod + .psect codesect3, code + .external asm_call_jit_compiler + +asm_calljavamethod:: + +; ldgp gp,0(pv) +; .prologue 1 + lda sp,-24(sp) ; allocate stack space + stq ra,0(sp) ; save return address + + stq r16,16(sp) ; save method pointer for compiler + lda r0,16(sp) ; pass pointer to method pointer via r0 + + bis r17,r17,r16 ; pass the remaining parameters + bis r18,r18,r17 + bis r19,r19,r18 + bis r20,r20,r19 + + la r28,asm_call_jit_compiler ; fake virtual function call + ; Changed!! from lda + + stq r28,8(sp) ; store function address + bis sp,sp,r28 ; set method pointer + + ldq pv,8(r28) ; method call as in Java + jmp ra,(pv) ; call JIT compiler + + ldq ra,0(sp) ; restore return address + lda sp,24(sp) ; free stack space + + bis r1,r1,r0 ; pass exception to caller (C) + jmp zero,(ra) + + .end asm_calljavamethod + + +/****************** function asm_call_jit_compiler ***************************** +* * +* invokes the compiler for untranslated JavaVM methods. * +* * +* Register R0 contains a pointer to the method info structure (prepared * +* by createcompilerstub). Using the return address in R26 and the * +* offset in the LDA instruction or using the value in methodptr R28 the * +* patching address for storing the method address can be computed: * +* * +* method address was either loaded using * +* M_LDQ (REG_PV, REG_PV, a) ; invokestatic/special (r27) * +* M_LDA (REG_PV, REG_RA, low) * +* M_LDAH(REG_PV, REG_RA, high) ; optional * +* or * +* M_LDQ (REG_PV, REG_METHODPTR, m) ; invokevirtual/interace (r28) * +* in the static case the method pointer can be computed using the * +* return address and the lda function following the jmp instruction * +* * +*******************************************************************************/ + + + .ident asm_call_jit_compiler + .psect code_sec1, code + .external compiler_compile + +asm_call_jit_compiler:: + +; ldgp gp,0(pv) +; .prologue 1 + ldl r22,-8(ra) ; load instruction LDQ PV,xxx(ryy) + srl r22,16,r22 ; shift right register number ryy + and r22,31,r22 ; isolate register number + subl r22,28,r22 ; test for REG_METHODPTR + beq r22,noregchange + ldl r22,0(ra) ; load instruction LDA PV,xxx(RA) + sll r22,48,r22 + sra r22,48,r22 ; isolate offset + addq r22,ra,r28 ; compute update address + ldl r22,4(ra) ; load instruction LDAH PV,xxx(PV) + srl r22,16,r22 ; isolate instruction code + lda r22,-0x177b(r22) ; test for LDAH + bne r22,noregchange + ldl r22,0(ra) ; load instruction LDA PV,xxx(RA) + sll r22,16,r22 ; compute high offset + addl r22,0,r22 ; sign extend high offset + addq r22,r28,r28 ; compute update address +noregchange: + lda sp,-14*8(sp) ; reserve stack space + stq r16,0*8(sp) ; save all argument registers + stq r17,1*8(sp) ; they could be used by method + stq r18,2*8(sp) + stq r19,3*8(sp) + stq r20,4*8(sp) + stq r21,5*8(sp) + stt f16,6*8(sp) + stt f17,7*8(sp) + stt f18,8*8(sp) + stt f19,9*8(sp) + stt f20,10*8(sp) + stt f21,11*8(sp) + stq r28,12*8(sp) ; save method pointer + stq ra,13*8(sp) ; save return address + + ldq r16,0(r0) ; pass 'methodinfo' pointer to + bsr ra,compiler_compile ; compiler +; ldgp gp,0(ra) + + call_pal PAL_imb ; synchronise instruction cache + + ldq r16,0*8(sp) ; load argument registers + ldq r17,1*8(sp) + ldq r18,2*8(sp) + ldq r19,3*8(sp) + ldq r20,4*8(sp) + ldq r21,5*8(sp) + ldt f16,6*8(sp) + ldt f17,7*8(sp) + ldt f18,8*8(sp) + ldt f19,9*8(sp) + ldt f20,10*8(sp) + ldt f21,11*8(sp) + ldq r28,12*8(sp) ; load method pointer + ldq ra,13*8(sp) ; load return address + lda sp,14*8(sp) ; deallocate stack area + + ldl r22,-8(ra) ; load instruction LDQ PV,xxx(ryy) + sll r22,48,r22 + sra r22,48,r22 ; isolate offset + + addq r22,r28,r22 ; compute update address via method pointer + stq r0,0(r22) ; save new method address there + + bis r0,r0,pv ; load method address into pv + + jmp zero, (pv) ; and call method. The method returns + ; directly to the caller (ra). + + .end asm_call_jit_compiler + + +/****************** function asm_dumpregistersandcall ************************** +* * +* This funtion saves all callee saved registers and calls the function * +* which is passed as parameter. * +* * +* This function is needed by the garbage collector, which needs to access * +* all registers which are stored on the stack. Unused registers are * +* cleared to avoid intererances with the GC. * +* * +* void asm_dumpregistersandcall (functionptr f); * +* * +*******************************************************************************/ + + .ident asm_dumpregistersandcall + .psect code_sec2, code +asm_dumpregistersandcall:: + lda sp,-16*8(sp) ; allocate stack + stq ra,0(sp) ; save return address + + stq r9,1*8(sp) ; save all callee saved registers + stq r10,2*8(sp) ; intialize the remaining registers + stq r11,3*8(sp) + stq r12,4*8(sp) + stq r13,5*8(sp) + stq r14,6*8(sp) + stq r15,7*8(sp) + stt f2,8*8(sp) + stt f3,9*8(sp) + stt f4,10*8(sp) + stt f5,11*8(sp) + stt f6,12*8(sp) + stt f7,13*8(sp) + stt f8,14*8(sp) + stt f9,15*8(sp) + + bis zero,zero,r0 ; intialize the remaining registers + bis zero,zero,r1 + bis zero,zero,r2 + bis zero,zero,r3 + bis zero,zero,r4 + bis zero,zero,r5 + bis zero,zero,r6 + bis zero,zero,r7 + bis zero,zero,r8 + bis zero,zero,r17 + bis zero,zero,r18 + bis zero,zero,r19 + bis zero,zero,r20 + bis zero,zero,r21 + bis zero,zero,r22 + bis zero,zero,r23 + bis zero,zero,r24 + bis zero,zero,r25 + bis zero,zero,r26 + bis zero,zero,r27 + bis zero,zero,r28 + bis zero,zero,r29 + cpys f31,f31,f0 + cpys f31,f31,f1 + cpys f31,f31,f10 + cpys f31,f31,f11 + cpys f31,f31,f12 + cpys f31,f31,f13 + cpys f31,f31,f14 + cpys f31,f31,f15 + cpys f31,f31,f16 + cpys f31,f31,f17 + cpys f31,f31,f18 + cpys f31,f31,f19 + cpys f31,f31,f20 + cpys f31,f31,f21 + cpys f31,f31,f22 + cpys f31,f31,f23 + cpys f31,f31,f24 + cpys f31,f31,f25 + cpys f31,f31,f26 + cpys f31,f31,f27 + cpys f31,f31,f28 + cpys f31,f31,f29 + cpys f31,f31,f30 + + bis r16,r16,pv ; load function pointer + jmp ra,(pv) ; and call function + + ldq ra,0(sp) ; load return address + lda sp,16*8(sp) ; deallocate stack + jmp zero,(ra) ; return + + .end + diff --git a/alpha/defines.h b/alpha/defines.h new file mode 100644 index 000000000..e64e10b18 --- /dev/null +++ b/alpha/defines.h @@ -0,0 +1,19 @@ +/*************************** alpha/defines.h *********************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + system-dependent definitions + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/09/11 + +*******************************************************************************/ + +#define USE_INTERNAL_THREADS + +#define HAVE_FCNTL +#define HAVE_IOCTL diff --git a/alpha/disass.c b/alpha/disass.c new file mode 100644 index 000000000..f4325066f --- /dev/null +++ b/alpha/disass.c @@ -0,0 +1,301 @@ +/********************************* disass.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + A very primitive disassembler for Alpha machine code for easy debugging. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/22 + +*******************************************************************************/ + + +#define ITYPE_UNDEF 0 +#define ITYPE_JMP 1 +#define ITYPE_MEM 2 +#define ITYPE_BRA 3 +#define ITYPE_OP 4 +#define ITYPE_FOP 5 + +static struct { int op; char *name; int itype; } ops[] = { + { 0x00, "", ITYPE_UNDEF}, + { 0x01, "", ITYPE_UNDEF}, + { 0x02, "", ITYPE_UNDEF}, + { 0x03, "", ITYPE_UNDEF}, + { 0x04, "", ITYPE_UNDEF}, + { 0x05, "", ITYPE_UNDEF}, + { 0x06, "", ITYPE_UNDEF}, + { 0x07, "", ITYPE_UNDEF}, + { 0x08, "LDA ", ITYPE_MEM}, + { 0x09, "LDAH ", ITYPE_MEM}, + { 0x0a, "LDB ", ITYPE_MEM}, + { 0x0b, "LDQ_U ", ITYPE_MEM}, + { 0x0c, "LDW ", ITYPE_MEM}, + { 0x0d, "STW ", ITYPE_MEM}, + { 0x0e, "STB ", ITYPE_MEM}, + { 0x0f, "STQ_U ", ITYPE_MEM}, + { 0x10, "OP ", ITYPE_OP}, + { 0x11, "OP ", ITYPE_OP}, + { 0x12, "OP ", ITYPE_OP}, + { 0x13, "OP ", ITYPE_OP}, + { 0x14, "", ITYPE_UNDEF}, + { 0x15, "", ITYPE_UNDEF}, + { 0x16, "FOP ", ITYPE_FOP}, + { 0x17, "FOP ", ITYPE_FOP}, + { 0x18, "MEMFMT ", ITYPE_MEM}, + { 0x19, "", ITYPE_UNDEF}, + { 0x1a, "JMP ", ITYPE_JMP}, + { 0x1b, "", ITYPE_UNDEF}, + { 0x1c, "OP ", ITYPE_OP}, + { 0x1d, "", ITYPE_UNDEF}, + { 0x1e, "", ITYPE_UNDEF}, + { 0x1f, "", ITYPE_UNDEF}, + { 0x20, "LDF ", ITYPE_MEM}, + { 0x21, "LDG ", ITYPE_MEM}, + { 0x22, "LDS ", ITYPE_MEM}, + { 0x23, "LDT ", ITYPE_MEM}, + { 0x24, "STF ", ITYPE_MEM}, + { 0x25, "STG ", ITYPE_MEM}, + { 0x26, "STS ", ITYPE_MEM}, + { 0x27, "STT ", ITYPE_MEM}, + { 0x28, "LDL ", ITYPE_MEM}, + { 0x29, "LDQ ", ITYPE_MEM}, + { 0x2a, "LDL_L ", ITYPE_MEM}, + { 0x2b, "LDQ_L ", ITYPE_MEM}, + { 0x2c, "STL ", ITYPE_MEM}, + { 0x2d, "STQ ", ITYPE_MEM}, + { 0x2e, "STL_C ", ITYPE_MEM}, + { 0x2f, "STQ_C ", ITYPE_MEM}, + { 0x30, "BR ", ITYPE_BRA}, + { 0x31, "FBEQ ", ITYPE_BRA}, + { 0x32, "FBLT ", ITYPE_BRA}, + { 0x33, "FBLE ", ITYPE_BRA}, + { 0x34, "BSR ", ITYPE_BRA}, + { 0x35, "FBNE ", ITYPE_BRA}, + { 0x36, "FBGE ", ITYPE_BRA}, + { 0x37, "FBGT ", ITYPE_BRA}, + { 0x38, "BLBC ", ITYPE_BRA}, + { 0x39, "BEQ ", ITYPE_BRA}, + { 0x3a, "BLT ", ITYPE_BRA}, + { 0x3b, "BLE ", ITYPE_BRA}, + { 0x3c, "BLBS ", ITYPE_BRA}, + { 0x3d, "BNE ", ITYPE_BRA}, + { 0x3e, "BGE ", ITYPE_BRA}, + { 0x3f, "BGT ", ITYPE_BRA} +}; + +static struct { u2 op,fun; char *name; } op3s[] = { + { 0x10, 0x00, "ADDL " }, + { 0x10, 0x40, "ADDL/V " }, + { 0x10, 0x20, "ADDQ " }, + { 0x10, 0x60, "ADDQ/V " }, + { 0x10, 0x09, "SUBL " }, + { 0x10, 0x49, "SUBL/V " }, + { 0x10, 0x29, "SUBQ " }, + { 0x10, 0x69, "SUBQ/V " }, + { 0x10, 0x2D, "CMPEQ " }, + { 0x10, 0x4D, "CMPLT " }, + { 0x10, 0x6D, "CMPLE " }, + { 0x10, 0x1D, "CMPULT " }, + { 0x10, 0x3D, "CMPULE " }, + { 0x10, 0x0F, "CMPBGE " }, + { 0x10, 0x02, "S4ADDL " }, + { 0x10, 0x0b, "S4SUBL " }, + { 0x10, 0x22, "S4ADDQ " }, + { 0x10, 0x2b, "S4SUBQ " }, + { 0x10, 0x12, "S8ADDL " }, + { 0x10, 0x1b, "S8SUBL " }, + { 0x10, 0x32, "S8ADDQ " }, + { 0x10, 0x3b, "S8SUBQ " }, + { 0x11, 0x00, "AND " }, + { 0x11, 0x20, "OR " }, + { 0x11, 0x40, "XOR " }, + { 0x11, 0x08, "ANDNOT " }, + { 0x11, 0x28, "ORNOT " }, + { 0x11, 0x48, "XORNOT " }, + { 0x11, 0x24, "CMOVEQ " }, + { 0x11, 0x44, "CMOVLT " }, + { 0x11, 0x64, "CMOVLE " }, + { 0x11, 0x26, "CMOVNE " }, + { 0x11, 0x46, "CMOVGE " }, + { 0x11, 0x66, "CMOVGT " }, + { 0x11, 0x14, "CMOVLBS" }, + { 0x11, 0x16, "CMOVLBC" }, + { 0x12, 0x39, "SLL " }, + { 0x12, 0x3C, "SRA " }, + { 0x12, 0x34, "SRL " }, + { 0x12, 0x30, "ZAP " }, + { 0x12, 0x31, "ZAPNOT " }, + { 0x12, 0x06, "EXTBL " }, + { 0x12, 0x16, "EXTWL " }, + { 0x12, 0x26, "EXTLL " }, + { 0x12, 0x36, "EXTQL " }, + { 0x12, 0x5a, "EXTWH " }, + { 0x12, 0x6a, "EXTLH " }, + { 0x12, 0x7a, "EXTQH " }, + { 0x12, 0x0b, "INSBL " }, + { 0x12, 0x1b, "INSWL " }, + { 0x12, 0x2b, "INSLL " }, + { 0x12, 0x3b, "INSQL " }, + { 0x12, 0x57, "INSWH " }, + { 0x12, 0x67, "INSLH " }, + { 0x12, 0x77, "INSQH " }, + { 0x12, 0x02, "MSKBL " }, + { 0x12, 0x12, "MSKWL " }, + { 0x12, 0x22, "MSKLL " }, + { 0x12, 0x32, "MSKQL " }, + { 0x12, 0x52, "MSKWH " }, + { 0x12, 0x62, "MSKLH " }, + { 0x12, 0x72, "MSKQH " }, + { 0x13, 0x00, "MULL " }, + { 0x13, 0x60, "MULQ/V " }, + { 0x13, 0x40, "MULL/V " }, + { 0x13, 0x30, "UMULH " }, + { 0x16, 0x080, "FADD " }, + { 0x16, 0x0a0, "DADD " }, + { 0x16, 0x081, "FSUB " }, + { 0x16, 0x0a1, "DSUB " }, + { 0x16, 0x082, "FMUL " }, + { 0x16, 0x0a2, "DMUL " }, + { 0x16, 0x083, "FDIV " }, + { 0x16, 0x0a3, "DDIV " }, + { 0x16, 0x580, "FADDS " }, + { 0x16, 0x5a0, "DADDS " }, + { 0x16, 0x581, "FSUBS " }, + { 0x16, 0x5a1, "DSUBS " }, + { 0x16, 0x582, "FMULS " }, + { 0x16, 0x5a2, "DMULS " }, + { 0x16, 0x583, "FDIVS " }, + { 0x16, 0x5a3, "DDIVS " }, + { 0x16, 0x0ac, "CVTDF " }, + { 0x16, 0x0bc, "CVTLF " }, + { 0x16, 0x0be, "CVTLD " }, + { 0x16, 0x0af, "CVTDL " }, + { 0x16, 0x02f, "CVTDLC " }, + { 0x16, 0x5ac, "CVTDFS " }, + { 0x16, 0x5af, "CVTDLS " }, + { 0x16, 0x52f, "CVTDLCS" }, + { 0x16, 0x0a4, "FCMPUN " }, + { 0x16, 0x0a5, "FCMPEQ " }, + { 0x16, 0x0a6, "FCMPLT " }, + { 0x16, 0x0a7, "FCMPLE " }, + { 0x16, 0x5a4, "FCMPUNS" }, + { 0x16, 0x5a5, "FCMPEQS" }, + { 0x16, 0x5a6, "FCMPLTS" }, + { 0x16, 0x5a7, "FCMPLES" }, + { 0x17, 0x020, "FMOV " }, + { 0x17, 0x021, "FMOVN " }, + { 0x1c, 0x0, "BSEXT " }, + { 0x1c, 0x1, "WSEXT " }, + + { 0x00, 0x00, NULL } +}; + + +static void disasscmd (int c, int pos) +{ + int op, opfun, fopfun, i; + int ra, rb, rc, lit, disp; + + op = (c>>26) & 0x3f; + opfun = (c>>5) & 0x7f; + fopfun = (c>>5) & 0x7ff; + ra = (c>>21) & 0x1f; + rb = (c>>16) & 0x1f; + rc = (c>>0) & 0x1f; + lit = (c>>13) & 0xff; + disp = (c<<16) >> 16; + + printf ("%6x: %8x ", pos, c); + + switch ( ops[op].itype ) { + case ITYPE_JMP: + switch ((c>>14) & 3) { + case 0: + printf ("JMP "); + break; + case 1: + printf ("JSR "); + break; + case 2: + printf ("RET "); + break; + case 3: + printf ("JSR_CO "); + break; + } + printf ("$%d,$%d\n", ra, rb); + break; + + case ITYPE_MEM: + if (op == 0x18 && ra == 0 && ra == 0 && disp == 0) + printf ("TRAPB\n"); + else + printf ("%s $%d,$%d,%d\n", ops[op].name, ra, rb, disp); + break; + + case ITYPE_BRA: + printf ("%s $%d,%x\n", ops[op].name, ra, pos + 4 + ((c << 11) >> 9)); + break; + + case ITYPE_FOP: + if (op == 0x17 && fopfun == 0x020 && ra == rb) { + if (ra == 31 && rc == 31) + printf ("FNOP\n"); + else + printf ("FMOV $f%d,$f%d\n", ra, rc); + return; + } + for (i = 0; op3s[i].name; i++) + if (op3s[i].op == op && op3s[i].fun == fopfun) { + printf ("%s $f%d,$f%d,$f%d\n", op3s[i].name, ra, rb, rc); + return; + } + printf ("%s%x $f%d,$f%d,$f%d\n", ops[op].name, fopfun, ra, rb, rc); + break; + + case ITYPE_OP: + if (op == 0x11 && opfun == 0x20 && ra == rb && ~(c&0x1000)) { + if (ra == 31 && rc == 31) + printf ("NOP\n"); + else + printf ("MOV $%d,$%d\n", ra, rc); + return; + } + for (i = 0; op3s[i].name; i++) { + if (op3s[i].op == op && op3s[i].fun == opfun) { + if (c&0x1000) + printf ("%s $%d,#%d,$%d\n", op3s[i].name, ra, lit, rc); + else + printf ("%s $%d,$%d,$%d\n", op3s[i].name, ra, rb, rc); + return; + } + } + /* fall through */ + default: + if (c&0x1000) + printf ("UNDEF %x(%x) $%d,#%d,$%d\n", op, opfun, ra, lit, rc); + else + printf ("UNDEF %x(%x) $%d,$%d,$%d\n", op, opfun, ra, rb, rc); + } +} + + +/*********************** funktion disassemble ********************************** + + outputs a disassembler listing of some machine code on 'stdout' + +*******************************************************************************/ + +static void disassemble (int *code, int len) +{ + int p; + + printf (" --- disassembler listing ---\n"); + for (p = 0; p < len; p += 4, code++) + disasscmd (*code, p); +} diff --git a/alpha/gen.c b/alpha/gen.c new file mode 100644 index 000000000..467b6bea2 --- /dev/null +++ b/alpha/gen.c @@ -0,0 +1,1847 @@ +/***************************** alpha/gen.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the codegenerator for an Alpha processor. + This module generates Alpha machine code for a sequence of + pseudo commands (PCMDs). + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/22 + +*******************************************************************************/ + + + +/******************************************************************************* + +Datatypes and Register Allocations: +----------------------------------- + +On 64-bit-machines (like the Alpha) all operands are stored in the +registers in a 64-bit form, even when the correspondig JavaVM +operands only need 32 bits. +This is done by a canonical representation: + +32-bit integers are allways stored as sign-extended 64-bit values +(this approach is directly supported by the Alpha architecture and +is very easy to implement). + +32-bit-floats are stored in a 64-bit doubleprecision register by +simply expanding the exponent and mantissa with zeroes. +(also supported by the architecture) + + +Stackframes: + +The calling conventions and the layout of the stack is +explained in detail in the documention file: calling.doc + +*******************************************************************************/ + + +/************************ Preallocated registers ******************************/ + +/* integer registers */ + +#define REG_RESULT 0 /* to deliver method results */ +#define REG_EXCEPTION 1 /* to throw an exception across method bounds */ + +#define REG_RA 26 /* return address */ +#define REG_PV 27 /* procedure vector, must be provided by caller */ +#define REG_METHODPTR 28 /* pointer to the place from where the procedure */ + /* vector has been fetched */ +#define REG_ITMP1 25 /* temporary register */ +#define REG_ITMP2 28 /* temporary register */ +#define REG_ITMP3 29 /* temporary register */ + +#define REG_SP 30 /* stack pointer */ +#define REG_ZERO 31 /* allways zero */ + +/* floating point registers */ + +#define REG_FRESULT 0 /* to deliver floating point method results */ +#define REG_FTMP1 28 /* temporary floating point register */ +#define REG_FTMP2 29 /* temporary floating point register */ +#define REG_FTMP3 30 /* temporary floating point register */ + + +/******************** register descripton - array *****************************/ + +/* #define REG_RES 0 reserved register for OS or code generator */ +/* #define REG_RET 1 return value register */ +/* #define REG_EXC 2 exception value register */ +/* #define REG_SAV 3 (callee) saved register */ +/* #define REG_TMP 4 scratch temporary register (caller saved) */ +/* #define REG_ARG 5 argument register (caller saved) */ + +/* #define REG_END -1 last entry in tables */ + +int regdescint[] = { + REG_RET, REG_EXC, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, + REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, + REG_END }; + +#define INT_SAV_FST 9 /* first int callee saved register */ +#define INT_SAV_CNT 7 /* number of int callee saved registers */ +#define INT_ARG_FST 16 /* first int callee saved register */ +#define INT_ARG_CNT 6 /* number of int callee saved registers */ + +/* for use of reserved registers, see comment above */ + +int regdescfloat[] = { + REG_RET, REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + REG_SAV, REG_SAV, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, + REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, + REG_END }; + +#define FLT_SAV_FST 2 /* first int callee saved register */ +#define FLT_SAV_CNT 8 /* number of int callee saved registers */ +#define FLT_ARG_FST 16 /* first int callee saved register */ +#define FLT_ARG_CNT 6 /* number of int callee saved registers */ + +/* for use of reserved registers, see comment above */ + + +/*** parameter allocation mode ***/ + +int reg_parammode = PARAMMODE_NUMBERED; + + /* parameter-registers will be allocated by assigning the + 1. parameter: int/float-reg 16 + 2. parameter: int/float-reg 17 + 3. parameter: int/float-reg 18 .... + */ + + +/************************** stackframe-infos **********************************/ + +int localvars_base; /* offset in stackframe for the local variables */ +int savedregs_base; /* offset in stackframe for the save area */ +int parentargs_base; /* offset in stackframe for the parameter from the caller*/ + +/* -> see file 'calling.doc' */ + + +/******************** macros to create code ***********************************/ + +/* 3-address-operations: M_OP3 + op ..... opcode + fu ..... function-number + a ..... register number source 1 + b ..... register number or constant integer source 2 + c ..... register number destination + const .. switch to use b as constant integer + (0 means: use b as register number) + (1 means: use b as constant 8-bit-integer) +*/ +#define M_OP3(op,fu,a,b,c,const) \ + mcode_adds4 ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \ + ((const)<<12)|((fu)<<5)|((c)) ) + +/* 3-address-floating-point-operation: M_FOP3 + op .... opcode + fu .... function-number + a,b ... source floating-point registers + c ..... destination register +*/ +#define M_FOP3(op,fu,a,b,c) \ + mcode_adds4 ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) ) + +/* branch instructions: M_BRA + op ..... opcode + a ...... register to be tested + disp ... relative address to be jumped to (divided by 4) +*/ +#define M_BRA(op,a,disp) \ + mcode_adds4 ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) ) + + +/* memory operations: M_MEM + op ..... opcode + a ...... source/target register for memory access + b ...... base register + disp ... displacement (16 bit signed) to be added to b +*/ +#define M_MEM(op,a,b,disp) \ + mcode_adds4 ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) ) + + +/***** macros for all used commands (see an Alpha-manual for description) *****/ + +#define M_LDA(a,b,disp) M_MEM (0x08,a,b,disp) /* low const */ +#define M_LDAH(a,b,disp) M_MEM (0x09,a,b,disp) /* high const */ +#define M_BLDU(a,b,disp) M_MEM (0x0a,a,b,disp) /* 8 load */ +#define M_SLDU(a,b,disp) M_MEM (0x0c,a,b,disp) /* 16 load */ +#define M_ILD(a,b,disp) M_MEM (0x28,a,b,disp) /* 32 load */ +#define M_LLD(a,b,disp) M_MEM (0x29,a,b,disp) /* 64 load */ +#define M_BST(a,b,disp) M_MEM (0x0e,a,b,disp) /* 8 store */ +#define M_SST(a,b,disp) M_MEM (0x0d,a,b,disp) /* 16 store */ +#define M_IST(a,b,disp) M_MEM (0x2c,a,b,disp) /* 32 store */ +#define M_LST(a,b,disp) M_MEM (0x2d,a,b,disp) /* 64 store */ + +#define M_BSEXT(b,c) M_OP3 (0x1c,0x0,REG_ZERO,b,c,0) /* 8 signext */ +#define M_SSEXT(b,c) M_OP3 (0x1c,0x1,REG_ZERO,b,c,0) /* 16 signext */ + +#define M_BR(disp) M_BRA (0x30,REG_ZERO,disp) /* branch */ +#define M_BSR(ra,disp) M_BRA (0x34,ra,disp) /* branch sbr */ +#define M_BEQZ(a,disp) M_BRA (0x39,a,disp) /* br a == 0 */ +#define M_BLTZ(a,disp) M_BRA (0x3a,a,disp) /* br a < 0 */ +#define M_BLEZ(a,disp) M_BRA (0x3b,a,disp) /* br a <= 0 */ +#define M_BNEZ(a,disp) M_BRA (0x3d,a,disp) /* br a != 0 */ +#define M_BGEZ(a,disp) M_BRA (0x3e,a,disp) /* br a >= 0 */ +#define M_BGTZ(a,disp) M_BRA (0x3f,a,disp) /* br a > 0 */ + +#define M_JMP(a,b) M_MEM (0x1a,a,b,0x0000) /* jump */ +#define M_JSR(a,b) M_MEM (0x1a,a,b,0x4000) /* call sbr */ +#define M_RET(a,b) M_MEM (0x1a,a,b,0x8000) /* return */ + +#define M_IADD(a,b,c,const) M_OP3 (0x10,0x0, a,b,c,const) /* 32 add */ +#define M_LADD(a,b,c,const) M_OP3 (0x10,0x20, a,b,c,const) /* 64 add */ +#define M_ISUB(a,b,c,const) M_OP3 (0x10,0x09, a,b,c,const) /* 32 sub */ +#define M_LSUB(a,b,c,const) M_OP3 (0x10,0x29, a,b,c,const) /* 64 sub */ +#define M_IMUL(a,b,c,const) M_OP3 (0x13,0x00, a,b,c,const) /* 32 mul */ +#define M_LMUL(a,b,c,const) M_OP3 (0x13,0x20, a,b,c,const) /* 64 mul */ + +#define M_CMPEQ(a,b,c,const) M_OP3 (0x10,0x2d, a,b,c,const) /* c = a == b */ +#define M_CMPLT(a,b,c,const) M_OP3 (0x10,0x4d, a,b,c,const) /* c = a < b */ +#define M_CMPLE(a,b,c,const) M_OP3 (0x10,0x6d, a,b,c,const) /* c = a <= b */ + +#define M_CMPULE(a,b,c,const) M_OP3 (0x10,0x3d, a,b,c,const) /* c = a <= b */ + +#define M_AND(a,b,c,const) M_OP3 (0x11,0x00, a,b,c,const) /* c = a & b */ +#define M_OR(a,b,c,const) M_OP3 (0x11,0x20, a,b,c,const) /* c = a | b */ +#define M_XOR(a,b,c,const) M_OP3 (0x11,0x40, a,b,c,const) /* c = a ^ b */ + +#define M_SLL(a,b,c,const) M_OP3 (0x12,0x39, a,b,c,const) /* c = a << b */ +#define M_SRA(a,b,c,const) M_OP3 (0x12,0x3c, a,b,c,const) /* c = a >> b */ +#define M_SRL(a,b,c,const) M_OP3 (0x12,0x34, a,b,c,const) /* c = a >>>b */ + +#define M_FLD(a,b,disp) M_MEM (0x22,a,b,disp) /* load flt */ +#define M_DLD(a,b,disp) M_MEM (0x23,a,b,disp) /* load dbl */ +#define M_FST(a,b,disp) M_MEM (0x26,a,b,disp) /* store flt */ +#define M_DST(a,b,disp) M_MEM (0x27,a,b,disp) /* store dbl */ + +#define M_FADD(a,b,c) M_FOP3 (0x16, 0x080, a,b,c) /* flt add */ +#define M_DADD(a,b,c) M_FOP3 (0x16, 0x0a0, a,b,c) /* dbl add */ +#define M_FSUB(a,b,c) M_FOP3 (0x16, 0x081, a,b,c) /* flt sub */ +#define M_DSUB(a,b,c) M_FOP3 (0x16, 0x0a1, a,b,c) /* dbl sub */ +#define M_FMUL(a,b,c) M_FOP3 (0x16, 0x082, a,b,c) /* flt mul */ +#define M_DMUL(a,b,c) M_FOP3 (0x16, 0x0a2, a,b,c) /* dbl mul */ +#define M_FDIV(a,b,c) M_FOP3 (0x16, 0x083, a,b,c) /* flt div */ +#define M_DDIV(a,b,c) M_FOP3 (0x16, 0x0a3, a,b,c) /* dbl div */ + +#define M_CVTLF(a,b,c) M_FOP3 (0x16, 0x0bc, a,b,c) /* long2flt */ +#define M_CVTLD(a,b,c) M_FOP3 (0x16, 0x0be, a,b,c) /* long2dbl */ +#define M_CVTDL(a,b,c) M_FOP3 (0x16, 0x0af, a,b,c) /* dbl2long */ +#define M_CVTDL_C(a,b,c) M_FOP3 (0x16, 0x02f, a,b,c) /* dbl2long */ + +#define M_FCMPEQ(a,b,c) M_FOP3 (0x16, 0x0a5, a,b,c) /* c = a==b */ +#define M_FCMPLT(a,b,c) M_FOP3 (0x16, 0x0a6, a,b,c) /* c = a=0 ? c=b */ +#define M_CMOVLE(a,b,c,const) M_OP3 (0x11,0x64, a,b,c,const) /* a<=0 ? c=b */ +#define M_CMOVGT(a,b,c,const) M_OP3 (0x11,0x66, a,b,c,const) /* a> 0 ? c=b */ + +#define M_CMPULT(a,b,c,const) M_OP3 (0x10,0x1d, a,b,c,const) +#define M_CMPBGE(a,b,c,const) M_OP3 (0x10,0x0f, a,b,c,const) + +#define M_FCMPUN(a,b,c) M_FOP3 (0x16, 0x0a4, a,b,c) /* unordered */ +#define M_FCMPLE(a,b,c) M_FOP3 (0x16, 0x0a7, a,b,c) /* c = a<=b */ + +#define M_FBNEZ(fa,disp) M_BRA (0x35,fa,disp) +#define M_FBLEZ(fa,disp) M_BRA (0x33,fa,disp) + +#define M_JMP_CO(a,b) M_MEM (0x1a,a,b,0xc000) /* call cosub */ + + +/******************** system independent macros *******************************/ + + + +/************** additional functions to generate code *************************/ + + +/* M_INTMOVE: + generates an integer-move from register a to b. + if a and b are the same int-register, no code will be generated. +*/ + +static void M_INTMOVE(int a, int b) +{ + if (a == b) return; + M_OR (a,a,b, 0); +} + + +/* M_FLTMOVE: + generates a floating-point-move from register a to b. + if a and b are the same float-register, no code will be generated +*/ + +static void M_FLTMOVE(int a, int b) +{ + if (a == b) return; + M_FMOV (a, b); +} + + +/* var_to_reg_xxx: + this function generates code to fetch data from a pseudo-register + into a real register. + If the pseudo-register has actually been assigned to a real + register, no code will be emitted, since following operations + can use this register directly. + + v: pseudoregister to be fetched from + tempregnum: temporary register to be used if v is actually spilled to ram + + return: the register number, where the operand can be found after + fetching (this wil be either tempregnum or the register + number allready given to v) +*/ + +static int var_to_reg_int (varid v, int tempregnum) +{ + reginfo *ri = v->reg; + + if (!(ri->typeflags & REG_INMEMORY)) + return ri->num; +#ifdef STATISTICS + count_spills++; +#endif + M_LLD (tempregnum, REG_SP, 8 * (localvars_base + ri->num) ); + return tempregnum; +} + + +static int var_to_reg_flt (varid v, int tempregnum) +{ + reginfo *ri = v->reg; + + + if (!(ri->typeflags & REG_INMEMORY)) + return ri->num; +#ifdef STATISTICS + count_spills++; +#endif + M_DLD (tempregnum, REG_SP, 8 * (localvars_base + ri->num) ); + return tempregnum; +} + + +/* reg_of_var: + This function determines a register, to which the result of an + operation should go, when it is ultimatively intended to store the result + in pseudoregister v. + If v is assigned to an actual register, this register will be + returned. + Otherwise (when v is spilled) this function returns tempregnum. +*/ + +static int reg_of_var(varid v, int tempregnum) +{ + if (!(v->reg->typeflags & REG_INMEMORY)) + return v->reg->num; + return tempregnum; +} + + +/* store_reg_to_var_xxx: + This function generates the code to store the result of an operation + back into a spilled pseudo-variable. + If the pseudo-variable has not been spilled in the first place, this + function will generate nothing. + + v ............ Pseudovariable + tempregnum ... Number of the temporary registers as returned by + reg_of_var. +*/ + +static void store_reg_to_var_int (varid v, int tempregnum) +{ + reginfo *ri = v->reg; + + if (!(ri->typeflags & REG_INMEMORY)) + return; +#ifdef STATISTICS + count_spills++; +#endif + M_LST (tempregnum, REG_SP, 8 * (localvars_base + ri->num) ); +} + +static void store_reg_to_var_flt (varid v, int tempregnum) +{ + reginfo *ri = v->reg; + + if (!(ri->typeflags & REG_INMEMORY)) + return; +#ifdef STATISTICS + count_spills++; +#endif + M_DST (tempregnum, REG_SP, 8 * (localvars_base + ri->num) ); +} + + +/***************** functions to process the pseudo commands *******************/ + +/* gen_method: + function to generate method-call +*/ + +static void gen_method (pcmd *c) +{ + int p, pa, r; + s4 a; + reginfo *ri; + classinfo *ci; + + for (p = 0; p < c->u.method.paramnum; p++) { + ri = c->u.method.params[p]->reg; + + if (p < INT_ARG_CNT) { /* arguments that go into registers */ + if (IS_INT_LNG_REG(ri->typeflags)) { + if (!(ri->typeflags & REG_INMEMORY)) + M_INTMOVE(ri->num, INT_ARG_FST+p); + else + M_LLD(INT_ARG_FST+p, REG_SP, 8*(localvars_base + ri->num)); + } + else { + if (!(ri->typeflags & REG_INMEMORY)) + M_FLTMOVE (ri->num, FLT_ARG_FST+p); + else + M_DLD(FLT_ARG_FST+p, REG_SP, 8*(localvars_base + ri->num)); + } + } + else { /* arguments that go into memory */ + pa = p - INT_ARG_CNT; + if (pa >= arguments_num) + panic ("invalid stackframe structure"); + + if (IS_INT_LNG_REG(ri->typeflags)) { + r = var_to_reg_int (c->u.method.params[p], REG_ITMP1); + M_LST(r, REG_SP, 8 * (0 + pa)); + } + else { + r = var_to_reg_flt (c->u.method.params[p], REG_FTMP1); + M_DST (r, REG_SP, 8 * (0 + pa)); + } + } + } /* end of for */ + + switch (c->opcode) { + case CMD_BUILTIN: + a = dseg_addaddress ( (void*) (c->u.method.builtin) ); + + M_LLD (REG_PV, REG_PV, a); /* Pointer to built-in-function */ + goto makeactualcall; + + case CMD_INVOKESTATIC: + case CMD_INVOKESPECIAL: + a = dseg_addaddress ( c->u.method.method->stubroutine ); + + M_LLD (REG_PV, REG_PV, a ); /* Method-Pointer in r27 */ + + goto makeactualcall; + + case CMD_INVOKEVIRTUAL: + + M_LLD (REG_METHODPTR, 16, OFFSET(java_objectheader, vftbl)); + M_LLD (REG_PV, REG_METHODPTR, + OFFSET(vftbl,table[0]) + + sizeof(methodptr) * c->u.method.method->vftblindex ); + + goto makeactualcall; + + case CMD_INVOKEINTERFACE: + ci = c->u.method.method->class; + + M_LLD (REG_METHODPTR, 16, OFFSET(java_objectheader, vftbl)); + M_LLD (REG_METHODPTR, REG_METHODPTR, OFFSET(vftbl, interfacevftbl)); + M_LLD (REG_METHODPTR, REG_METHODPTR, sizeof(methodptr*) * ci->index); + M_LLD (REG_PV, REG_METHODPTR, sizeof(methodptr) * (c->u.method.method - ci->methods) ); + + goto makeactualcall; + + default: + sprintf (logtext, "Unkown PCMD-Command: %d", c->opcode); + error (); + } + + +makeactualcall: + + + M_JSR (REG_RA, REG_PV); + if (mcodelen<=32768) M_LDA (REG_PV, REG_RA, -mcodelen); + else { + s4 ml=-mcodelen, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + + if ( c->dest ) { + ri = c->dest->reg; + + if (IS_INT_LNG_REG(ri->typeflags)) { + if (!(ri->typeflags & REG_INMEMORY)) + M_INTMOVE (REG_RESULT, ri->num); + else M_LST (REG_RESULT, REG_SP, 8 * (localvars_base + ri->num) ); + } + else { + if (!(ri->typeflags & REG_INMEMORY)) + M_FLTMOVE (REG_RESULT, ri->num); + else M_DST (REG_RESULT, REG_SP, 8 * (localvars_base + ri->num) ); + } + } + + if (c->u.method.exceptionvar) { + ri = c->u.method.exceptionvar->reg; + if (!(ri->typeflags & REG_INMEMORY)) + M_INTMOVE (REG_EXCEPTION, ri->num); + else M_LST (REG_EXCEPTION, REG_SP, 8 *(localvars_base + ri->num) ); + } +} + + +/************************ function block_genmcode ****************************** + + generates machine code for a complete basic block + +*******************************************************************************/ + + +static void block_genmcode(basicblock *b) +{ + int s1, s2, s3, d; + s4 a; + pcmd *c; + + mcode_blockstart (b); + + for(c = list_first(&(b->pcmdlist)); + c != NULL; + c = list_next(&(b->pcmdlist), c)) + + switch (c->opcode) { + + case CMD_TRACEBUILT: + M_LDA (REG_SP, REG_SP, -8); + a = dseg_addaddress (c->u.a.value); + M_LLD(REG_ITMP1, REG_PV, a); + M_LST(REG_ITMP1, REG_SP, 0); + a = dseg_addaddress ((void*) (builtin_trace_args)); + M_LLD(REG_PV, REG_PV, a); + M_JSR (REG_RA, REG_PV); + if (mcodelen<=32768) M_LDA (REG_PV, REG_RA, -mcodelen); + else { + s4 ml=-mcodelen, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + M_LDA (REG_SP, REG_SP, 8); + b -> mpc = mcodelen; + break; + + + /*********************** constant operations **************************/ + + case CMD_LOADCONST_I: + d = reg_of_var(c->dest, REG_ITMP1); + if ( (c->u.i.value >= -32768) && (c->u.i.value <= 32767) ) { + M_LDA (d, REG_ZERO, c->u.i.value); + } + else { + a = dseg_adds4 (c->u.i.value); + M_ILD (d, REG_PV, a); + } + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LOADCONST_L: + d = reg_of_var(c->dest, REG_ITMP1); +#if U8_AVAILABLE + if ((c->u.l.value >= -32768) && (c->u.l.value <= 32767) ) { + M_LDA (d, REG_ZERO, c->u.l.value); + } + else { + a = dseg_adds8 (c->u.l.value); + M_LLD (d, REG_PV, a); + } +#else + a = dseg_adds8 (c->u.l.value); + M_LLD (d, REG_PV, a); +#endif + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LOADCONST_F: + d = reg_of_var (c->dest, REG_FTMP1); + a = dseg_addfloat (c->u.f.value); + M_FLD (d, REG_PV, a); + store_reg_to_var_flt (c->dest, d); + break; + + case CMD_LOADCONST_D: + d = reg_of_var (c->dest, REG_FTMP1); + a = dseg_adddouble (c->u.d.value); + M_DLD (d, REG_PV, a); + store_reg_to_var_flt (c->dest, d); + break; + + + case CMD_LOADCONST_A: + d = reg_of_var(c->dest, REG_ITMP1); + if (c->u.a.value) { + a = dseg_addaddress (c->u.a.value); + M_LLD (d, REG_PV, a); + } + else { + M_INTMOVE (REG_ZERO, d); + } + store_reg_to_var_int(c->dest, d); + break; + + /************************* move operation *****************************/ + + case CMD_MOVE: + if (IS_INT_LNG_REG(c->source1->reg->typeflags)) { + d = reg_of_var(c->dest, REG_ITMP1); + s1 = var_to_reg_int(c->source1, d); + M_INTMOVE(s1,d); + store_reg_to_var_int(c->dest, d); + } + else { + d = reg_of_var(c->dest, REG_FTMP1); + s1 = var_to_reg_flt(c->source1, d); + M_FLTMOVE(s1,d); + store_reg_to_var_flt(c->dest, d); + } + break; + + + /********************* integer operations *****************************/ + + case CMD_IINC: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + if ((c->u.i.value >= 0) && (c->u.i.value <= 256)) { + M_IADD (s1, c->u.i.value, d, 1); + } + else if ((c->u.i.value >= -256) && (c->u.i.value < 0)) { + M_ISUB (s1, (-c->u.i.value), d, 1); + } + else { + M_LDA (d, s1, c->u.i.value); + M_IADD (d, REG_ZERO, d, 0); + } + store_reg_to_var_int(c->dest, d); + break; + + case CMD_INEG: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_ISUB (REG_ZERO, s1, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LNEG: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_LSUB (REG_ZERO, s1, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_I2L: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_INTMOVE (s1, d); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_L2I: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_IADD (s1, REG_ZERO, d , 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_INT2BYTE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + if (has_ext_instr_set) { + M_BSEXT (s1, d); + } + else { + M_SLL (s1,56, d, 1); + M_SRA ( d,56, d, 1); + } + store_reg_to_var_int(c->dest, d); + break; + + case CMD_INT2CHAR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_ZAPNOT (s1, 0x03, d, 1); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_INT2SHORT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + if (has_ext_instr_set) { + M_SSEXT (s1, d); + } + else { + M_SLL ( s1, 48, d, 1); + M_SRA ( d, 48, d, 1); + } + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IADD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_IADD (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + case CMD_LADD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_LADD (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_ISUB: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_ISUB (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + case CMD_LSUB: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_LSUB (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IMUL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_IMUL (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + case CMD_LMUL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_LMUL (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + + case CMD_ISHL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_AND (s2, 0x1f, REG_ITMP3, 1); + M_SLL (s1, REG_ITMP3, d, 0); + M_IADD (d, REG_ZERO, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_ISHR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_AND (s2, 0x1f, REG_ITMP3, 1); + M_SRA (s1, REG_ITMP3, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IUSHR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_AND (s2, 0x1f, REG_ITMP2, 1); + M_ZAPNOT (s1, 0x0f, d, 1); + M_SRL ( d, REG_ITMP2, d, 0); + M_IADD ( d, REG_ZERO, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LSHL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_SLL (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LSHR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_SRA (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_LUSHR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_SRL (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IAND: + case CMD_LAND: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_AND (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IOR: + case CMD_LOR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_OR ( s1,s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_IXOR: + case CMD_LXOR: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_XOR (s1, s2, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + + case CMD_LCMP: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_CMPLT (s1, s2, REG_ITMP3, 0); + M_CMPLT (s2, s1, REG_ITMP1, 0); + M_LSUB (REG_ITMP1, REG_ITMP3, d, 0); + store_reg_to_var_int(c->dest, d); + break; + + + /*********************** floating operations **************************/ + + case CMD_FNEG: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_FTMP3); + M_FMOVN (s1, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DNEG: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_FTMP3); + M_FMOVN (s1, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FADD: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_FADD ( s1,s2, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DADD: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_DADD (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FSUB: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_FSUB (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DSUB: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_DSUB (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FMUL: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_FMUL (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DMUL: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_DMUL (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FDIV: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_FDIV (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DDIV: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_DDIV (s1, s2, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FREM: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_FDIV ( s1,s2, REG_FTMP3 ); + M_CVTDL_C ( REG_ZERO, REG_FTMP3, REG_FTMP3 ); /* round to integer */ + M_CVTLF ( REG_ZERO, REG_FTMP3, REG_FTMP3 ); + M_FMUL ( REG_FTMP3, s2, REG_FTMP3 ); + M_FSUB ( s1, REG_FTMP3, d); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DREM: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_DDIV ( s1,s2, REG_FTMP3 ); + M_CVTDL_C ( REG_ZERO, REG_FTMP3, REG_FTMP3 ); /* round to integer */ + M_CVTLD ( REG_ZERO, REG_FTMP3, REG_FTMP3 ); + M_DMUL ( REG_FTMP3, s2, REG_FTMP3 ); + M_DSUB ( s1, REG_FTMP3, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_I2F: + case CMD_L2F: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_FTMP3); + a = dseg_adddouble(0.0); + M_LST (s1, REG_PV, a); + M_DLD (d, REG_PV, a); + M_CVTLF ( REG_ZERO, d, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_I2D: + case CMD_L2D: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_FTMP3); + a = dseg_adddouble(0.0); + M_LST (s1, REG_PV, a); + M_DLD (d, REG_PV, a); + M_CVTLD ( REG_ZERO, d, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_F2I: + case CMD_D2I: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_ITMP3); + a = dseg_adddouble(0.0); + M_CVTDL_C (REG_ZERO, s1, REG_FTMP1); + M_DST (REG_FTMP1, REG_PV, a); + M_ILD (d, REG_PV, a); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_F2L: + case CMD_D2L: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_ITMP3); + a = dseg_adddouble(0.0); + M_CVTDL_C (REG_ZERO, s1, REG_FTMP1); + M_DST (REG_FTMP1, REG_PV, a); + M_LLD (d, REG_PV, a); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_F2D: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_FTMP3); + M_FLTMOVE (s1, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_D2F: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + d = reg_of_var(c->dest, REG_FTMP3); + M_FADD (s1, REG_ZERO, d); + store_reg_to_var_flt(c->dest, d); + break; + + case CMD_FCMPL: + case CMD_DCMPL: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_LSUB (REG_ZERO, 1, d, 1); + M_FCMPEQ (s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instructions */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLT (s2, s1, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LADD (REG_ZERO, 1, d, 1); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_FCMPG: + case CMD_DCMPG: + s1 = var_to_reg_flt(c->source1, REG_FTMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_LADD (REG_ZERO, 1, d, 1); + M_FCMPEQ (s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLT (s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LSUB (REG_ZERO, 1, d, 1); + store_reg_to_var_int(c->dest, d); + break; + + + /********************** memory operations *****************************/ + + case CMD_ARRAYLENGTH: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_ILD (d, s1, OFFSET(java_arrayheader, size)); + store_reg_to_var_int(c->dest, d); + break; + + case CMD_AALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_LLD ( d, REG_ITMP1, OFFSET (java_objectarray, data[0])); + store_reg_to_var_int(c->dest, d); + break; + case CMD_LALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_LLD ( d, REG_ITMP1, OFFSET (java_longarray, data[0])); + store_reg_to_var_int(c->dest, d); + break; + case CMD_IALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + M_S4ADDQ (s2, s1, REG_ITMP1, 0); + M_ILD ( d, REG_ITMP1, OFFSET (java_intarray, data[0])); + store_reg_to_var_int(c->dest, d); + break; + case CMD_FALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_S4ADDQ (s2, s1, REG_ITMP1, 0); + M_FLD ( d, REG_ITMP1, OFFSET (java_floatarray, data[0])); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_DALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_FTMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_DLD ( d, REG_ITMP1, OFFSET (java_doublearray, data[0])); + store_reg_to_var_flt(c->dest, d); + break; + case CMD_CALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_SLDU (d, REG_ITMP1, OFFSET (java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_EXTWL (REG_ITMP2, REG_ITMP1, d, 0); + } + store_reg_to_var_int(c->dest, d); + break; + case CMD_SALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_SLDU (d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_SSEXT (d, d); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0]) + 2); + M_EXTQH (REG_ITMP2, REG_ITMP1, d, 0); + M_SRA (d, 48, d, 1); + } + store_reg_to_var_int(c->dest, d); + break; + case CMD_BALOAD: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + d = reg_of_var(c->dest, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_BLDU (d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_BSEXT (d, d); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_bytearray, data[0]) + 1); + M_EXTQH (REG_ITMP2, REG_ITMP1, d, 0); + M_SRA (d, 56, d, 1); + } + store_reg_to_var_int(c->dest, d); + break; + + case CMD_AASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_LST (s3, REG_ITMP1, OFFSET (java_objectarray, data[0])); + break; + case CMD_LASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_LST (s3, REG_ITMP1, OFFSET (java_longarray, data[0])); + break; + case CMD_IASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + M_S4ADDQ (s2, s1, REG_ITMP1, 0); + M_IST (s3, REG_ITMP1, OFFSET (java_intarray, data[0])); + break; + case CMD_FASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_flt(c->source3, REG_FTMP3); + M_S4ADDQ (s2, s1, REG_ITMP1, 0); + M_FST (s3, REG_ITMP1, OFFSET (java_floatarray, data[0])); + break; + case CMD_DASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_flt(c->source3, REG_FTMP3); + M_S8ADDQ (s2, s1, REG_ITMP1, 0); + M_DST (s3, REG_ITMP1, OFFSET (java_doublearray, data[0])); + break; + case CMD_CASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_SST (s3, REG_ITMP1, OFFSET (java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_INSWL (s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKWL (REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U (REG_ITMP2, REG_ITMP1, 0); + } + break; + case CMD_SASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_SST (s3, REG_ITMP1, OFFSET (java_shortarray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_INSWL (s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKWL (REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U (REG_ITMP2, REG_ITMP1, 0); + } + break; + case CMD_BASTORE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + s3 = var_to_reg_int(c->source3, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_BST (s3, REG_ITMP1, OFFSET (java_bytearray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LLD_U (REG_ITMP2, REG_ITMP1, OFFSET (java_bytearray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET (java_bytearray, data[0])); + M_INSBL (s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKBL (REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U (REG_ITMP2, REG_ITMP1, 0); + } + break; + + + case CMD_PUTFIELD: + switch (c->u.mem.type) { + case TYPE_INT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_IST (s2, s1, c->u.mem.offset); + break; + case TYPE_LONG: + case TYPE_ADDRESS: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_LST (s2, s1, c->u.mem.offset); + break; + case TYPE_FLOAT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + M_FST (s2, s1, c->u.mem.offset); + break; + case TYPE_DOUBLE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_flt(c->source2, REG_FTMP2); + M_DST (s2, s1, c->u.mem.offset); + break; + default: panic ("internal error"); + } + break; + + case CMD_GETFIELD: + switch (c->u.mem.type) { + case TYPE_INT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_ILD (d, s1, c->u.mem.offset); + store_reg_to_var_int(c->dest, d); + break; + case TYPE_LONG: + case TYPE_ADDRESS: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_ITMP3); + M_LLD (d, s1, c->u.mem.offset); + store_reg_to_var_int(c->dest, d); + break; + case TYPE_FLOAT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_FTMP1); + M_FLD (d, s1, c->u.mem.offset); + store_reg_to_var_flt(c->dest, d); + break; + case TYPE_DOUBLE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + d = reg_of_var(c->dest, REG_FTMP1); + M_DLD (d, s1, c->u.mem.offset); + store_reg_to_var_flt(c->dest, d); + break; + default: panic ("internal error"); + } + break; + + + /********************** branch operations *****************************/ + + case CMD_GOTO: + mcode_addreference (c->u.bra.target); + M_BR (0); + break; + + case CMD_JSR: { + reginfo *di = c->dest->reg; + + if (di->typeflags & REG_INMEMORY) + panic ("Can not put returnaddress into memory var"); + + mcode_addreference (c->u.bra.target); + M_BSR (di->num, 0); + } + break; + + case CMD_RET: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + M_RET (REG_ZERO, s1); + break; + + case CMD_IFEQ: + case CMD_IFEQL: + case CMD_IFNULL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BEQZ (s1, 0); + break; + case CMD_IFLT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BLTZ (s1, 0); + break; + case CMD_IFLE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BLEZ (s1, 0); + break; + case CMD_IFNE: + case CMD_IFNONNULL: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BNEZ (s1, 0); + break; + case CMD_IFGT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BGTZ (s1, 0); + break; + case CMD_IFGE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + mcode_addreference (c->u.bra.target); + M_BGEZ (s1, 0); + break; + + case CMD_IF_ICMPEQ: + case CMD_IF_ACMPEQ: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPEQ (s1, s2, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BNEZ (REG_ITMP1, 0); + break; + case CMD_IF_ICMPNE: + case CMD_IF_ACMPNE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPEQ (s1, s2, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BEQZ (REG_ITMP1, 0); + break; + case CMD_IF_ICMPLT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPLT (s1, s2, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BNEZ (REG_ITMP1, 0); + break; + case CMD_IF_ICMPGT: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPLE (s1, s2, REG_ITMP1, 0); + mcode_addreference ( c->u.bra.target ); + M_BEQZ (REG_ITMP1, 0); + break; + case CMD_IF_ICMPLE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPLE (s1, s2, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BNEZ (REG_ITMP1, 0); + break; + case CMD_IF_ICMPGE: + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPLT (s1, s2, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BEQZ (REG_ITMP1, 0); + break; + + case CMD_IF_UCMPGE: /* branch if the unsigned value of s1 is + greater that s2 (note, that s2 has + to be >= 0) */ + s1 = var_to_reg_int(c->source1, REG_ITMP1); + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_CMPULE (s2, s1, REG_ITMP1, 0); + mcode_addreference (c->u.bra.target); + M_BNEZ (REG_ITMP1, 0); + break; + + + case CMD_IRETURN: + case CMD_LRETURN: + case CMD_ARETURN: + s1 = var_to_reg_int(c->source1, REG_RESULT); + M_INTMOVE (s1, REG_RESULT); + goto nowperformreturn; + case CMD_FRETURN: + case CMD_DRETURN: + s1 = var_to_reg_flt(c->source1, REG_FRESULT); + M_FLTMOVE (s1, REG_FRESULT); + goto nowperformreturn; + + case CMD_RETURN: +nowperformreturn: + { + int r, p; + + s2 = var_to_reg_int(c->source2, REG_ITMP2); + M_INTMOVE (s2, REG_EXCEPTION); + + p = parentargs_base; + if (!isleafmethod) + {p--; M_LLD (REG_RA, REG_SP, 8*p);} + for (r = INT_SAV_FST; r < INT_SAV_FST + INT_SAV_CNT; r++) + if (!(intregs[r].typeflags & REG_ISUNUSED)) + {p--; M_LLD (r, REG_SP, 8*p);} + for (r = FLT_SAV_FST; r < FLT_SAV_FST + FLT_SAV_CNT; r++) + if (!(floatregs[r].typeflags & REG_ISUNUSED)) + {p--; M_DLD (r, REG_SP, 8*p);} + + if (parentargs_base) + {M_LDA (REG_SP, REG_SP, parentargs_base*8);} + if (runverbose) { + M_LDA (REG_SP, REG_SP, -32); + M_LST(REG_RA, REG_SP, 0); + M_LST(REG_RESULT, REG_SP, 8); + M_DST(REG_FRESULT, REG_SP,16); + M_LST(REG_EXCEPTION, REG_SP, 24); + a = dseg_addaddress (method); + M_LLD(INT_ARG_FST, REG_PV, a); + M_OR(REG_RESULT, REG_RESULT, INT_ARG_FST + 1, 0); + M_FLTMOVE(REG_FRESULT, FLT_ARG_FST + 2); + a = dseg_addaddress ((void*) (builtin_displaymethodstop)); + M_LLD(REG_PV, REG_PV, a); + M_JSR (REG_RA, REG_PV); + if (mcodelen<=32768) M_LDA (REG_PV, REG_RA, -mcodelen); + else { + s4 ml=-mcodelen, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + M_LLD(REG_EXCEPTION, REG_SP, 24); + M_DLD(REG_FRESULT, REG_SP,16); + M_LLD(REG_RESULT, REG_SP, 8); + M_LLD(REG_RA, REG_SP, 0); + M_LDA (REG_SP, REG_SP, 32); + } + M_RET (REG_ZERO, REG_RA); + } + break; + + + case CMD_TABLEJUMP: + { + int i; + + /* build jump table top down and use address of lowest entry */ + + a = 0; + for (i = c->u.tablejump.targetcount - 1; i >= 0; i--) { + a = dseg_addtarget (c->u.tablejump.targets[i]); + } + } + + /* last offset a returned by dseg_addtarget is used by load */ + + s1 = var_to_reg_int(c->source1, REG_ITMP1); + M_S8ADDQ (s1, REG_PV, REG_ITMP2, 0); + M_LLD (REG_ITMP3, REG_ITMP2, a); + M_JMP (REG_ZERO, REG_ITMP3); + break; + + + case CMD_INVOKESTATIC: + case CMD_INVOKESPECIAL: + case CMD_INVOKEVIRTUAL: + case CMD_INVOKEINTERFACE: + case CMD_BUILTIN: + gen_method (c); + break; + + case CMD_DROP: + case CMD_ACTIVATE: + break; + + default: sprintf (logtext, "Unknown pseudo command: %d(%d)", c->opcode, + c->tag); + error(); + } +} + + +/*********************** function input_args_prealloc ************************** + + preallocates the input arguments (on the Alpha only for leaf methods) + +*******************************************************************************/ + + +static void input_args_prealloc() +{ + int i, t; + varid p; + reginfo *r; + + if (isleafmethod) + for (i = 0; (i < mparamnum) && (i < INT_ARG_CNT); i++) { + t = mparamtypes[i]; + p = mparamvars[i]; + p->saved = !isleafmethod; + if (t==TYPE_DOUBLE || t==TYPE_FLOAT) + r = &floatregs[FLT_ARG_FST + i]; + else + r = &intregs[INT_ARG_FST + i]; + r->typeflags &= ~REG_ISFREEUNUSED; + p->reg = r; + } +} + + +/********************* function gen_computestackframe ************************** + + computes the size and the layout of a stack frame. + The values of localvars_base, savedregs_base, parentargs_base + are numbers of 8-byte slots in the stackframe (every spilled or + saved register value will be stored in a 64-bit slot, regardless + of its type: INT/LONG/FLOAT/DOUBLE/ADDRESS) + (a detailed description of the stack frame is contained in 'calling.doc') + + +*******************************************************************************/ + + +static void gen_computestackframe() +{ + int i; + + savedregs_num = (isleafmethod) ? 0 : 1; /* space to save the RA */ + + /* space to save used callee saved registers */ + + for (i = INT_SAV_FST; i < INT_SAV_FST + INT_SAV_CNT; i++) + if (! (intregs[i].typeflags & REG_ISUNUSED)) + savedregs_num++; + for (i = FLT_SAV_FST; i < FLT_SAV_FST + FLT_SAV_CNT; i++) + if (! (floatregs[i].typeflags & REG_ISUNUSED)) + savedregs_num++; + + localvars_base = arguments_num; + savedregs_base = localvars_base + localvars_num; + parentargs_base = savedregs_base + savedregs_num; +} + + +/******************** function gen_header ************************************** + + using the data computed by gen_computestackframe it generates a function + header which: + + - saves the necessary registers + - copies arguments to registers or to stack slots + +*******************************************************************************/ + + +static void gen_header () +{ + int p, pa, r; + reginfo *ri; + + + /* create stack frame (if necessary) */ + + if (parentargs_base) + {M_LDA (REG_SP, REG_SP, -parentargs_base * 8);} + + /* save return address and used callee saved registers */ + + p = parentargs_base; + if (!isleafmethod) + {p--; M_LST (REG_RA, REG_SP, 8*p);} + for (r = INT_SAV_FST; r < INT_SAV_FST + INT_SAV_CNT; r++) + if (!(intregs[r].typeflags & REG_ISUNUSED)) + {p--; M_LST (r, REG_SP, 8 * p);} + for (r = FLT_SAV_FST; r < FLT_SAV_FST + FLT_SAV_CNT; r++) + if (!(floatregs[r].typeflags & REG_ISUNUSED)) + {p--; M_DST (r, REG_SP, 8 * p);} + + /* take arguments out of register or stack frame */ + + for (p = 0; p < mparamnum; p++) { + ri = mparamvars[p]->reg; + + if (p < INT_ARG_CNT) { /* register arguments */ + if (IS_INT_LNG_REG(ri->typeflags)) { /* integer args */ + if (!(ri->typeflags & REG_INMEMORY)) /* reg arg -> register */ + M_INTMOVE (16+p, ri->num); + else /* reg arg -> spilled */ + M_LST (16+p, REG_SP, 8 * (localvars_base + ri->num)); + } + else { /* floating args */ + if (!(ri->typeflags & REG_INMEMORY)) /* reg-arg -> register */ + M_FLTMOVE (16+p, ri->num); + else /* reg-arg -> spilled */ + M_DST (16+p, REG_SP, 8 * (localvars_base + ri->num)); + } + } + + else { /* stack arguments */ + pa = p - INT_ARG_CNT; + if (IS_INT_LNG_REG(ri->typeflags)) { /* integer args */ + if (!(ri->typeflags & REG_INMEMORY)) /* stack arg -> register */ + M_LLD (ri->num, REG_SP, 8 * (parentargs_base + pa)); + else { /* stack arg -> spilled */ + M_LLD (REG_ITMP1, REG_SP, 8 * (parentargs_base + pa)); + M_LST (REG_ITMP1, REG_SP, 8 * (localvars_base + ri->num)); + } + } + else { + if (!(ri->typeflags & REG_INMEMORY)) /* stack-arg -> register */ + M_DLD (ri->num, REG_SP, 8 * (parentargs_base + pa) ); + else { /* stack-arg -> spilled */ + M_DLD (REG_FTMP1, REG_SP, 8 * (parentargs_base + pa)); + M_DST (REG_FTMP1, REG_SP, 8 * (localvars_base + ri->num)); + } + } + } + } /* end for */ +} /* end gen_header */ + + +/************************ function gen_resolvebranch *************************** + + backpatches a branch instruction; Alpha branch instructions are very + regular, so it is only necessary to overwrite some fixed bits in the + instruction. + + parameters: mcodepiece .. start of code area + sourcepos ... offset of branch instruction + targetpos ... offset of branch target + +*******************************************************************************/ + + +static void gen_resolvebranch ( void* mcodepiece, s4 sourcepos, s4 targetpos) +{ + s4 *command = mcodepiece; + s4 offset = targetpos - (sourcepos+4); + + (*command) |= ((offset >> 2) & ((s4) 0x1fffff) ); +} + + + +/******** redefinition of code generation makros (compilinf into array) *******/ + +/* +These macros are newly defined to allow code generation into an array. +This is necessary, because the original M_.. macros generate code by +calling 'mcode_adds4' that uses an additional data structure to +receive the code. + +For a faster (but less flexible) version to generate code, these +macros directly use the (s4* p) - pointer to put the code directly +in a locally defined array. +This makes sense only for the stub-generation-routines below. +*/ + +#undef M_OP3 +#define M_OP3(op,fu,a,b,c,const) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \ + ((const)<<12)|((fu)<<5)|((c)) ) +#undef M_FOP3 +#define M_FOP3(op,fu,a,b,c) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) ) +#undef M_BRA +#define M_BRA(op,a,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) ) +#undef M_MEM +#define M_MEM(op,a,b,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) ) + + +/************************ function createcompilerstub ************************** + + creates a stub routine which calls the compiler + +*******************************************************************************/ + +#define COMPSTUBSIZE 3 + +u1 *createcompilerstub (methodinfo *m) +{ + u8 *s = CNEW (u8, COMPSTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + /* code for the stub */ + M_LLD (REG_PV, REG_PV, 16); /* load pointer to the compiler */ + M_JMP (0, REG_PV); /* jump to the compiler, return address + in reg 0 is used as method pointer */ + s[1] = (u8) m; /* literals to be adressed */ + s[2] = (u8) asm_call_jit_compiler; /* jump directly via PV from above */ + +#ifdef STATISTICS + count_cstub_len += COMPSTUBSIZE * 8; +#endif + + return (u1*) s; +} + + +/************************* function removecompilerstub ************************* + + deletes a compilerstub from memory (simply by freeing it) + +*******************************************************************************/ + +void removecompilerstub (u1 *stub) +{ + CFREE (stub, COMPSTUBSIZE * 8); +} + + +/********************* Funktion: createnativestub ****************************** + + creates a stub routine which calls a native method + +*******************************************************************************/ + +#define NATIVESTUBSIZE 11 + +u1 *createnativestub (functionptr f, methodinfo *m) +{ + u8 *s = CNEW (u8, NATIVESTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + M_LDA (REG_SP, REG_SP, -8); /* build up stackframe */ + M_LST (REG_RA, REG_SP, 0); /* store return address */ + + M_LLD (REG_PV, REG_PV, 6*8); /* load adress of native method */ + M_JSR (REG_RA, REG_PV); /* call native method */ + M_LDA (REG_PV, REG_RA, -4*4); /* recompute pv from ra */ + + M_LLD (22, REG_PV, 7*8); /* get address of exceptionptr */ + M_LLD (REG_EXCEPTION, 22, 0); /* load exception into reg. 1 */ + M_LST (REG_ZERO, 22, 0); /* store NULL into exceptionptr */ + + M_LLD (REG_RA, REG_SP, 0); /* load return address */ + M_LDA (REG_SP, REG_SP, 8); /* remove stackframe */ + + M_RET (REG_ZERO, REG_RA); /* return to caller */ + + s[6] = (u8) f; /* address of native method */ + s[7] = (u8) (&exceptionptr); /* address of exceptionptr */ + +#ifdef STATISTICS + count_nstub_len += NATIVESTUBSIZE * 8; +#endif + + return (u1*) s; +} + + +/************************ function: removenativestub *************************** + + removes a previously created native-stub from memory + +*******************************************************************************/ + +void removenativestub (u1 *stub) +{ + CFREE (stub, NATIVESTUBSIZE * 8); +} + diff --git a/alpha/native-math.h b/alpha/native-math.h new file mode 100644 index 000000000..4e87509b0 --- /dev/null +++ b/alpha/native-math.h @@ -0,0 +1,38 @@ +/************************* alpha/native-math.h ********************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the machine-specific floating point definitions. + + Authors: Michael Gschwind EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/21 + +*******************************************************************************/ + +/* include machine-specific math.h */ + +#include + +/* define infinity for floating point numbers */ + +u4 flt_nan = 0xffffffff; +u4 flt_posinf = 0x7f800000; +u4 flt_neginf = 0xff800000; + +#define FLT_NAN (*((float*) (&flt_nan))) +#define FLT_POSINF (*((float*) (&flt_posinf))) +#define FLT_NEGINF (*((float*) (&flt_neginf))) + +/* define infinity for double floating point numbers */ + +u8 dbl_nan = 0xffffffffffffffffL ; +u8 dbl_posinf = 0x7ff0000000000000L ; +u8 dbl_neginf = 0xfff0000000000000L ; + +#define DBL_NAN (*((double*) (&dbl_nan))) +#define DBL_POSINF (*((double*) (&dbl_posinf))) +#define DBL_NEGINF (*((double*) (&dbl_neginf))) diff --git a/alpha/ngen.c b/alpha/ngen.c new file mode 100644 index 000000000..7fd8cd9ba --- /dev/null +++ b/alpha/ngen.c @@ -0,0 +1,2725 @@ +/***************************** alpha/ngen.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the codegenerator for an Alpha processor. + This module generates Alpha machine code for a sequence of + pseudo commands (ICMDs). + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/08/10 + +*******************************************************************************/ + + + +/******************************************************************************* + +Datatypes and Register Allocations: +----------------------------------- + +On 64-bit-machines (like the Alpha) all operands are stored in the +registers in a 64-bit form, even when the correspondig JavaVM +operands only need 32 bits. +This is done by a canonical representation: + +32-bit integers are allways stored as sign-extended 64-bit values +(this approach is directly supported by the Alpha architecture and +is very easy to implement). + +32-bit-floats are stored in a 64-bit doubleprecision register by +simply expanding the exponent and mantissa with zeroes. +(also supported by the architecture) + + +Stackframes: + +The calling conventions and the layout of the stack is +explained in detail in the documention file: calling.doc + +*******************************************************************************/ + + +/*********** additional functions and macros to generate code *****************/ + +#define BlockPtrOfPC(pc) block+block_index[pc] + +#ifdef STATISTICS +#define COUNT_SPILLS count_spills++ +#else +#define COUNT_SPILLS +#endif + + +/* gen_nullptr_check(objreg) */ + +#ifdef SOFTNULLPTRCHECK +#define gen_nullptr_check(objreg) \ + if (checknull) {\ + M_BEQZ((objreg), 0);\ + mcode_addxnullrefs(mcodeptr);\ + } +#else +#define gen_nullptr_check(objreg) +#endif + + +/* MCODECHECK(icnt) */ + +#define MCODECHECK(icnt) \ + if((mcodeptr+(icnt))>mcodeend)mcodeptr=mcode_increase((u1*)mcodeptr) + +/* M_INTMOVE: + generates an integer-move from register a to b. + if a and b are the same int-register, no code will be generated. +*/ + +#define M_INTMOVE(a,b) if(a!=b){M_OR(a,a,b,0);} + + +/* M_FLTMOVE: + generates a floating-point-move from register a to b. + if a and b are the same float-register, no code will be generated +*/ + +#define M_FLTMOVE(a,b) if(a!=b){M_FMOV(a,b);} + + +/* var_to_reg_xxx: + this function generates code to fetch data from a pseudo-register + into a real register. + If the pseudo-register has actually been assigned to a real + register, no code will be emitted, since following operations + can use this register directly. + + v: pseudoregister to be fetched from + tempregnum: temporary register to be used if v is actually spilled to ram + + return: the register number, where the operand can be found after + fetching (this wil be either tempregnum or the register + number allready given to v) +*/ + +#define var_to_reg_int(regnr,v,tempnr) { \ + if ((v)->flags & INMEMORY) \ + {COUNT_SPILLS;M_LLD(tempnr,REG_SP,8*(v)->regoff);regnr=tempnr;} \ + else regnr=(v)->regoff; \ +} + + +#define var_to_reg_flt(regnr,v,tempnr) { \ + if ((v)->flags & INMEMORY) \ + {COUNT_SPILLS;M_DLD(tempnr,REG_SP,8*(v)->regoff);regnr=tempnr;} \ + else regnr=(v)->regoff; \ +} + + +/* reg_of_var: + This function determines a register, to which the result of an + operation should go, when it is ultimatively intended to store the result + in pseudoregister v. + If v is assigned to an actual register, this register will be + returned. + Otherwise (when v is spilled) this function returns tempregnum. + If not already done, regoff and flags are set in the stack location. +*/ + +static int reg_of_var(stackptr v, int tempregnum) +{ + varinfo *var; + + switch (v->varkind) { + case TEMPVAR: + if (!(v->flags & INMEMORY)) + return(v->regoff); + break; + case STACKVAR: + var = &(interfaces[v->varnum][v->type]); + v->regoff = var->regoff; + if (!(var->flags & INMEMORY)) + return(var->regoff); + break; + case LOCALVAR: + var = &(locals[v->varnum][v->type]); + v->regoff = var->regoff; + if (!(var->flags & INMEMORY)) + return(var->regoff); + break; + case ARGVAR: + v->regoff = v->varnum; + if (IS_FLT_DBL_TYPE(v->type)) { + if (v->varnum < fltreg_argnum) { + v->regoff = argfltregs[v->varnum]; + return(argfltregs[v->varnum]); + } + } + else + if (v->varnum < intreg_argnum) { + v->regoff = argintregs[v->varnum]; + return(argintregs[v->varnum]); + } + v->regoff -= intreg_argnum; + break; + } + v->flags |= INMEMORY; + return tempregnum; +} + + +/* store_reg_to_var_xxx: + This function generates the code to store the result of an operation + back into a spilled pseudo-variable. + If the pseudo-variable has not been spilled in the first place, this + function will generate nothing. + + v ............ Pseudovariable + tempregnum ... Number of the temporary registers as returned by + reg_of_var. +*/ + +#define store_reg_to_var_int(sptr, tempregnum) { \ + if ((sptr)->flags & INMEMORY) { \ + COUNT_SPILLS; \ + M_LST(tempregnum, REG_SP, 8 * (sptr)->regoff); \ + } \ + } + +#define store_reg_to_var_flt(sptr, tempregnum) { \ + if ((sptr)->flags & INMEMORY) { \ + COUNT_SPILLS; \ + M_DST(tempregnum, REG_SP, 8 * (sptr)->regoff); \ + } \ + } + + +void asm_signal_exception(void *xptr, void *sigctx); + +void catch_NullPointerException(int sig, int code, void *sigctx) +{ + sigset_t nsig; + + /* Reset signal handler - necessary for SysV, does no harm for BSD */ + + signal(sig, (void*) catch_NullPointerException); + sigemptyset(&nsig); + sigaddset(&nsig, sig); + sigprocmask(SIG_UNBLOCK, &nsig, 0); + asm_signal_exception(proto_java_lang_NullPointerException, sigctx); +} + +#ifdef __osf__ + +void init_exceptions(void) +{ + +#else + +#include + +extern unsigned long ieee_get_fp_control(); +extern void ieee_set_fp_control(unsigned long fp_control); + +void init_exceptions(void) +{ +/* initialise floating point control */ +ieee_set_fp_control(ieee_get_fp_control() + & ~IEEE_TRAP_ENABLE_INV + & ~IEEE_TRAP_ENABLE_DZE +/* & ~IEEE_TRAP_ENABLE_UNF */ + & ~IEEE_TRAP_ENABLE_OVF); +#endif + + /* Catch signal we need to convert to exceptions */ + if (!checknull) { +#if defined(SIGSEGV) + signal(SIGSEGV, (void*) catch_NullPointerException); +#endif +#if defined(SIGBUS) + signal(SIGBUS, (void*) catch_NullPointerException); +#endif + } +} + +/*************************** function gen_mcode ******************************** + + generates machine code + +*******************************************************************************/ + +#define MethodPointer -8 +#define FrameSize -12 +#define IsSync -16 +#define IsLeaf -20 +#define IntSave -24 +#define FltSave -28 +#define ExTableSize -32 +#define ExTableStart -32 + +#define ExEntrySize -32 +#define ExStartPC -8 +#define ExEndPC -16 +#define ExHandlerPC -24 +#define ExCatchType -32 + +static void gen_mcode() +{ + int len, s1, s2, s3, d, bbs; + s4 a; + s4 *mcodeptr; + stackptr src; + varinfo *var; + basicblock *bptr; + instruction *iptr; + + { + int p, pa, t, l, r; + + savedregs_num = (isleafmethod) ? 0 : 1; /* space to save the RA */ + + /* space to save used callee saved registers */ + + savedregs_num += (savintregcnt - maxsavintreguse); + savedregs_num += (savfltregcnt - maxsavfltreguse); + + parentargs_base = maxmemuse + savedregs_num; + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) + parentargs_base++; +#endif + + /* create method header */ + + (void) dseg_addaddress(method); /* MethodPointer */ + (void) dseg_adds4(parentargs_base * 8); /* FrameSize */ + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) + (void) dseg_adds4((maxmemuse + 1) * 8); /* IsSync */ + else +#endif + (void) dseg_adds4(0); /* IsSync */ + + (void) dseg_adds4(isleafmethod); /* IsLeaf */ + (void) dseg_adds4(savintregcnt - maxsavintreguse); /* IntSave */ + (void) dseg_adds4(savfltregcnt - maxsavfltreguse); /* FltSave */ + (void) dseg_adds4(exceptiontablelength); /* ExTableSize */ + + for (len = 0; len < exceptiontablelength; len++) { + dseg_addtarget(BlockPtrOfPC(extable[len].startpc)); + dseg_addtarget(BlockPtrOfPC(extable[len].endpc)); + dseg_addtarget(BlockPtrOfPC(extable[len].handlerpc)); + (void) dseg_addaddress(extable[len].catchtype); + } + + /* initialise mcode variables */ + + mcodeptr = (s4*) mcodebase; + mcodeend = (s4*) (mcodebase + mcodesize); + MCODECHECK(128); + + /* create stack frame (if necessary) */ + + if (parentargs_base) + {M_LDA (REG_SP, REG_SP, -parentargs_base * 8);} + + /* save return address and used callee saved registers */ + + p = parentargs_base; + if (!isleafmethod) + {p--; M_LST (REG_RA, REG_SP, 8*p);} + for (r = savintregcnt - 1; r >= maxsavintreguse; r--) + {p--; M_LST (savintregs[r], REG_SP, 8 * p);} + for (r = savfltregcnt - 1; r >= maxsavfltreguse; r--) + {p--; M_DST (savfltregs[r], REG_SP, 8 * p);} + + /* save monitorenter argument */ + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + if (method->flags & ACC_STATIC) { + p = dseg_addaddress (class); + M_LLD(REG_ITMP1, REG_PV, p); + M_LST(REG_ITMP1, REG_SP, 8 * maxmemuse); + } + else { + M_LST (argintregs[0], REG_SP, 8 * maxmemuse); + } + } +#endif + + if (runverbose && isleafmethod) { + M_LDA (REG_SP, REG_SP, -(8*8)); + M_LST(REG_RA, REG_SP, 1*8); + M_LST(argintregs[0], REG_SP, 2*8); + M_LST(argintregs[1], REG_SP, 3*8); + M_LST(argintregs[2], REG_SP, 4*8); + M_LST(argintregs[3], REG_SP, 5*8); + M_LST(argintregs[4], REG_SP, 6*8); + M_LST(argintregs[5], REG_SP, 7*8); + p = dseg_addaddress (method); + M_LLD(REG_ITMP1, REG_PV, p); + M_LST(REG_ITMP1, REG_SP, 0); + p = dseg_addaddress ((void*) (builtin_trace_args)); + M_LLD(REG_PV, REG_PV, p); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + M_LLD(REG_RA, REG_SP, 1*8); + M_LLD(argintregs[0], REG_SP, 2*8); + M_LLD(argintregs[1], REG_SP, 3*8); + M_LLD(argintregs[2], REG_SP, 4*8); + M_LLD(argintregs[3], REG_SP, 5*8); + M_LLD(argintregs[4], REG_SP, 6*8); + M_LLD(argintregs[5], REG_SP, 7*8); + M_LDA (REG_SP, REG_SP, 8*8); + } + + /* take arguments out of register or stack frame */ + + for (p = 0, l = 0; p < mparamcount; p++) { + t = mparamtypes[p]; + var = &(locals[l][t]); + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; + if (var->type < 0) + continue; + r = var->regoff; + if (IS_INT_LNG_TYPE(t)) { /* integer args */ + if (p < INT_ARG_CNT) { /* register arguments */ + if (!(var->flags & INMEMORY)) /* reg arg -> register */ + {M_INTMOVE (argintregs[p], r);} + else /* reg arg -> spilled */ + M_LST (argintregs[p], REG_SP, 8 * r); + } + else { /* stack arguments */ + pa = p - INT_ARG_CNT; + if (!(var->flags & INMEMORY)) /* stack arg -> register */ + M_LLD (r, REG_SP, 8 * (parentargs_base + pa)); + else { /* stack arg -> spilled */ + M_LLD (REG_ITMP1, REG_SP, 8 * (parentargs_base + pa)); + M_LST (REG_ITMP1, REG_SP, 8 * r); + } + } + } + else { /* floating args */ + if (p < FLT_ARG_CNT) { /* register arguments */ + if (!(var->flags & INMEMORY)) /* reg arg -> register */ + {M_FLTMOVE (argfltregs[p], r);} + else /* reg arg -> spilled */ + M_DST (argfltregs[p], REG_SP, 8 * r); + } + else { /* stack arguments */ + pa = p - FLT_ARG_CNT; + if (!(var->flags & INMEMORY)) /* stack-arg -> register */ + M_DLD (r, REG_SP, 8 * (parentargs_base + pa) ); + else { /* stack-arg -> spilled */ + M_DLD (REG_FTMP1, REG_SP, 8 * (parentargs_base + pa)); + M_DST (REG_FTMP1, REG_SP, 8 * r); + } + } + } + } /* end for */ + + if (runverbose && !isleafmethod) { + M_LDA (REG_SP, REG_SP, -8); + p = dseg_addaddress (method); + M_LLD(REG_ITMP1, REG_PV, p); + M_LST(REG_ITMP1, REG_SP, 0); + p = dseg_addaddress ((void*) (builtin_trace_args)); + M_LLD(REG_PV, REG_PV, p); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + M_LDA(REG_SP, REG_SP, 8); + } + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + p = dseg_addaddress ((void*) (builtin_monitorenter)); + M_LLD(REG_PV, REG_PV, p); + M_LLD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + } + + /* end of header generation */ + + for (bbs = block_count, bptr = block; --bbs >= 0; bptr++) { + bptr -> mpc = (int)((u1*) mcodeptr - mcodebase); + + /* branch resolving */ + + { + branchref *brefs; + for (brefs = bptr->branchrefs; brefs != NULL; brefs = brefs->next) { + gen_resolvebranch((u1*) mcodebase + brefs->branchpos, + brefs->branchpos, bptr->mpc); + } + } + src = bptr->instack; + len = bptr->indepth; + MCODECHECK(64+len); + while (src != NULL) { + len--; + if ((len == 0) && (bptr->type != BBTYPE_STD)) { + d = reg_of_var(src, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + store_reg_to_var_int(src, d); + } + else { + d = reg_of_var(src, REG_IFTMP); + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + if (!(interfaces[len][s2].flags & INMEMORY)) { + s1 = interfaces[len][s2].regoff; + M_FLTMOVE(s1,d); + } + else { + M_DLD(d, REG_SP, 8 * interfaces[len][s2].regoff); + } + store_reg_to_var_flt(src, d); + } + else { + if (!(interfaces[len][s2].flags & INMEMORY)) { + s1 = interfaces[len][s2].regoff; + M_INTMOVE(s1,d); + } + else { + M_LLD(d, REG_SP, 8 * interfaces[len][s2].regoff); + } + store_reg_to_var_int(src, d); + } + } + } + src = src->prev; + } + s1 = bptr[0].ipc; + src = bptr->instack; + len = bptr[1].ipc - s1; + for (iptr = &instr[s1]; + len > 0; + src = iptr->dst, len--, iptr++) { + + MCODECHECK(64); + switch (iptr->opc) { + + case ICMD_NOP: + break; + + case ICMD_NULLCHECKPOP: + var_to_reg_int(s1, src, REG_ITMP1); + gen_nullptr_check(s1); + break; + + /*********************** constant operations **************************/ + + case ICMD_ICONST: + d = reg_of_var(iptr->dst, REG_ITMP1); + if ( (iptr->val.i >= -32768) && (iptr->val.i <= 32767) ) { + M_LDA(d, REG_ZERO, iptr->val.i); + } + else { + a = dseg_adds4 (iptr->val.i); + M_ILD(d, REG_PV, a); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LCONST: + d = reg_of_var(iptr->dst, REG_ITMP1); + if ((iptr->val.l >= -32768) && (iptr->val.l <= 32767) ) { + M_LDA(d, REG_ZERO, iptr->val.l); + } + else { + a = dseg_adds8 (iptr->val.l); + M_LLD(d, REG_PV, a); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FCONST: + d = reg_of_var (iptr->dst, REG_FTMP1); + a = dseg_addfloat (iptr->val.f); + M_FLD(d, REG_PV, a); + store_reg_to_var_flt (iptr->dst, d); + break; + + case ICMD_DCONST: + d = reg_of_var (iptr->dst, REG_FTMP1); + a = dseg_adddouble (iptr->val.d); + M_DLD(d, REG_PV, a); + store_reg_to_var_flt (iptr->dst, d); + break; + + + case ICMD_ACONST: + d = reg_of_var(iptr->dst, REG_ITMP1); + if (iptr->val.a) { + a = dseg_addaddress (iptr->val.a); + M_LLD(d, REG_PV, a); + } + else { + M_INTMOVE(REG_ZERO, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + /********************** load/store operations *************************/ + + case ICMD_ILOAD: + case ICMD_LLOAD: + case ICMD_ALOAD: + d = reg_of_var(iptr->dst, REG_ITMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_LLD(d, REG_SP, 8 * var->regoff); + else + {M_INTMOVE(var->regoff,d);} + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FLOAD: + case ICMD_DLOAD: + d = reg_of_var(iptr->dst, REG_FTMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_DLD(d, REG_SP, 8 * var->regoff); + else + {M_FLTMOVE(var->regoff,d);} + store_reg_to_var_flt(iptr->dst, d); + break; + + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_ASTORE: + if ((src->varkind == LOCALVAR) && + (src->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + var_to_reg_int(s1, src, REG_ITMP1); + M_LST(s1, REG_SP, 8 * var->regoff); + } + else { + var_to_reg_int(s1, src, var->regoff); + M_INTMOVE(s1, var->regoff); + } + break; + + case ICMD_FSTORE: + case ICMD_DSTORE: + if ((src->varkind == LOCALVAR) && + (src->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + var_to_reg_flt(s1, src, REG_FTMP1); + M_DST(s1, REG_SP, 8 * var->regoff); + } + else { + var_to_reg_flt(s1, src, var->regoff); + M_FLTMOVE(s1, var->regoff); + } + break; + + + /******************* pop/dup/swap operations **************************/ + + case ICMD_POP: + case ICMD_POP2: + break; + +#define M_COPY(from,to) \ + d = reg_of_var(to, REG_IFTMP); \ + if ((from->regoff != to->regoff) || \ + ((from->flags ^ to->flags) & INMEMORY)) { \ + if (IS_FLT_DBL_TYPE(from->type)) { \ + var_to_reg_flt(s1, from, d); \ + M_FLTMOVE(s1,d); \ + store_reg_to_var_flt(to, d); \ + }\ + else { \ + var_to_reg_int(s1, from, d); \ + M_INTMOVE(s1,d); \ + store_reg_to_var_int(to, d); \ + }\ + } + + case ICMD_DUP: + M_COPY(src, iptr->dst); + break; + + case ICMD_DUP_X1: + M_COPY(src, iptr->dst->prev->prev); + case ICMD_DUP2: + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + break; + + case ICMD_DUP2_X1: + M_COPY(src->prev, iptr->dst->prev->prev->prev); + case ICMD_DUP_X2: + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(src, iptr->dst->prev->prev->prev); + break; + + case ICMD_DUP2_X2: + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(src->prev->prev->prev, iptr->dst->prev->prev->prev); + M_COPY(src, iptr->dst->prev->prev->prev->prev); + M_COPY(src->prev, iptr->dst->prev->prev->prev->prev->prev); + break; + + case ICMD_SWAP: + M_COPY(src, iptr->dst->prev); + M_COPY(src->prev, iptr->dst); + break; + + + /********************* integer operations *****************************/ + + case ICMD_INEG: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ISUB(REG_ZERO, s1, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LNEG: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LSUB(REG_ZERO, s1, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_I2L: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_INTMOVE(s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_L2I: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IADD(s1, REG_ZERO, d , 0); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2BYTE: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (has_ext_instr_set) { + M_BSEXT(s1, d); + } + else { + M_SLL(s1,56, d, 1); + M_SRA( d,56, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2CHAR: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ZAPNOT(s1, 0x03, d, 1); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2SHORT: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (has_ext_instr_set) { + M_SSEXT(s1, d); + } + else { + M_SLL( s1, 48, d, 1); + M_SRA( d, 48, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + +#define ICONST(r,c) if(((c)>=-32768)&&((c)<= 32767)){M_LDA(r,REG_ZERO,c);} \ + else{a=dseg_adds4(c);M_ILD(r,REG_PV,a);} + +#define LCONST(r,c) if(((c)>=-32768)&&((c)<= 32767)){M_LDA(r,REG_ZERO,c);} \ + else{a=dseg_adds8(c);M_LLD(r,REG_PV,a);} + + + case ICMD_IADD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IADD(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IADDCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IADD(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_IADD(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LADD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LADD(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LADDCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LADD(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LADD(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISUB: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ISUB(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_ISUBCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_ISUB(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_ISUB(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LSUB: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LSUB(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LSUBCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LSUB(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LSUB(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IMUL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IMUL(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IMULCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IMUL(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_IMUL(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LMUL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LMUL (s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LMULCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LMUL(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LMUL(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_ISHL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND(s2, 0x1f, REG_ITMP3, 1); + M_SLL(s1, REG_ITMP3, d, 0); + M_IADD(d, REG_ZERO, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_ISHLCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL(s1, iptr->val.i & 0x1f, d, 1); + M_IADD(d, REG_ZERO, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISHR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND(s2, 0x1f, REG_ITMP3, 1); + M_SRA(s1, REG_ITMP3, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_ISHRCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA(s1, iptr->val.i & 0x1f, d, 1); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IUSHR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND (s2, 0x1f, REG_ITMP2, 1); + M_ZAPNOT(s1, 0x0f, d, 1); + M_SRL ( d, REG_ITMP2, d, 0); + M_IADD ( d, REG_ZERO, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IUSHRCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ZAPNOT(s1, 0x0f, d, 1); + M_SRL(d, iptr->val.i & 0x1f, d, 1); + M_IADD(d, REG_ZERO, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LSHLCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL(s1, iptr->val.l & 0x3f, d, 1); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LSHRCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA(s1, iptr->val.l & 0x3f, d, 1); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LUSHR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRL(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LUSHRCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRL(s1, iptr->val.l & 0x3f, d, 1); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IAND: + case ICMD_LAND: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IANDCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_AND(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_AND(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LANDCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_AND(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_AND(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IOR: + case ICMD_LOR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_OR( s1,s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IORCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_OR(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_OR(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LORCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_OR(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_OR(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IXOR: + case ICMD_LXOR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_XOR(s1, s2, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IXORCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_XOR(s1, iptr->val.i, d, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_XOR(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LXORCONST: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_XOR(s1, iptr->val.l, d, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_XOR(s1, REG_ITMP2, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_LCMP: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CMPLT(s1, s2, REG_ITMP3, 0); + M_CMPLT(s2, s1, REG_ITMP1, 0); + M_LSUB (REG_ITMP1, REG_ITMP3, d, 0); + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_IINC: + var = &(locals[iptr->op1][TYPE_INT]); + if (var->flags & INMEMORY) { + s1 = REG_ITMP1; + M_LLD(s1, REG_SP, 8 * var->regoff); + } + else + s1 = var->regoff; + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IADD(s1, iptr->val.i, s1, 1); + } + else if ((iptr->val.i > -256) && (iptr->val.i < 0)) { + M_ISUB(s1, (-iptr->val.i), s1, 1); + } + else { + M_LDA (s1, s1, iptr->val.i); + M_IADD(s1, REG_ZERO, s1, 0); + } + if (var->flags & INMEMORY) + M_LST(s1, REG_SP, 8 * var->regoff); + break; + + + /*********************** floating operations **************************/ + + case ICMD_FNEG: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FMOVN(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DNEG: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FMOVN(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FADD: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_FADDS(s1, s2, d); + M_TRAPB; + } + else { + M_FADD(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DADD: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_DADDS(s1, s2, d); + M_TRAPB; + } + else { + M_DADD(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FSUB: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_FSUBS(s1, s2, d); + M_TRAPB; + } + else { + M_FSUB(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DSUB: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_DSUBS(s1, s2, d); + M_TRAPB; + } + else { + M_DSUB(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FMUL: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_FMULS(s1, s2, d); + M_TRAPB; + } + else { + M_FMUL(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DMUL: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_DMULS(s1, s2, d); + M_TRAPB; + } + else { + M_DMUL(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FDIV: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_FDIVS(s1, s2, d); + M_TRAPB; + } + else { + M_FDIV(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DDIV: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_DDIVS(s1, s2, d); + M_TRAPB; + } + else { + M_DDIV(s1, s2, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FREM: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_FDIVS(s1,s2, REG_FTMP3); + M_TRAPB; + M_CVTDL_CS(REG_ZERO, REG_FTMP3, REG_FTMP3); /* round to integer */ + M_TRAPB; + M_CVTLF(REG_ZERO, REG_FTMP3, REG_FTMP3); + M_FMULS(REG_FTMP3, s2, REG_FTMP3); + M_TRAPB; + M_FSUBS(s1, REG_FTMP3, d); + M_TRAPB; + } + else { + M_FDIV(s1,s2, REG_FTMP3); + M_CVTDL_C(REG_ZERO, REG_FTMP3, REG_FTMP3); /* round to integer */ + M_CVTLF(REG_ZERO, REG_FTMP3, REG_FTMP3); + M_FMUL(REG_FTMP3, s2, REG_FTMP3); + M_FSUB(s1, REG_FTMP3, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DREM: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_DDIVS(s1,s2, REG_FTMP3); + M_TRAPB; + M_CVTDL_CS(REG_ZERO, REG_FTMP3, REG_FTMP3); /* round to integer */ + M_TRAPB; + M_CVTLD(REG_ZERO, REG_FTMP3, REG_FTMP3); + M_DMULS(REG_FTMP3, s2, REG_FTMP3); + M_TRAPB; + M_DSUBS(s1, REG_FTMP3, d); + M_TRAPB; + } + else { + M_DDIV(s1,s2, REG_FTMP3); + M_CVTDL_C(REG_ZERO, REG_FTMP3, REG_FTMP3); /* round to integer */ + M_CVTLD(REG_ZERO, REG_FTMP3, REG_FTMP3); + M_DMUL(REG_FTMP3, s2, REG_FTMP3); + M_DSUB(s1, REG_FTMP3, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_I2F: + case ICMD_L2F: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + a = dseg_adddouble(0.0); + M_LST (s1, REG_PV, a); + M_DLD (d, REG_PV, a); + M_CVTLF(REG_ZERO, d, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_I2D: + case ICMD_L2D: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + a = dseg_adddouble(0.0); + M_LST (s1, REG_PV, a); + M_DLD (d, REG_PV, a); + M_CVTLD(REG_ZERO, d, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_F2I: + case ICMD_D2I: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = dseg_adddouble(0.0); + if (checkfloats) { + M_CVTDL_CS(REG_ZERO, s1, REG_FTMP1); + M_TRAPB; + M_CVTLIS(REG_FTMP1, REG_FTMP2); + M_TRAPB; + } + else { + M_CVTDL_C(REG_ZERO, s1, REG_FTMP1); + M_CVTLI(REG_FTMP1, REG_FTMP2); + } + M_DST (REG_FTMP1, REG_PV, a); + M_ILD (d, REG_PV, a); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_F2L: + case ICMD_D2L: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = dseg_adddouble(0.0); + if (checkfloats) { + M_CVTDL_CS(REG_ZERO, s1, REG_FTMP1); + M_TRAPB; + } + else { + M_CVTDL_C(REG_ZERO, s1, REG_FTMP1); + } + M_DST (REG_FTMP1, REG_PV, a); + M_LLD (d, REG_PV, a); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_F2D: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FLTMOVE(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_D2F: + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + if (checkfloats) { + M_CVTDFS(REG_ZERO, s1, d); + M_TRAPB; + } + else { + M_CVTDF(REG_ZERO, s1, d); + } + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FCMPL: + case ICMD_DCMPL: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (checkfloats) { + M_LSUB (REG_ZERO, 1, d, 1); + M_FCMPEQS(s1, s2, REG_FTMP3); + M_TRAPB; + M_FBEQZ (REG_FTMP3, 1); /* jump over next instructions */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLTS(s2, s1, REG_FTMP3); + M_TRAPB; + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LADD (REG_ZERO, 1, d, 1); + } + else { + M_LSUB (REG_ZERO, 1, d, 1); + M_FCMPEQ(s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instructions */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLT(s2, s1, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LADD (REG_ZERO, 1, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FCMPG: + case ICMD_DCMPG: + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (checkfloats) { + M_LADD (REG_ZERO, 1, d, 1); + M_FCMPEQS(s1, s2, REG_FTMP3); + M_TRAPB; + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLTS(s1, s2, REG_FTMP3); + M_TRAPB; + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LSUB (REG_ZERO, 1, d, 1); + } + else { + M_LADD (REG_ZERO, 1, d, 1); + M_FCMPEQ(s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_OR (REG_ZERO, REG_ZERO, d, 0); + M_FCMPLT(s1, s2, REG_FTMP3); + M_FBEQZ (REG_FTMP3, 1); /* jump over next instruction */ + M_LSUB (REG_ZERO, 1, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + /********************** memory operations *****************************/ + +#define gen_bound_check \ + if (checkbounds) {\ + M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));\ + M_CMPULT(s2, REG_ITMP3, REG_ITMP3, 0);\ + M_BEQZ(REG_ITMP3, 0);\ + mcode_addxboundrefs(mcodeptr);\ + } + + case ICMD_ARRAYLENGTH: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_ILD(d, s1, OFFSET(java_arrayheader, size)); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_AALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_LLD( d, REG_ITMP1, OFFSET(java_objectarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_LALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_LLD(d, REG_ITMP1, OFFSET(java_longarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_IALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S4ADDQ(s2, s1, REG_ITMP1, 0); + M_ILD(d, REG_ITMP1, OFFSET(java_intarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_FALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S4ADDQ(s2, s1, REG_ITMP1, 0); + M_FLD(d, REG_ITMP1, OFFSET(java_floatarray, data[0])); + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_DALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_DLD(d, REG_ITMP1, OFFSET(java_doublearray, data[0])); + store_reg_to_var_flt(iptr->dst, d); + break; + case ICMD_CALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LADD(s2, REG_ITMP1, REG_ITMP1, 0); + M_SLDU(d, REG_ITMP1, OFFSET(java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_EXTWL(REG_ITMP2, REG_ITMP1, d, 0); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_SALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LADD(s2, REG_ITMP1, REG_ITMP1, 0); + M_SLDU( d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_SSEXT(d, d); + } + else { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LADD(s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA(REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0])+2); + M_EXTQH(REG_ITMP2, REG_ITMP1, d, 0); + M_SRA(d, 48, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + case ICMD_BALOAD: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1, 0); + M_BLDU (d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_BSEXT (d, d); + } + else { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_LDA(REG_ITMP1, REG_ITMP1, OFFSET(java_bytearray, data[0])+1); + M_EXTQH(REG_ITMP2, REG_ITMP1, d, 0); + M_SRA(d, 56, d, 1); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_AASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_LST (s3, REG_ITMP1, OFFSET(java_objectarray, data[0])); + break; + case ICMD_LASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_LST (s3, REG_ITMP1, OFFSET(java_longarray, data[0])); + break; + case ICMD_IASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_S4ADDQ(s2, s1, REG_ITMP1, 0); + M_IST (s3, REG_ITMP1, OFFSET(java_intarray, data[0])); + break; + case ICMD_FASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_flt(s3, src, REG_FTMP3); + M_S4ADDQ(s2, s1, REG_ITMP1, 0); + M_FST (s3, REG_ITMP1, OFFSET(java_floatarray, data[0])); + break; + case ICMD_DASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_flt(s3, src, REG_FTMP3); + M_S8ADDQ(s2, s1, REG_ITMP1, 0); + M_DST (s3, REG_ITMP1, OFFSET(java_doublearray, data[0])); + break; + case ICMD_CASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LADD(s2, REG_ITMP1, REG_ITMP1, 0); + M_SST (s3, REG_ITMP1, OFFSET(java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_INSWL(s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKWL(REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + case ICMD_SASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1, 0); + M_LADD(s2, REG_ITMP1, REG_ITMP1, 0); + M_SST (s3, REG_ITMP1, OFFSET(java_shortarray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LADD (s2, REG_ITMP1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_INSWL(s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKWL(REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + case ICMD_BASTORE: + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1, 0); + M_BST (s3, REG_ITMP1, OFFSET(java_bytearray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1, 0); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_INSBL(s3, REG_ITMP1, REG_ITMP3, 0); + M_MSKBL(REG_ITMP2, REG_ITMP1, REG_ITMP2, 0); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2, 0); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + + + case ICMD_PUTSTATIC: + a = dseg_addaddress (iptr->val.a); + M_LLD(REG_ITMP1, REG_PV, a); + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s2, src, REG_ITMP2); + M_IST(s2, REG_ITMP1, 0); + break; + case TYPE_LNG: + case TYPE_ADR: + var_to_reg_int(s2, src, REG_ITMP2); + M_LST(s2, REG_ITMP1, 0); + break; + case TYPE_FLT: + var_to_reg_flt(s2, src, REG_FTMP2); + M_FST(s2, REG_ITMP1, 0); + break; + case TYPE_DBL: + var_to_reg_flt(s2, src, REG_FTMP2); + M_DST(s2, REG_ITMP1, 0); + break; + default: panic ("internal error"); + } + break; + + case ICMD_GETSTATIC: + a = dseg_addaddress (iptr->val.a); + M_LLD(REG_ITMP1, REG_PV, a); + switch (iptr->op1) { + case TYPE_INT: + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ILD(d, REG_ITMP1, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_LNG: + case TYPE_ADR: + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LLD(d, REG_ITMP1, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_FLT: + d = reg_of_var(iptr->dst, REG_FTMP1); + M_FLD(d, REG_ITMP1, 0); + store_reg_to_var_flt(iptr->dst, d); + break; + case TYPE_DBL: + d = reg_of_var(iptr->dst, REG_FTMP1); + M_DLD(d, REG_ITMP1, 0); + store_reg_to_var_flt(iptr->dst, d); + break; + default: panic ("internal error"); + } + break; + + + case ICMD_PUTFIELD: + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + gen_nullptr_check(s1); + M_IST(s2, s1, iptr->val.i); + break; + case TYPE_LNG: + case TYPE_ADR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + gen_nullptr_check(s1); + M_LST(s2, s1, iptr->val.i); + break; + case TYPE_FLT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + gen_nullptr_check(s1); + M_FST(s2, s1, iptr->val.i); + break; + case TYPE_DBL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + gen_nullptr_check(s1); + M_DST(s2, s1, iptr->val.i); + break; + default: panic ("internal error"); + } + break; + + case ICMD_GETFIELD: + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_ILD(d, s1, iptr->val.i); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_LNG: + case TYPE_ADR: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_LLD(d, s1, iptr->val.i); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_FLT: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP1); + gen_nullptr_check(s1); + M_FLD(d, s1, iptr->val.i); + store_reg_to_var_flt(iptr->dst, d); + break; + case TYPE_DBL: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP1); + gen_nullptr_check(s1); + M_DLD(d, s1, iptr->val.i); + store_reg_to_var_flt(iptr->dst, d); + break; + default: panic ("internal error"); + } + break; + + + /********************** branch operations *****************************/ + +#define ALIGNCODENOP {if((int)((long)mcodeptr&7)){M_NOP;}} + + case ICMD_ATHROW: + var_to_reg_int(s1, src, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1_XPTR); + a = dseg_addaddress(asm_handle_exception); + M_LLD(REG_ITMP2, REG_PV, a); + M_JMP(REG_ITMP2_XPC, REG_ITMP2); + ALIGNCODENOP; + break; + + case ICMD_GOTO: + M_BR(0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + ALIGNCODENOP; + break; + + case ICMD_JSR: + M_BSR(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_RET: + var = &(locals[iptr->op1][TYPE_ADR]); + if (var->flags & INMEMORY) { + M_LLD(REG_ITMP1, REG_SP, 8 * var->regoff); + M_RET(REG_ZERO, REG_ITMP1); + } + else + M_RET(REG_ZERO, var->regoff); + ALIGNCODENOP; + break; + + case ICMD_IFNULL: + var_to_reg_int(s1, src, REG_ITMP1); + M_BEQZ(s1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFNONNULL: + var_to_reg_int(s1, src, REG_ITMP1); + M_BNEZ(s1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFEQ: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BEQZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPEQ(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFLT: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BLTZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLT(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFLE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BLEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLE(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFNE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BNEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPEQ(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFGT: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BGTZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLE(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IFGE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BGEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLT(s1, iptr->val.i, REG_ITMP1, 1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LEQ: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BEQZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPEQ(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_LLT: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BLTZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLT(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_LLE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BLEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLE(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_LNE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BNEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPEQ(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_LGT: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BGTZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLE(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_LGE: + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BGEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLT(s1, iptr->val.l, REG_ITMP1, 1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1, 0); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPEQ: + case ICMD_IF_LCMPEQ: + case ICMD_IF_ACMPEQ: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPEQ(s1, s2, REG_ITMP1, 0); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_ICMPNE: + case ICMD_IF_LCMPNE: + case ICMD_IF_ACMPNE: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPEQ(s1, s2, REG_ITMP1, 0); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_ICMPLT: + case ICMD_IF_LCMPLT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLT(s1, s2, REG_ITMP1, 0); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_ICMPGT: + case ICMD_IF_LCMPGT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLE(s1, s2, REG_ITMP1, 0); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_ICMPLE: + case ICMD_IF_LCMPLE: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLE(s1, s2, REG_ITMP1, 0); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + case ICMD_IF_ICMPGE: + case ICMD_IF_LCMPGE: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLT(s1, s2, REG_ITMP1, 0); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + +/* branch if the unsigned value of s1 is greater that s2 (note, that s2 has + to be >= 0) */ + +/* case ICMD_IF_UCMPGE: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPULE(s2, s1, REG_ITMP1, 0); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; +*/ + + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_ARETURN: + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_LLD(REG_PV, REG_PV, a); + M_LLD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + var_to_reg_int(s1, src, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); + goto nowperformreturn; + + case ICMD_FRETURN: + case ICMD_DRETURN: + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_LLD(REG_PV, REG_PV, a); + M_LLD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + var_to_reg_flt(s1, src, REG_FRESULT); + M_FLTMOVE(s1, REG_FRESULT); + goto nowperformreturn; + + case ICMD_RETURN: + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_LLD(REG_PV, REG_PV, a); + M_LLD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + +nowperformreturn: + { + int r, p; + + p = parentargs_base; + if (!isleafmethod) + {p--; M_LLD (REG_RA, REG_SP, 8 * p);} + for (r = savintregcnt - 1; r >= maxsavintreguse; r--) + {p--; M_LLD(savintregs[r], REG_SP, 8 * p);} + for (r = savfltregcnt - 1; r >= maxsavfltreguse; r--) + {p--; M_DLD(savfltregs[r], REG_SP, 8 * p);} + + if (parentargs_base) + {M_LDA(REG_SP, REG_SP, parentargs_base*8);} + if (runverbose) { + M_LDA (REG_SP, REG_SP, -24); + M_LST(REG_RA, REG_SP, 0); + M_LST(REG_RESULT, REG_SP, 8); + M_DST(REG_FRESULT, REG_SP,16); + a = dseg_addaddress (method); + M_LLD(argintregs[0], REG_PV, a); + M_OR(REG_RESULT, REG_RESULT, argintregs[1], 0); + M_FLTMOVE(REG_FRESULT, argfltregs[2]); + a = dseg_addaddress ((void*) (builtin_displaymethodstop)); + M_LLD(REG_PV, REG_PV, a); + M_JSR (REG_RA, REG_PV); + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1<=32768) M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml=-s1, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + M_DLD(REG_FRESULT, REG_SP,16); + M_LLD(REG_RESULT, REG_SP, 8); + M_LLD(REG_RA, REG_SP, 0); + M_LDA (REG_SP, REG_SP, 24); + } + M_RET(REG_ZERO, REG_RA); + ALIGNCODENOP; + } + break; + + + case ICMD_TABLESWITCH: + { + s4 i, l, *s4ptr; + + s4ptr = iptr->val.a; + l = s4ptr[1]; /* low */ + i = s4ptr[2]; /* high */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (l == 0) + {M_INTMOVE(s1, REG_ITMP1);} + else + M_LDA(REG_ITMP1, s1, -l); + i = i - l + 1; + + if (i <= 256) + M_CMPULE(REG_ITMP1, i - 1, REG_ITMP2, 1); + else { + M_LDA(REG_ITMP2, REG_ZERO, i - 1); + M_CMPULE(REG_ITMP1, REG_ITMP2, REG_ITMP2, 0); + } + M_BEQZ(REG_ITMP2, 0); + mcode_addreference(BlockPtrOfPC(s4ptr[0]), mcodeptr); + + /* build jump table top down and use address of lowest entry */ + + s4ptr += 3 + i; + while (--i >= 0) { + dseg_addtarget(BlockPtrOfPC(*--s4ptr)); + } + } + + /* length of dataseg after last dseg_addtarget is used by load */ + + M_S8ADDQ(REG_ITMP1, REG_PV, REG_ITMP2, 0); + M_LLD(REG_ITMP2, REG_ITMP2, -dseglen); + M_JMP(REG_ZERO, REG_ITMP2); + ALIGNCODENOP; + break; + + + case ICMD_LOOKUPSWITCH: + { + s4 i, l, val, *s4ptr; + + s4ptr = iptr->val.a; + l = s4ptr[0]; /* default */ + i = s4ptr[1]; /* count */ + + MCODECHECK((i<<2)+8); + var_to_reg_int(s1, src, REG_ITMP1); + while (--i >= 0) { + s4ptr += 2; + val = s4ptr[0]; + if ((val >= 0) && (val <= 255)) { + M_CMPEQ(s1, val, REG_ITMP2, 1); + } + else { + if ((val >= -32768) && (val <= 32767)) { + M_LDA(REG_ITMP2, REG_ZERO, val); + } + else { + a = dseg_adds4 (val); + M_ILD(REG_ITMP2, REG_PV, a); + } + M_CMPEQ(s1, REG_ITMP2, REG_ITMP2, 0); + } + M_BNEZ(REG_ITMP2, 0); + mcode_addreference(BlockPtrOfPC(s4ptr[1]), mcodeptr); + } + + M_BR(0); + mcode_addreference(BlockPtrOfPC(l), mcodeptr); + ALIGNCODENOP; + break; + } + + + case ICMD_BUILTIN3: + s3 = 3; + goto gen_method; + + case ICMD_BUILTIN2: + s3 = 2; + goto gen_method; + + case ICMD_BUILTIN1: + s3 = 1; + goto gen_method; + + case ICMD_INVOKESTATIC: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKEINTERFACE: + s3 = iptr->op1; + +gen_method: { + methodinfo *m; + classinfo *ci; + + MCODECHECK((s3 << 1) + 64); + + for (; --s3 >= 0; src = src->prev) { + if (src->varkind == ARGVAR) + continue; + if (IS_INT_LNG_TYPE(src->type)) { + if (s3 < INT_ARG_CNT) { + s1 = argintregs[s3]; + var_to_reg_int(d, src, s1); + M_INTMOVE(d, s1); + } + else { + var_to_reg_int(d, src, REG_ITMP1); + M_LST(d, REG_SP, 8 * (s3 - INT_ARG_CNT)); + } + } + else + if (s3 < FLT_ARG_CNT) { + s1 = argfltregs[s3]; + var_to_reg_flt(d, src, s1); + M_FLTMOVE(d, s1); + } + else { + var_to_reg_flt(d, src, REG_FTMP1); + M_DST(d, REG_SP, 8 * (s3 - FLT_ARG_CNT)); + } + } /* end of for */ + + m = iptr->val.a; + switch (iptr->opc) { + case ICMD_BUILTIN3: + case ICMD_BUILTIN2: + case ICMD_BUILTIN1: + a = dseg_addaddress ((void*) (m)); + + M_LLD(REG_PV, REG_PV, a); /* Pointer to built-in-function */ + d = iptr->op1; + goto makeactualcall; + + case ICMD_INVOKESTATIC: + case ICMD_INVOKESPECIAL: + a = dseg_addaddress (m->stubroutine); + + M_LLD(REG_PV, REG_PV, a ); /* Method-Pointer in r27 */ + + d = m->returntype; + goto makeactualcall; + + case ICMD_INVOKEVIRTUAL: + + gen_nullptr_check(argintregs[0]); + M_LLD(REG_METHODPTR, argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_LLD(REG_PV, REG_METHODPTR, OFFSET(vftbl, table[0]) + + sizeof(methodptr) * m->vftblindex); + + d = m->returntype; + goto makeactualcall; + + case ICMD_INVOKEINTERFACE: + ci = m->class; + + gen_nullptr_check(argintregs[0]); + M_LLD(REG_METHODPTR, argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_LLD(REG_METHODPTR, REG_METHODPTR, + OFFSET(vftbl, interfacevftbl)); + M_LLD(REG_METHODPTR, REG_METHODPTR, + sizeof(methodptr*) * ci->index); + M_LLD(REG_PV, REG_METHODPTR, + sizeof(methodptr) * (m - ci->methods)); + + d = m->returntype; + goto makeactualcall; + + default: + d = 0; + sprintf (logtext, "Unkown ICMD-Command: %d", iptr->opc); + error (); + } + +makeactualcall: + + M_JSR (REG_RA, REG_PV); + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1<=32768) M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml=-s1, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + + if (d != TYPE_VOID) { + if (IS_INT_LNG_TYPE(iptr->dst->type)) { + s1 = reg_of_var(iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + store_reg_to_var_int(iptr->dst, s1); + } + else { + s1 = reg_of_var(iptr->dst, REG_FRESULT); + M_FLTMOVE(REG_FRESULT, s1); + store_reg_to_var_flt(iptr->dst, s1); + } + } + } + break; + + case ICMD_CHECKASIZE: + var_to_reg_int(s1, src, REG_ITMP1); + M_BLTZ(s1, 0); + mcode_addxcheckarefs(mcodeptr); + break; + + case ICMD_MULTIANEWARRAY: + + /* check for negative sizes and copy sizes to stack if necessary */ + + MCODECHECK((iptr->op1 << 1) + 64); + + for (s1 = iptr->op1; --s1 >= 0; src = src->prev) { + var_to_reg_int(s2, src, REG_ITMP1); + M_BLTZ(s2, 0); + mcode_addxcheckarefs(mcodeptr); + + /* copy sizes to stack (argument numbers >= INT_ARG_CNT) */ + + if (src->varkind != ARGVAR) { + M_LST(s2, REG_SP, 8 * (s1 + INT_ARG_CNT)); + } + } + + /* a0 = dimension count */ + + M_LDA(argintregs[0], REG_ZERO, iptr->op1); + + /* a1 = arraydescriptor */ + + a = dseg_addaddress(iptr->val.a); + M_LLD(argintregs[1], REG_PV, a); + + /* a2 = pointer to dimensions = stack pointer */ + + M_INTMOVE(REG_SP, argintregs[2]); + + a = dseg_addaddress((void*) (builtin_nmultianewarray)); + M_LLD(REG_PV, REG_PV, a); + M_JSR(REG_RA, REG_PV); + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1 <= 32768) + M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml = -s1, mh = 0; + while (ml < -32768) {ml += 65536; mh--;} + M_LDA(REG_PV, REG_RA, ml); + M_LDAH(REG_PV, REG_PV, mh); + } + s1 = reg_of_var(iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + store_reg_to_var_int(iptr->dst, s1); + break; + + + default: sprintf (logtext, "Unknown pseudo command: %d", iptr->opc); + error(); + } /* switch */ + } /* for instruction */ + src = bptr->outstack; + len = bptr->outdepth; + MCODECHECK(64+len); + while (src) { + len--; + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + var_to_reg_int(s1, src, REG_ITMP1); + if (!(interfaces[len][s2].flags & INMEMORY)) { + M_FLTMOVE(s1,interfaces[len][s2].regoff); + } + else { + M_DST(s1, REG_SP, 8 * interfaces[len][s2].regoff); + } + } + else { + var_to_reg_flt(s1, src, REG_FTMP1); + if (!(interfaces[len][s2].flags & INMEMORY)) { + M_INTMOVE(s1,interfaces[len][s2].regoff); + } + else { + M_LST(s1, REG_SP, 8 * interfaces[len][s2].regoff); + } + } + } + src = src->prev; + } + } /* for basic block */ + + { + s4 *xcodeptr = NULL; + + for (; xboundrefs != NULL; xboundrefs = xboundrefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xboundrefs->branchpos, + xboundrefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xboundrefs->branchpos, + xboundrefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xboundrefs->branchpos); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_ArrayIndexOutOfBoundsException); + M_LLD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_LLD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ZERO, REG_ITMP3); + } + } + + xcodeptr = NULL; + + for (; xcheckarefs != NULL; xcheckarefs = xcheckarefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xcheckarefs->branchpos, + xcheckarefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xcheckarefs->branchpos, + xcheckarefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xcheckarefs->branchpos); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_NegativeArraySizeException); + M_LLD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_LLD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ZERO, REG_ITMP3); + } + } + + +#ifdef SOFTNULLPTRCHECK + + xcodeptr = NULL; + + for (; xnullrefs != NULL; xnullrefs = xnullrefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xnullrefs->branchpos, + xnullrefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xnullrefs->branchpos, + xnullrefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xnullrefs->branchpos - 4); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_NullPointerException); + M_LLD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_LLD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ZERO, REG_ITMP3); + } + } + +#endif + } + + mcode_finish((int)((u1*) mcodeptr - mcodebase)); +} + + +/******** redefinition of code generation macros (compiling into array) *******/ + +/* +These macros are newly defined to allow code generation into an array. +This is necessary, because the original M_.. macros generate code by +calling 'mcode_adds4' that uses an additional data structure to +receive the code. + +For a faster (but less flexible) version to generate code, these +macros directly use the (s4* p) - pointer to put the code directly +in a locally defined array. +This makes sense only for the stub-generation-routines below. +*/ + +#undef M_OP3 +#define M_OP3(op,fu,a,b,c,const) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \ + ((const)<<12)|((fu)<<5)|((c)) ) +#undef M_FOP3 +#define M_FOP3(op,fu,a,b,c) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) ) +#undef M_BRA +#define M_BRA(op,a,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) ) +#undef M_MEM +#define M_MEM(op,a,b,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) ) + + +#if 0 + +/************************ function createcompilerstub ************************** + + creates a stub routine which calls the compiler + +*******************************************************************************/ + +#define COMPSTUBSIZE 3 + +u1 *createcompilerstub (methodinfo *m) +{ + u8 *s = CNEW (u8, COMPSTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + /* code for the stub */ + M_LLD (REG_PV, REG_PV, 16); /* load pointer to the compiler */ + M_JMP (0, REG_PV); /* jump to the compiler, return address + in reg 0 is used as method pointer */ + s[1] = (u8) m; /* literals to be adressed */ + s[2] = (u8) asm_call_jit_compiler; /* jump directly via PV from above */ + +#ifdef STATISTICS + count_cstub_len += COMPSTUBSIZE * 8; +#endif + + return (u1*) s; +} + + +/************************* function removecompilerstub ************************* + + deletes a compilerstub from memory (simply by freeing it) + +*******************************************************************************/ + +void removecompilerstub (u1 *stub) +{ + CFREE (stub, COMPSTUBSIZE * 8); +} + + +/************************ function: removenativestub *************************** + + removes a previously created native-stub from memory + +*******************************************************************************/ + +void removenativestub (u1 *stub) +{ + CFREE (stub, NATIVESTUBSIZE * 8); +} + +#endif /* 0 */ + + +/********************* Funktion: ncreatenativestub ***************************** + + creates a stub routine which calls a native method + +*******************************************************************************/ + +#define NATIVESTUBSIZE 11 + +u1 *ncreatenativestub (functionptr f, methodinfo *m) +{ + u8 *s = CNEW (u8, NATIVESTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + M_LDA (REG_SP, REG_SP, -8); /* build up stackframe */ + M_LST (REG_RA, REG_SP, 0); /* store return address */ + + M_LLD (REG_PV, REG_PV, 8*8); /* load adress of native method */ + M_JSR (REG_RA, REG_PV); /* call native method */ + + M_LDA (REG_PV, REG_RA, -4*4); /* recompute pv from ra */ + M_LLD (REG_ITMP3, REG_PV, 9*8); /* get address of exceptionptr */ + + M_LLD (REG_RA, REG_SP, 0); /* load return address */ + M_LLD (REG_ITMP1, REG_ITMP3, 0); /* load exception into reg. itmp1 */ + + M_LDA (REG_SP, REG_SP, 8); /* remove stackframe */ + M_BNEZ (REG_ITMP1, 1); /* if no exception then return */ + + M_RET (REG_ZERO, REG_RA); /* return to caller */ + + M_LST (REG_ZERO, REG_ITMP3, 0); /* store NULL into exceptionptr */ + M_LDA (REG_ITMP2, REG_RA, -4); /* move fault address into reg. itmp2 */ + + M_LLD (REG_ITMP3, REG_PV,10*8); /* load asm exception handler address */ + M_JMP (REG_ZERO, REG_ITMP3); /* jump to asm exception handler */ + + + s[8] = (u8) f; /* address of native method */ + s[9] = (u8) (&exceptionptr); /* address of exceptionptr */ + s[10]= (u8) (asm_handle_nat_exception); /* addr of asm exception handler */ + +#ifdef STATISTICS + count_nstub_len += NATIVESTUBSIZE * 8; +#endif + + return (u1*) s; +} + diff --git a/alpha/ngen.h b/alpha/ngen.h new file mode 100644 index 000000000..5b3239cd1 --- /dev/null +++ b/alpha/ngen.h @@ -0,0 +1,328 @@ +/***************************** alpha/ngen.h ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the machine dependent code generator definitions and macros for an + Alpha processor. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/08/10 + +*******************************************************************************/ + +/************************ Preallocated registers ******************************/ + +/* integer registers */ + +#define REG_RESULT 0 /* to deliver method results */ +#define REG_EXCEPTION 1 /* to throw an exception across method bounds */ + +#define REG_RA 26 /* return address */ +#define REG_PV 27 /* procedure vector, must be provided by caller */ +#define REG_METHODPTR 28 /* pointer to the place from where the procedure */ + /* vector has been fetched */ +#define REG_ITMP1 25 /* temporary register */ +#define REG_ITMP2 28 /* temporary register */ +#define REG_ITMP3 29 /* temporary register */ + +#define REG_ITMP1_XPTR 25 /* exception pointer = temporary register 1 */ +#define REG_ITMP2_XPC 28 /* exception pc = temporary register 2 */ + +#define REG_SP 30 /* stack pointer */ +#define REG_ZERO 31 /* allways zero */ + +/* floating point registers */ + +#define REG_FRESULT 0 /* to deliver floating point method results */ +#define REG_FTMP1 28 /* temporary floating point register */ +#define REG_FTMP2 29 /* temporary floating point register */ +#define REG_FTMP3 30 /* temporary floating point register */ + +#define REG_IFTMP 28 /* temporary integer and floating point register */ + +/******************** register descripton - array *****************************/ + +/* #define REG_RES 0 reserved register for OS or code generator */ +/* #define REG_RET 1 return value register */ +/* #define REG_EXC 2 exception value register */ +/* #define REG_SAV 3 (callee) saved register */ +/* #define REG_TMP 4 scratch temporary register (caller saved) */ +/* #define REG_ARG 5 argument register (caller saved) */ + +/* #define REG_END -1 last entry in tables */ + +int nregdescint[] = { + REG_RET, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, + REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, + REG_END }; + +#define INT_SAV_CNT 7 /* number of int callee saved registers */ +#define INT_ARG_CNT 6 /* number of int argument registers */ + +/* for use of reserved registers, see comment above */ + +int nregdescfloat[] = { + REG_RET, REG_TMP, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + REG_SAV, REG_SAV, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, + REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, + REG_END }; + +#define FLT_SAV_CNT 8 /* number of flt callee saved registers */ +#define FLT_ARG_CNT 6 /* number of flt argument registers */ + +/* for use of reserved registers, see comment above */ + + +/*** parameter allocation mode ***/ + +int nreg_parammode = PARAMMODE_NUMBERED; + + /* parameter-registers will be allocated by assigning the + 1. parameter: int/float-reg 16 + 2. parameter: int/float-reg 17 + 3. parameter: int/float-reg 18 .... + */ + + +/************************** stackframe-infos **********************************/ + +int parentargs_base; /* offset in stackframe for the parameter from the caller*/ + +/* -> see file 'calling.doc' */ + + +/******************** macros to create code ***********************************/ + +/* 3-address-operations: M_OP3 + op ..... opcode + fu ..... function-number + a ..... register number source 1 + b ..... register number or constant integer source 2 + c ..... register number destination + const .. switch to use b as constant integer + (0 means: use b as register number) + (1 means: use b as constant 8-bit-integer) +*/ +#define M_OP3(op,fu,a,b,c,const) \ + *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \ + ((const)<<12)|((fu)<<5)|((c)) ) + +/* 3-address-floating-point-operation: M_FOP3 + op .... opcode + fu .... function-number + a,b ... source floating-point registers + c ..... destination register +*/ +#define M_FOP3(op,fu,a,b,c) \ + *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) ) + +/* branch instructions: M_BRA + op ..... opcode + a ...... register to be tested + disp ... relative address to be jumped to (divided by 4) +*/ +#define M_BRA(op,a,disp) \ + *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) ) + + +/* memory operations: M_MEM + op ..... opcode + a ...... source/target register for memory access + b ...... base register + disp ... displacement (16 bit signed) to be added to b +*/ +#define M_MEM(op,a,b,disp) \ + *(mcodeptr++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) ) + + +/***** macros for all used commands (see an Alpha-manual for description) *****/ + +#define M_LDA(a,b,disp) M_MEM (0x08,a,b,disp) /* low const */ +#define M_LDAH(a,b,disp) M_MEM (0x09,a,b,disp) /* high const */ +#define M_BLDU(a,b,disp) M_MEM (0x0a,a,b,disp) /* 8 load */ +#define M_SLDU(a,b,disp) M_MEM (0x0c,a,b,disp) /* 16 load */ +#define M_ILD(a,b,disp) M_MEM (0x28,a,b,disp) /* 32 load */ +#define M_LLD(a,b,disp) M_MEM (0x29,a,b,disp) /* 64 load */ +#define M_BST(a,b,disp) M_MEM (0x0e,a,b,disp) /* 8 store */ +#define M_SST(a,b,disp) M_MEM (0x0d,a,b,disp) /* 16 store */ +#define M_IST(a,b,disp) M_MEM (0x2c,a,b,disp) /* 32 store */ +#define M_LST(a,b,disp) M_MEM (0x2d,a,b,disp) /* 64 store */ + +#define M_BSEXT(b,c) M_OP3 (0x1c,0x0,REG_ZERO,b,c,0) /* 8 signext */ +#define M_SSEXT(b,c) M_OP3 (0x1c,0x1,REG_ZERO,b,c,0) /* 16 signext */ + +#define M_BR(disp) M_BRA (0x30,REG_ZERO,disp) /* branch */ +#define M_BSR(ra,disp) M_BRA (0x34,ra,disp) /* branch sbr */ +#define M_BEQZ(a,disp) M_BRA (0x39,a,disp) /* br a == 0 */ +#define M_BLTZ(a,disp) M_BRA (0x3a,a,disp) /* br a < 0 */ +#define M_BLEZ(a,disp) M_BRA (0x3b,a,disp) /* br a <= 0 */ +#define M_BNEZ(a,disp) M_BRA (0x3d,a,disp) /* br a != 0 */ +#define M_BGEZ(a,disp) M_BRA (0x3e,a,disp) /* br a >= 0 */ +#define M_BGTZ(a,disp) M_BRA (0x3f,a,disp) /* br a > 0 */ + +#define M_JMP(a,b) M_MEM (0x1a,a,b,0x0000) /* jump */ +#define M_JSR(a,b) M_MEM (0x1a,a,b,0x4000) /* call sbr */ +#define M_RET(a,b) M_MEM (0x1a,a,b,0x8000) /* return */ + +#define M_IADD(a,b,c,const) M_OP3 (0x10,0x0, a,b,c,const) /* 32 add */ +#define M_LADD(a,b,c,const) M_OP3 (0x10,0x20, a,b,c,const) /* 64 add */ +#define M_ISUB(a,b,c,const) M_OP3 (0x10,0x09, a,b,c,const) /* 32 sub */ +#define M_LSUB(a,b,c,const) M_OP3 (0x10,0x29, a,b,c,const) /* 64 sub */ +#define M_IMUL(a,b,c,const) M_OP3 (0x13,0x00, a,b,c,const) /* 32 mul */ +#define M_LMUL(a,b,c,const) M_OP3 (0x13,0x20, a,b,c,const) /* 64 mul */ + +#define M_CMPEQ(a,b,c,const) M_OP3 (0x10,0x2d, a,b,c,const) /* c = a == b */ +#define M_CMPLT(a,b,c,const) M_OP3 (0x10,0x4d, a,b,c,const) /* c = a < b */ +#define M_CMPLE(a,b,c,const) M_OP3 (0x10,0x6d, a,b,c,const) /* c = a <= b */ + +#define M_CMPULE(a,b,c,const) M_OP3 (0x10,0x3d, a,b,c,const) /* c = a <= b */ +#define M_CMPULT(a,b,c,const) M_OP3 (0x10,0x1d, a,b,c,const) /* c = a <= b */ + +#define M_AND(a,b,c,const) M_OP3 (0x11,0x00, a,b,c,const) /* c = a & b */ +#define M_OR(a,b,c,const) M_OP3 (0x11,0x20, a,b,c,const) /* c = a | b */ +#define M_XOR(a,b,c,const) M_OP3 (0x11,0x40, a,b,c,const) /* c = a ^ b */ + +#define M_NOP M_OR (31,31,31,0) + +#define M_SLL(a,b,c,const) M_OP3 (0x12,0x39, a,b,c,const) /* c = a << b */ +#define M_SRA(a,b,c,const) M_OP3 (0x12,0x3c, a,b,c,const) /* c = a >> b */ +#define M_SRL(a,b,c,const) M_OP3 (0x12,0x34, a,b,c,const) /* c = a >>>b */ + +#define M_FLD(a,b,disp) M_MEM (0x22,a,b,disp) /* load flt */ +#define M_DLD(a,b,disp) M_MEM (0x23,a,b,disp) /* load dbl */ +#define M_FST(a,b,disp) M_MEM (0x26,a,b,disp) /* store flt */ +#define M_DST(a,b,disp) M_MEM (0x27,a,b,disp) /* store dbl */ + +#define M_FADD(a,b,c) M_FOP3 (0x16, 0x080, a,b,c) /* flt add */ +#define M_DADD(a,b,c) M_FOP3 (0x16, 0x0a0, a,b,c) /* dbl add */ +#define M_FSUB(a,b,c) M_FOP3 (0x16, 0x081, a,b,c) /* flt sub */ +#define M_DSUB(a,b,c) M_FOP3 (0x16, 0x0a1, a,b,c) /* dbl sub */ +#define M_FMUL(a,b,c) M_FOP3 (0x16, 0x082, a,b,c) /* flt mul */ +#define M_DMUL(a,b,c) M_FOP3 (0x16, 0x0a2, a,b,c) /* dbl mul */ +#define M_FDIV(a,b,c) M_FOP3 (0x16, 0x083, a,b,c) /* flt div */ +#define M_DDIV(a,b,c) M_FOP3 (0x16, 0x0a3, a,b,c) /* dbl div */ + +#define M_FADDS(a,b,c) M_FOP3 (0x16, 0x580, a,b,c) /* flt add */ +#define M_DADDS(a,b,c) M_FOP3 (0x16, 0x5a0, a,b,c) /* dbl add */ +#define M_FSUBS(a,b,c) M_FOP3 (0x16, 0x581, a,b,c) /* flt sub */ +#define M_DSUBS(a,b,c) M_FOP3 (0x16, 0x5a1, a,b,c) /* dbl sub */ +#define M_FMULS(a,b,c) M_FOP3 (0x16, 0x582, a,b,c) /* flt mul */ +#define M_DMULS(a,b,c) M_FOP3 (0x16, 0x5a2, a,b,c) /* dbl mul */ +#define M_FDIVS(a,b,c) M_FOP3 (0x16, 0x583, a,b,c) /* flt div */ +#define M_DDIVS(a,b,c) M_FOP3 (0x16, 0x5a3, a,b,c) /* dbl div */ + +#define M_CVTDF(a,b,c) M_FOP3 (0x16, 0x0ac, a,b,c) /* dbl2long */ +#define M_CVTLF(a,b,c) M_FOP3 (0x16, 0x0bc, a,b,c) /* long2flt */ +#define M_CVTLD(a,b,c) M_FOP3 (0x16, 0x0be, a,b,c) /* long2dbl */ +#define M_CVTDL(a,b,c) M_FOP3 (0x16, 0x1af, a,b,c) /* dbl2long */ +#define M_CVTDL_C(a,b,c) M_FOP3 (0x16, 0x12f, a,b,c) /* dbl2long */ +#define M_CVTLI(a,b) M_FOP3 (0x17, 0x130, 31,a,b) /* long2int */ + +#define M_CVTDFS(a,b,c) M_FOP3 (0x16, 0x5ac, a,b,c) /* dbl2long */ +#define M_CVTDLS(a,b,c) M_FOP3 (0x16, 0x5af, a,b,c) /* dbl2long */ +#define M_CVTDL_CS(a,b,c) M_FOP3 (0x16, 0x52f, a,b,c) /* dbl2long */ +#define M_CVTLIS(a,b) M_FOP3 (0x17, 0x530, 31,a,b) /* long2int */ + +#define M_FCMPEQ(a,b,c) M_FOP3 (0x16, 0x0a5, a,b,c) /* c = a==b */ +#define M_FCMPLT(a,b,c) M_FOP3 (0x16, 0x0a6, a,b,c) /* c = a=0 ? c=b */ +#define M_CMOVLE(a,b,c,const) M_OP3 (0x11,0x64, a,b,c,const) /* a<=0 ? c=b */ +#define M_CMOVGT(a,b,c,const) M_OP3 (0x11,0x66, a,b,c,const) /* a> 0 ? c=b */ + +#define M_CMPBGE(a,b,c,const) M_OP3 (0x10,0x0f, a,b,c,const) + +#define M_FCMPUN(a,b,c) M_FOP3 (0x16, 0x0a4, a,b,c) /* unordered */ +#define M_FCMPLE(a,b,c) M_FOP3 (0x16, 0x0a7, a,b,c) /* c = a<=b */ + +#define M_FCMPUNS(a,b,c) M_FOP3 (0x16, 0x5a4, a,b,c) /* unordered */ +#define M_FCMPLES(a,b,c) M_FOP3 (0x16, 0x5a7, a,b,c) /* c = a<=b */ + +#define M_FBNEZ(fa,disp) M_BRA (0x35,fa,disp) +#define M_FBLEZ(fa,disp) M_BRA (0x33,fa,disp) + +#define M_JMP_CO(a,b) M_MEM (0x1a,a,b,0xc000) /* call cosub */ + + +/************************ function gen_resolvebranch *************************** + + backpatches a branch instruction; Alpha branch instructions are very + regular, so it is only necessary to overwrite some fixed bits in the + instruction. + + parameters: ip ... pointer to instruction after branch (void*) + so ... offset of instruction after branch (s4) + to ... offset of branch target (s4) + +*******************************************************************************/ + +#define gen_resolvebranch(ip,so,to) ((s4*)(ip))[-1]|=((s4)(to)-(so))>>2&0x1fffff + +#define SOFTNULLPTRCHECK diff --git a/alpha/sigcontext.h b/alpha/sigcontext.h new file mode 100644 index 000000000..2b5f1b5e4 --- /dev/null +++ b/alpha/sigcontext.h @@ -0,0 +1,37 @@ +#ifndef _ASMAXP_SIGCONTEXT_H +#define _ASMAXP_SIGCONTEXT_H + +struct sigcontext_struct { + + /* + * what should we have here? I'd probably better use the same + * stack layout as OSF/1, just in case we ever want to try + * running their binaries.. + * + * This is the basic layout, but I don't know if we'll ever + * actually fill in all the values.. + */ + + long sc_onstack; /* sigstack state to restore */ + long sc_mask; /* signal mask to restore */ + long sc_pc; /* pc at time of signal */ + long sc_ps; /* psl to retore */ + long sc_regs[32]; /* processor regs 0 to 31 */ + long sc_ownedfp; /* fp has been used */ + long sc_fpregs[32]; /* fp regs 0 to 31 */ + unsigned long sc_fpcr; /* floating point control register */ + unsigned long sc_fp_control; /* software fpcr */ + /* rest is unused */ + unsigned long sc_reserved1, sc_reserved2; + unsigned long sc_ssize; + char *sc_sbase; + unsigned long sc_traparg_a0; + unsigned long sc_traparg_a1; + unsigned long sc_traparg_a2; + unsigned long sc_fp_trap_pc; + unsigned long sc_fp_trigger_sum; + unsigned long sc_fp_trigger_inst; + unsigned long sc_retcode[2]; +}; + +#endif diff --git a/alpha/threads.h b/alpha/threads.h new file mode 100644 index 000000000..c2b8e86a0 --- /dev/null +++ b/alpha/threads.h @@ -0,0 +1,72 @@ +/* + * i386/threads.h + * i386 threading information. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + * + * See file COPYRIGHT for information on usage and disclaimer of warranties + * + * Written by Tim Wilkinson , 1996. + */ + +#ifndef __alpha_threads_h +#define __alpha_threads_h + +/**/ +/* Thread handling */ +/**/ + +#include "../threads/thread.h" + +void perform_alpha_threadswitch (u1 **from, u1 **to); +u1* initialize_thread_stack (void *func, u1 *stack); +u1* used_stack_top (void); + +#define THREADSTACKSIZE (64 * 1024) + +#define THREADSWITCH(to, from) perform_alpha_threadswitch(&(from)->restorePoint,\ + &(to)->restorePoint) + +#define THREADINIT(to, func) (to)->restorePoint = \ + initialize_thread_stack((u1*)(func), \ + (to)->stackEnd) + +#define USEDSTACKTOP(top) (top) = used_stack_top() + +#define THREADINFO(ee) \ + do { \ + (ee)->restorePoint = 0; \ + (ee)->flags = THREAD_FLAGS_NOSTACKALLOC;\ + } while(0) + +/* + void* ptr; \ + asm("addq $30,$31,%0" : "=r" (ptr)); \ + (ee)->stackEnd = ptr; \ + (ee)->stackBase = (ee)->stackEnd - threadStackSize;\ +*/ + +/* +#define THREADFRAMES(tid, cnt) \ + do { \ + void** ptr; \ + cnt = 0; \ + if (tid == currentThread) { \ + asm("movl %%ebp,%0" : "=r" (ptr));\ + } \ + else { \ + ptr = ((void***)tid->PrivateInfo->restorePoint)[2];\ + } \ + while (*ptr != 0) { \ + cnt++; \ + ptr = (void**)*ptr; \ + } \ + } while (0) +*/ + +#endif diff --git a/alpha/types.h b/alpha/types.h new file mode 100644 index 000000000..8325c8cf8 --- /dev/null +++ b/alpha/types.h @@ -0,0 +1,58 @@ +/*************************** alpha/types.h ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + machine specific definitions for the Alpha processor + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Michael Gschwind EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/09/22 + +*******************************************************************************/ + +#ifndef _CACAO_TYPES_H + +#define _CACAO_TYPES_H + +#define POINTERSIZE 8 +#define WORDS_BIGENDIAN 0 + +#define SUPPORT_DIVISION 0 +#define SUPPORT_LONG 1 +#define SUPPORT_FLOAT 1 +#define SUPPORT_DOUBLE 1 + +#define SUPPORT_LONG_ADD 1 +#define SUPPORT_LONG_CMP 1 +#define SUPPORT_LONG_LOG 1 +#define SUPPORT_LONG_SHIFT 1 +#define SUPPORT_LONG_MULDIV 1 +#define SUPPORT_LONG_ICVT 1 +#define SUPPORT_LONG_FCVT 1 + +#define U8_AVAILABLE 1 + + +typedef signed char s1; +typedef unsigned char u1; + +typedef signed short int s2; +typedef unsigned short int u2; + +typedef signed int s4; +typedef unsigned int u4; + +#if U8_AVAILABLE +typedef signed long int s8; +typedef unsigned long int u8; +#else +typedef struct {u4 low, high;} u8; +#define s8 u8 +#endif + +#endif + diff --git a/asmpart.h b/asmpart.h new file mode 100644 index 000000000..927ccd161 --- /dev/null +++ b/asmpart.h @@ -0,0 +1,41 @@ +/****************************** asmpart.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Headerfile for asmpart.S. asmpart.S contains the machine dependent + Java - C interface functions. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/15 + +*******************************************************************************/ + +int has_no_x_instr_set(); + /* determines if the byte support instruction set (21164a and higher) + is available. */ + +void synchronize_caches(); + + +void asm_call_jit_compiler (); + /* invokes the compiler for untranslated JavaVM methods. + Register R0 contains a pointer to the method info structure + (prepared by createcompilerstub). */ + +java_objectheader *asm_calljavamethod (methodinfo *m, void *arg1, void*arg2, + void*arg3, void*arg4); + /* This function calls a Java-method (which possibly needs compilation) + with up to 4 parameters. This function calls a Java-method (which + possibly needs compilation) with up to 4 parameters. */ + + +void asm_dumpregistersandcall ( functionptr f); + /* This funtion saves all callee saved registers and calls the function + which is passed as parameter. + This function is needed by the garbage collector, which needs to access + all registers which are stored on the stack. Unused registers are + cleared to avoid interferances with the GC. */ diff --git a/builtin.c b/builtin.c new file mode 100644 index 000000000..c1de52db7 --- /dev/null +++ b/builtin.c @@ -0,0 +1,1621 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** builtin.c ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enthaelt die C-Funktionen fuer alle JavaVM-Befehle, die sich nicht direkt + auf Maschinencode "ubersetzen lassen. Im Code f"ur die Methoden steht + dann ein Funktionsaufruf (nat"urlich mit den Aufrufskonventionen von C). + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/12/03 + +*******************************************************************************/ + +#include +#include + +#include "global.h" +#include "builtin.h" + +#include "loader.h" +#include "tables.h" + +#include "threads/thread.h" +#include "threads/locks.h" /* schani */ + +#include "sysdep/native-math.h" + +builtin_descriptor builtin_desc[] = { + {(functionptr) builtin_instanceof, "instanceof"}, + {(functionptr) builtin_checkcast, "checkcast"}, + {(functionptr) new_builtin_checkcast, "checkcast"}, + {(functionptr) builtin_arrayinstanceof, "arrayinstanceof"}, + {(functionptr) builtin_checkarraycast, "checkarraycast"}, + {(functionptr) new_builtin_checkarraycast, "checkarraycast"}, + {(functionptr) new_builtin_aastore, "aastore"}, + {(functionptr) builtin_new, "new"}, + {(functionptr) builtin_anewarray, "anewarray"}, + {(functionptr) builtin_newarray_array, "newarray_array"}, + {(functionptr) builtin_newarray_boolean, "newarray_boolean"}, + {(functionptr) builtin_newarray_char, "newarray_char"}, + {(functionptr) builtin_newarray_float, "newarray_float"}, + {(functionptr) builtin_newarray_double, "newarray_double"}, + {(functionptr) builtin_newarray_byte, "newarray_byte"}, + {(functionptr) builtin_newarray_short, "newarray_short"}, + {(functionptr) builtin_newarray_int, "newarray_int"}, + {(functionptr) builtin_newarray_long, "newarray_long"}, + {(functionptr) builtin_displaymethodstart, "displaymethodstart"}, + {(functionptr) builtin_displaymethodstop, "displaymethodstop"}, + {(functionptr) builtin_monitorenter, "monitorenter"}, + {(functionptr) new_builtin_monitorenter, "monitorenter"}, + {(functionptr) builtin_monitorexit, "monitorexit"}, + {(functionptr) new_builtin_monitorexit, "monitorexit"}, + {(functionptr) builtin_idiv, "idiv"}, + {(functionptr) new_builtin_idiv, "idiv"}, + {(functionptr) builtin_irem, "irem"}, + {(functionptr) new_builtin_irem, "irem"}, + {(functionptr) builtin_ladd, "ladd"}, + {(functionptr) builtin_lsub, "lsub"}, + {(functionptr) builtin_lmul, "lmul"}, + {(functionptr) builtin_ldiv, "ldiv"}, + {(functionptr) new_builtin_ldiv, "ldiv"}, + {(functionptr) builtin_lrem, "lrem"}, + {(functionptr) new_builtin_lrem, "lrem"}, + {(functionptr) builtin_lshl, "lshl"}, + {(functionptr) builtin_lshr, "lshr"}, + {(functionptr) builtin_lushr, "lushr"}, + {(functionptr) builtin_land, "land"}, + {(functionptr) builtin_lor, "lor"}, + {(functionptr) builtin_lxor, "lxor"}, + {(functionptr) builtin_lneg, "lneg"}, + {(functionptr) builtin_lcmp, "lcmp"}, + {(functionptr) builtin_fadd, "fadd"}, + {(functionptr) builtin_fsub, "fsub"}, + {(functionptr) builtin_fmul, "fmul"}, + {(functionptr) builtin_fdiv, "fdiv"}, + {(functionptr) builtin_frem, "frem"}, + {(functionptr) builtin_fneg, "fneg"}, + {(functionptr) builtin_fcmpl, "fcmpl"}, + {(functionptr) builtin_fcmpg, "fcmpg"}, + {(functionptr) builtin_dadd, "dadd"}, + {(functionptr) builtin_dsub, "dsub"}, + {(functionptr) builtin_dmul, "dmul"}, + {(functionptr) builtin_ddiv, "ddiv"}, + {(functionptr) builtin_drem, "drem"}, + {(functionptr) builtin_dneg, "dneg"}, + {(functionptr) builtin_dcmpl, "dcmpl"}, + {(functionptr) builtin_dcmpg, "dcmpg"}, + {(functionptr) builtin_i2l, "i2l"}, + {(functionptr) builtin_i2f, "i2f"}, + {(functionptr) builtin_i2d, "i2d"}, + {(functionptr) builtin_l2i, "l2i"}, + {(functionptr) builtin_l2f, "l2f"}, + {(functionptr) builtin_l2d, "l2d"}, + {(functionptr) builtin_f2i, "f2i"}, + {(functionptr) builtin_f2l, "f2l"}, + {(functionptr) builtin_f2d, "f2d"}, + {(functionptr) builtin_d2i, "d2i"}, + {(functionptr) builtin_d2l, "d2l"}, + {(functionptr) builtin_d2f, "d2f"}, + {(functionptr) NULL, "unknown"} + }; + + +/***************************************************************************** + TYPCHECKS +*****************************************************************************/ + + + +/*************** interne Funktion: builtin_isanysubclass ********************* + + "uberpr"uft, ob eine Klasse eine Unterklasse einer anderen Klasse ist. + Dabei gelten auch Interfaces, die eine Klasse implementiert, als + deren Oberklassen. + R"uckgabewert: 1 ... es trifft zu + 0 ... es trifft nicht zu + +*****************************************************************************/ + +static s4 builtin_isanysubclass (classinfo *sub, classinfo *super) +{ + if (super->flags & ACC_INTERFACE) { + u4 index = super->index; +/* if (sub->vftbl == NULL) return 0; */ + if (index >= sub->vftbl->interfacetablelength) return 0; + return ( sub->vftbl->interfacevftbl[index] ) ? 1 : 0; + } + else { + while (sub) { + if (sub==super) return 1; + sub = sub->super; + } + return 0; + } +} + + +/****************** Funktion: builtin_instanceof ***************************** + + "Uberpr"uft, ob ein Objekt eine Instanz einer Klasse (oder einer davon + abgeleiteten Klasse) ist, oder ob die Klasse des Objekts ein Interface + implementiert. + Return: 1, wenn ja + 0, wenn nicht, oder wenn Objekt ein NULL-Zeiger + +*****************************************************************************/ + +s4 builtin_instanceof(java_objectheader *obj, classinfo *class) +{ +#ifdef DEBUG + log_text ("builtin_instanceof called"); +#endif + + if (!obj) return 0; + return builtin_isanysubclass (obj->vftbl->class, class); +} + + + +/**************** Funktion: builtin_checkcast ******************************* + + "Uberpr"uft, ob ein Objekt eine Instanz einer Klasse (oder einer davon + abgeleiteten Klasse ist). + Unterschied zu builtin_instanceof: Ein NULL-Zeiger ist immer richtig + Return: 1, wenn ja, oder wenn Objekt ein NULL-Zeiger + 0, wenn nicht + +****************************************************************************/ + +s4 builtin_checkcast(java_objectheader *obj, classinfo *class) +{ +#ifdef DEBUG + log_text ("builtin_checkcast called"); +#endif + + if (!obj) return 1; + if ( builtin_isanysubclass (obj->vftbl->class, class) ) { + return 1; + } +#if DEBUG + printf ("#### checkcast failed "); + unicode_display (obj->vftbl->class->name); + printf (" -> "); + unicode_display (class->name); + printf ("\n"); +#endif + + return 0; +} + + + +/*********** interne Funktion: builtin_descriptorscompatible ****************** + + "uberpr"uft, ob zwei Array-Typdescriptoren compartible sind, d.h., + ob ein Array vom Typ 'desc' gefahrlos einer Variblen vom Typ 'target' + zugewiesen werden kann. + Return: 1, wenn ja + 0, wenn nicht + +******************************************************************************/ + +static s4 builtin_descriptorscompatible + (constant_arraydescriptor *desc, constant_arraydescriptor *target) +{ + if (desc==target) return 1; + if (desc->arraytype != target->arraytype) return 0; + switch (target->arraytype) { + case ARRAYTYPE_OBJECT: + return builtin_isanysubclass (desc->objectclass, target->objectclass); + case ARRAYTYPE_ARRAY: + return builtin_descriptorscompatible + (desc->elementdescriptor, target->elementdescriptor); + default: return 1; + } +} + + + +/******************** Funktion: builtin_checkarraycast *********************** + + "uberpr"uft, ob ein gegebenes Objekt tats"achlich von einem + Untertyp des geforderten Arraytyps ist. + Dazu muss das Objekt auf jeden Fall ein Array sein. + Bei einfachen Arrays (int,short,double,etc.) muss der Typ genau + "ubereinstimmen. + Bei Arrays von Objekten muss der Elementtyp des tats"achlichen Arrays + ein Untertyp (oder der selbe Typ) vom geforderten Elementtyp sein. + Bei Arrays vom Arrays (die eventuell wieder Arrays von Arrays + sein k"onnen) m"ussen die untersten Elementtypen in der entsprechenden + Unterklassenrelation stehen. + + Return: 1, wenn Cast in Ordung ist + 0, wenn es nicht geht + + Achtung: ein Cast mit einem NULL-Zeiger geht immer gut. + +*****************************************************************************/ + +s4 builtin_checkarraycast(java_objectheader *o, constant_arraydescriptor *desc) +{ + java_arrayheader *a = (java_arrayheader*) o; + + if (!o) return 1; + if (o->vftbl->class != class_array) { + return 0; + } + + if (a->arraytype != desc->arraytype) { + return 0; + } + + switch (a->arraytype) { + case ARRAYTYPE_OBJECT: { + java_objectarray *oa = (java_objectarray*) o; + return builtin_isanysubclass (oa->elementtype, desc->objectclass); + } + case ARRAYTYPE_ARRAY: { + java_arrayarray *aa = (java_arrayarray*) o; + return builtin_descriptorscompatible + (aa->elementdescriptor, desc->elementdescriptor); + } + default: + return 1; + } +} + + +s4 builtin_arrayinstanceof + (java_objectheader *obj, constant_arraydescriptor *desc) +{ + if (!obj) return 1; + return builtin_checkarraycast (obj, desc); +} + + +/************************** exception functions ******************************* + +******************************************************************************/ + +java_objectheader *builtin_throw_exception (java_objectheader *exceptionptr) { + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + fflush (stdout); + return exceptionptr; +} + + +/******************* Funktion: builtin_canstore ******************************* + + "uberpr"uft, ob ein Objekt in einem Array gespeichert werden + darf. + Return: 1, wenn es geht + 0, wenn nicht + +******************************************************************************/ + + +s4 builtin_canstore (java_objectarray *a, java_objectheader *o) +{ + if (!o) return 1; + + switch (a->header.arraytype) { + case ARRAYTYPE_OBJECT: + if ( ! builtin_checkcast (o, a->elementtype) ) { + return 0; + } + return 1; + break; + + case ARRAYTYPE_ARRAY: + if ( ! builtin_checkarraycast + (o, ((java_arrayarray*)a)->elementdescriptor) ) { + return 0; + } + return 1; + break; + + default: + panic ("builtin_canstore called with invalid arraytype"); + return 0; + } +} + + + +/***************************************************************************** + ARRAYOPERATIONEN +*****************************************************************************/ + + + +/******************** Funktion: builtin_new ********************************** + + Legt ein neues Objekt einer Klasse am Heap an. + Return: Der Zeiger auf das Objekt, oder NULL, wenn kein Speicher + mehr frei ist. + +*****************************************************************************/ + +java_objectheader *builtin_new (classinfo *c) +{ + java_objectheader *o; + + o = heap_allocate ( c->instancesize, true, c->finalizer ); + if (!o) return NULL; + + memset (o, 0, c->instancesize); + + o -> vftbl = c -> vftbl; + return o; +} + + + +/******************** Funktion: builtin_anewarray **************************** + + Legt ein Array von Zeigern auf Objekte am Heap an. + Parameter: + size ......... Anzahl der Elemente + elementtype .. ein Zeiger auf die classinfo-Struktur des Typs + der Elemente + + Return: Zeiger auf das Array, oder NULL (wenn kein Speicher frei) + +*****************************************************************************/ + +java_objectarray *builtin_anewarray (s4 size, classinfo *elementtype) +{ + s4 i; + java_objectarray *a; + + a = heap_allocate ( sizeof(java_objectarray) + (size-1) * sizeof(void*), + true, 0 /* FALSE */ ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_OBJECT; + a -> elementtype = elementtype; + for (i=0; idata[i] = NULL; + return a; +} + + + +/******************** Funktion: builtin_newarray_array *********************** + + Legt ein Array von Zeigern auf Arrays am Heap an. + Paramter: size ......... Anzahl der Elemente + elementdesc .. Zeiger auf die Arraybeschreibungs-Struktur f"ur + die Element-Arrays. + + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_arrayarray *builtin_newarray_array + (s4 size, constant_arraydescriptor *elementdesc) +{ + s4 i; + java_arrayarray *a; + + a = heap_allocate ( sizeof(java_arrayarray) + (size-1) * sizeof(void*), + true, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_ARRAY; + a -> elementdescriptor = elementdesc; + for (i=0; idata[i] = NULL; + return a; +} + + +/******************** Funktion: builtin_newarray_boolean ************************ + + Legt ein Array von Bytes am Heap an, das allerdings als Boolean-Array + gekennzeichnet wird (wichtig bei Casts!) + + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_booleanarray *builtin_newarray_boolean (s4 size) +{ + java_booleanarray *a; + + a = heap_allocate ( sizeof(java_booleanarray) + (size-1) * sizeof(u1), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_BOOLEAN; + memset (a->data, 0, sizeof(u1) * size); + + return a; +} + +/******************** Funktion: builtin_newarray_char ************************ + + Legt ein Array von 16-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_chararray *builtin_newarray_char (s4 size) +{ + java_chararray *a; + + a = heap_allocate ( sizeof(java_chararray) + (size-1) * sizeof(u2), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_CHAR; + memset (a->data, 0, sizeof(u2) * size); + + return a; +} + + +/******************** Funktion: builtin_newarray_float *********************** + + Legt ein Array von 32-bit-IEEE-float am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_floatarray *builtin_newarray_float (s4 size) +{ + s4 i; + java_floatarray *a; + + a = heap_allocate ( sizeof(java_floatarray) + (size-1) * sizeof(float), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_FLOAT; + for (i=0; idata[i] = 0.0; + return a; +} + + +/******************** Funktion: builtin_newarray_double *********************** + + Legt ein Array von 64-bit-IEEE-float am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_doublearray *builtin_newarray_double (s4 size) +{ + s4 i; + java_doublearray *a; + + a = heap_allocate ( sizeof(java_doublearray) + (size-1) * sizeof(double), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_DOUBLE; + for (i=0; idata[i] = 0.0; + return a; +} + + + + +/******************** Funktion: builtin_newarray_byte *********************** + + Legt ein Array von 8-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_bytearray *builtin_newarray_byte (s4 size) +{ + java_bytearray *a; + + a = heap_allocate ( sizeof(java_bytearray) + (size-1) * sizeof(s1), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array->vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_BYTE; + memset (a->data, 0, sizeof(u1) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_short *********************** + + Legt ein Array von 16-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_shortarray *builtin_newarray_short (s4 size) +{ + java_shortarray *a; + + a = heap_allocate ( sizeof(java_shortarray) + (size-1) * sizeof(s2), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_SHORT; + memset (a->data, 0, sizeof(s2) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_int *********************** + + Legt ein Array von 32-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_intarray *builtin_newarray_int (s4 size) +{ + java_intarray *a; + + a = heap_allocate ( sizeof(java_intarray) + (size-1) * sizeof(s4), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_INT; + memset (a->data, 0, sizeof(s4) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_long *********************** + + Legt ein Array von 64-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_longarray *builtin_newarray_long (s4 size) +{ + java_longarray *a; + + a = heap_allocate ( sizeof(java_longarray) + (size-1) * sizeof(s8), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_LONG; + memset (a->data, 0, sizeof(s8) * size); + return a; +} + + + +/***************** Funktion: builtin_multianewarray *************************** + + Legt ein mehrdimensionales Array am Heap an. + Die Gr"ossen der einzelnen Dimensionen werden in einem Integerarray + "ubergeben. Der Typ es zu erzeugenden Arrays wird als + Referenz auf eine constant_arraydescriptor - Struktur "ubergeben. + + Return: Ein Zeiger auf das Array, oder NULL, wenn kein Speicher mehr + vorhanden ist. + +******************************************************************************/ + + /* Hilfsfunktion */ + +static java_arrayheader *multianewarray_part (java_intarray *dims, int thisdim, + constant_arraydescriptor *desc) +{ + u4 size,i; + java_arrayarray *a; + + size = dims -> data[thisdim]; + + if (thisdim == (dims->header.size-1)) { + /* letzte Dimension schon erreicht */ + + switch (desc -> arraytype) { + case ARRAYTYPE_BOOLEAN: + return (java_arrayheader*) builtin_newarray_boolean (size); + case ARRAYTYPE_CHAR: + return (java_arrayheader*) builtin_newarray_char (size); + case ARRAYTYPE_FLOAT: + return (java_arrayheader*) builtin_newarray_float (size); + case ARRAYTYPE_DOUBLE: + return (java_arrayheader*) builtin_newarray_double (size); + case ARRAYTYPE_BYTE: + return (java_arrayheader*) builtin_newarray_byte (size); + case ARRAYTYPE_SHORT: + return (java_arrayheader*) builtin_newarray_short (size); + case ARRAYTYPE_INT: + return (java_arrayheader*) builtin_newarray_int (size); + case ARRAYTYPE_LONG: + return (java_arrayheader*) builtin_newarray_long (size); + case ARRAYTYPE_OBJECT: + return (java_arrayheader*) builtin_anewarray (size, desc->objectclass); + + case ARRAYTYPE_ARRAY: + return (java_arrayheader*) builtin_newarray_array (size, desc->elementdescriptor); + + default: panic ("Invalid arraytype in multianewarray"); + } + } + + /* wenn letzte Dimension noch nicht erreicht wurde */ + + if (desc->arraytype != ARRAYTYPE_ARRAY) + panic ("multianewarray with too many dimensions"); + + a = builtin_newarray_array (size, desc->elementdescriptor); + if (!a) return NULL; + + for (i=0; ielementdescriptor); + if (!ea) return NULL; + + a -> data[i] = ea; + } + + return (java_arrayheader*) a; +} + + +java_arrayheader *builtin_multianewarray (java_intarray *dims, + constant_arraydescriptor *desc) +{ + return multianewarray_part (dims, 0, desc); +} + + +static java_arrayheader *nmultianewarray_part (int n, long *dims, int thisdim, + constant_arraydescriptor *desc) +{ + int size, i; + java_arrayarray *a; + + size = (int) dims[thisdim]; + + if (thisdim == (n - 1)) { + /* letzte Dimension schon erreicht */ + + switch (desc -> arraytype) { + case ARRAYTYPE_BOOLEAN: + return (java_arrayheader*) builtin_newarray_boolean(size); + case ARRAYTYPE_CHAR: + return (java_arrayheader*) builtin_newarray_char(size); + case ARRAYTYPE_FLOAT: + return (java_arrayheader*) builtin_newarray_float(size); + case ARRAYTYPE_DOUBLE: + return (java_arrayheader*) builtin_newarray_double(size); + case ARRAYTYPE_BYTE: + return (java_arrayheader*) builtin_newarray_byte(size); + case ARRAYTYPE_SHORT: + return (java_arrayheader*) builtin_newarray_short(size); + case ARRAYTYPE_INT: + return (java_arrayheader*) builtin_newarray_int(size); + case ARRAYTYPE_LONG: + return (java_arrayheader*) builtin_newarray_long(size); + case ARRAYTYPE_OBJECT: + return (java_arrayheader*) builtin_anewarray(size, + desc->objectclass); + case ARRAYTYPE_ARRAY: + return (java_arrayheader*) builtin_newarray_array(size, + desc->elementdescriptor); + + default: panic ("Invalid arraytype in multianewarray"); + } + } + + /* wenn letzte Dimension noch nicht erreicht wurde */ + + if (desc->arraytype != ARRAYTYPE_ARRAY) + panic ("multianewarray with too many dimensions"); + + a = builtin_newarray_array(size, desc->elementdescriptor); + if (!a) return NULL; + + for (i = 0; i < size; i++) { + java_arrayheader *ea = + nmultianewarray_part(n, dims, thisdim + 1, desc->elementdescriptor); + if (!ea) return NULL; + + a -> data[i] = ea; + } + + return (java_arrayheader*) a; +} + + +java_arrayheader *builtin_nmultianewarray (int size, + constant_arraydescriptor *desc, long *dims) +{ + (void) builtin_newarray_int(size); /* for compatibility with -old */ + return nmultianewarray_part (size, dims, 0, desc); +} + + + + +/************************* Funktion: builtin_aastore ************************* + + speichert eine Referenz auf ein Objekt in einem Object-Array oder + in einem Array-Array. + Dabei wird allerdings vorher "uberpr"uft, ob diese Operation + zul"assig ist. + + Return: 1, wenn alles OK ist + 0, wenn dieses Objekt nicht in dieses Array gespeichert werden + darf + +*****************************************************************************/ + +s4 builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o) +{ + if (builtin_canstore(a,o)) { + a->data[index] = o; + return 1; + } + return 0; +} + + + + + + +/***************************************************************************** + METHODEN-PROTOKOLLIERUNG + + Verschiedene Funktionen, mit denen eine Meldung ausgegeben werden + kann, wann immer Methoden aufgerufen oder beendet werden. + (f"ur Debug-Zwecke) + +*****************************************************************************/ + + +u4 methodindent=0; + +java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr, + methodinfo *method, int *pos, int noindent) { + + if (!noindent) + methodindent--; + if (verbose || runverbose) { + printf("Exception "); + unicode_display (exceptionptr->vftbl->class->name); + printf(" thrown in "); + if (method) { + unicode_display (method->class->name); + printf("."); + unicode_display (method->name); + if (method->flags & ACC_SYNCHRONIZED) + printf("(SYNC)"); + else + printf("(NOSYNC)"); + printf("(%p) at position %p\n", method->entrypoint, pos); + } + else + printf("call_java_method\n"); + fflush (stdout); + } + return exceptionptr; +} + + +void builtin_trace_args(long a0, long a1, long a2, long a3, long a4, long a5, + methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "called: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + sprintf (logtext+strlen(logtext), "("); + switch (method->paramcount) { + case 6: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx, %lx, %lx", + a0, a1, a2, a3, a4, a5); + break; + case 5: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx, %lx", + a0, a1, a2, a3, a4); + break; + case 4: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx", + a0, a1, a2, a3); + break; + case 3: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx", a0, a1, a2); + break; + case 2: + sprintf(logtext+strlen(logtext), "%lx, %lx", a0, a1); + break; + case 1: + sprintf(logtext+strlen(logtext), "%lx", a0); + break; + } + sprintf (logtext+strlen(logtext), ")"); + + dolog (); + methodindent++; +} + +void builtin_displaymethodstart(methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "called: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + dolog (); + methodindent++; +} + +void builtin_displaymethodstop(methodinfo *method, long l, double d) +{ + methodindent--; + sprintf (logtext, " "); + sprintf (logtext+methodindent, "finished: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + switch (method->returntype) { + case TYPE_INT: + case TYPE_LONG: + sprintf (logtext+strlen(logtext), "->%ld", l); + break; + case TYPE_FLOAT: + case TYPE_DOUBLE: + sprintf (logtext+strlen(logtext), "->%g", d); + break; + case TYPE_ADDRESS: + sprintf (logtext+strlen(logtext), "->%p", (void*) l); + break; + } + dolog (); +} + +void builtin_displaymethodexception(methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "exception abort: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + dolog (); +} + + +/**************************************************************************** + SYNCHRONIZATION FUNCTIONS +*****************************************************************************/ + +/* + * Lock the mutex of an object. + */ +#ifdef USE_THREADS +void +internal_lock_mutex_for_object (java_objectheader *object) +{ + mutexHashEntry *entry; + int hashValue; + + assert(object != 0); + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object != 0) + { + if (entry->mutex.count == 0 && entry->conditionCount == 0) + { + entry->object = 0; + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + else + { + while (entry->next != 0 && entry->object != object) + entry = entry->next; + + if (entry->object != object) + { + entry->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = firstFreeOverflowEntry->next; + + entry = entry->next; + entry->object = 0; + entry->next = 0; + assert(entry->conditionCount == 0); + } + } + } + else + { + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + + if (entry->object == 0) + entry->object = object; + + internal_lock_mutex(&entry->mutex); +} +#endif + + +/* + * Unlocks the mutex of an object. + */ +#ifdef USE_THREADS +void +internal_unlock_mutex_for_object (java_objectheader *object) +{ + int hashValue; + mutexHashEntry *entry; + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object == object) + internal_unlock_mutex(&entry->mutex); + else + { + while (entry->next != 0 && entry->next->object != object) + entry = entry->next; + + assert(entry->next != 0); + + internal_unlock_mutex(&entry->next->mutex); + + if (entry->next->mutex.count == 0 && entry->conditionCount == 0) + { + mutexHashEntry *unlinked = entry->next; + + entry->next = unlinked->next; + unlinked->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = unlinked; + } + } +} +#endif + +void +builtin_monitorenter (java_objectheader *o) +{ +#ifdef USE_THREADS + int hashValue; + + assert(blockInts == 0); + + ++blockInts; + + hashValue = MUTEX_HASH_VALUE(o); + if (mutexHashTable[hashValue].object == o + && mutexHashTable[hashValue].mutex.holder == currentThread) + ++mutexHashTable[hashValue].mutex.count; + else + internal_lock_mutex_for_object(o); + + --blockInts; + + assert(blockInts == 0); +#endif +} + +void builtin_monitorexit (java_objectheader *o) +{ +#ifdef USE_THREADS + int hashValue; + + assert(blockInts == 0); + + ++blockInts; + + hashValue = MUTEX_HASH_VALUE(o); + if (mutexHashTable[hashValue].object == o) + { + if (mutexHashTable[hashValue].mutex.count == 1 + && mutexHashTable[hashValue].mutex.muxWaiters != 0) + internal_unlock_mutex_for_object(o); + else + --mutexHashTable[hashValue].mutex.count; + } + else + internal_unlock_mutex_for_object(o); + + --blockInts; + + assert(blockInts == 0); +#endif +} + + +/***************************************************************************** + DIVERSE HILFSFUNKTIONEN +*****************************************************************************/ + + + +/*********** Funktionen f"ur die Integerdivision ***************************** + + Auf manchen Systemen (z.B. DEC ALPHA) wird durch die CPU keine Integer- + division unterst"utzt. + Daf"ur gibt es dann diese Hilfsfunktionen + +******************************************************************************/ + +s4 builtin_idiv (s4 a, s4 b) { return a/b; } +s4 builtin_irem (s4 a, s4 b) { return a%b; } + + +/************** Funktionen f"ur Long-Arithmetik ******************************* + + Auf Systemen, auf denen die CPU keine 64-Bit-Integers unterst"utzt, + werden diese Funktionen gebraucht + +******************************************************************************/ + + +s8 builtin_ladd (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a+b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lsub (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a-b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lmul (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a*b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_ldiv (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a/b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lrem (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a%b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lshl (s8 a, s4 b) +{ +#if U8_AVAILABLE + return a<<(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lshr (s8 a, s4 b) +{ +#if U8_AVAILABLE + return a>>(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lushr (s8 a, s4 b) +{ +#if U8_AVAILABLE + return ((u8)a)>>(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_land (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a&b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lor (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a|b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lxor (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a^b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lneg (s8 a) +{ +#if U8_AVAILABLE + return -a; +#else + return builtin_i2l(0); +#endif +} + +s4 builtin_lcmp (s8 a, s8 b) +{ +#if U8_AVAILABLE + if (ab) return 1; + return 0; +#else + return 0; +#endif +} + + + + + +/*********** Funktionen f"ur die Floating-Point-Operationen ******************/ + +float builtin_fadd (float a, float b) +{ + if (isnanf(a)) return FLT_NAN; + if (isnanf(b)) return FLT_NAN; + if (finitef(a)) { + if (finitef(b)) return a+b; + else return b; + } + else { + if (finitef(b)) return a; + else { + if (copysignf(1.0, a)==copysignf(1.0, b)) return a; + else return FLT_NAN; + } + } +} + +float builtin_fsub (float a, float b) +{ + return builtin_fadd (a, builtin_fneg(b)); +} + +float builtin_fmul (float a, float b) +{ + if (isnanf(a)) return FLT_NAN; + if (isnanf(b)) return FLT_NAN; + if (finitef(a)) { + if (finitef(b)) return a*b; + else { + if (a==0) return FLT_NAN; + else return copysignf(b, copysignf(1.0, b)*a); + } + } + else { + if (finitef(b)) { + if (b==0) return FLT_NAN; + else return copysignf(a, copysignf(1.0, a)*b); + } + else { + return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b)); + } + } +} + +float builtin_fdiv (float a, float b) +{ + if (finitef(a) && finitef(b)) { + if (b != 0) + return a / b; + else { + if (a > 0) + return FLT_POSINF; + else if (a < 0) + return FLT_NEGINF; + } + } + return FLT_NAN; +} + +float builtin_frem (float a, float b) +{ + +/* return (float) builtin_drem((double) a, (double) b); */ + + float f; + + if (finite((double) a) && finite((double) b)) { + f = a / b; + if (finite((double) f)) + return fmodf(a, b); + return FLT_NAN; + } + if (isnan((double) b)) + return FLT_NAN; + if (finite((double) a)) + return a; + return FLT_NAN; + +/* float f; + + if (finitef(a) && finitef(b)) { + f = a / b; + if (finitef(f)) + return a - floorf(f) * b; + return FLT_NAN; + } + if (isnanf(b)) + return FLT_NAN; + if (finitef(a)) + return a; + return FLT_NAN; */ +} + + +float builtin_fneg (float a) +{ + if (isnanf(a)) return a; + else { + if (finitef(a)) return -a; + else return copysignf(a,-copysignf(1.0, a)); + } +} + +s4 builtin_fcmpl (float a, float b) +{ + if (isnanf(a)) return -1; + if (isnanf(b)) return -1; + if (!finitef(a) || !finitef(b)) { + a = finitef(a) ? 0 : copysignf(1.0, a); + b = finitef(b) ? 0 : copysignf(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + +s4 builtin_fcmpg (float a, float b) +{ + if (isnanf(a)) return 1; + if (isnanf(b)) return 1; + if (!finitef(a) || !finitef(b)) { + a = finitef(a) ? 0 : copysignf(1.0, a); + b = finitef(b) ? 0 : copysignf(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + + + +/*********** Funktionen f"ur doppelt genaue Fliesskommazahlen ***************/ + +double builtin_dadd (double a, double b) +{ + if (isnan(a)) return DBL_NAN; + if (isnan(b)) return DBL_NAN; + if (finite(a)) { + if (finite(b)) return a+b; + else return b; + } + else { + if (finite(b)) return a; + else { + if (copysign(1.0, a)==copysign(1.0, b)) return a; + else return DBL_NAN; + } + } +} + +double builtin_dsub (double a, double b) +{ + return builtin_dadd (a, builtin_dneg(b)); +} + +double builtin_dmul (double a, double b) +{ + if (isnan(a)) return DBL_NAN; + if (isnan(b)) return DBL_NAN; + if (finite(a)) { + if (finite(b)) return a*b; + else { + if (a==0) return DBL_NAN; + else return copysign(b, copysign(1.0, b)*a); + } + } + else { + if (finite(b)) { + if (b==0) return DBL_NAN; + else return copysign(a, copysign(1.0, a)*b); + } + else { + return copysign(a, copysign(1.0, a)*copysign(1.0, b)); + } + } +} + +double builtin_ddiv (double a, double b) +{ + if (finite(a) && finite(b)) { + if (b != 0) + return a / b; + else { + if (a > 0) + return DBL_POSINF; + else if (a < 0) + return DBL_NEGINF; + } + } + return DBL_NAN; +} + +double builtin_drem (double a, double b) +{ + double d; + + if (finite(a) && finite(b)) { + d = a / b; + if (finite(d)) { + if ((d < 1.0) && (d > 0.0)) + return a; + return fmod(a, b); + } + return DBL_NAN; + } + if (isnan(b)) + return DBL_NAN; + if (finite(a)) + return a; + return DBL_NAN; +} + +double builtin_dneg (double a) +{ + if (isnan(a)) return a; + else { + if (finite(a)) return -a; + else return copysign(a,-copysign(1.0, a)); + } +} + +s4 builtin_dcmpl (double a, double b) +{ + if (isnan(a)) return -1; + if (isnan(b)) return -1; + if (!finite(a) || !finite(b)) { + a = finite(a) ? 0 : copysign(1.0, a); + b = finite(b) ? 0 : copysign(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + +s4 builtin_dcmpg (double a, double b) +{ + if (isnan(a)) return 1; + if (isnan(b)) return 1; + if (!finite(a) || !finite(b)) { + a = finite(a) ? 0 : copysign(1.0, a); + b = finite(b) ? 0 : copysign(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + + +/*********************** Umwandlungsoperationen ****************************/ + +s8 builtin_i2l (s4 i) +{ +#if U8_AVAILABLE + return i; +#else + s8 v; v.high = 0; v.low=i; return v; +#endif +} + +float builtin_i2f (s4 a) +{ +float f = (float) a; +return f; +} + +double builtin_i2d (s4 a) +{ +double d = (double) a; +return d; +} + + +s4 builtin_l2i (s8 l) +{ +#if U8_AVAILABLE + return (s4) l; +#else + return l.low; +#endif +} + +float builtin_l2f (s8 a) +{ +#if U8_AVAILABLE + float f = (float) a; + return f; +#else + return 0.0; +#endif +} + +double builtin_l2d (s8 a) +{ +#if U8_AVAILABLE + double d = (double) a; + return d; +#else + return 0.0; +#endif +} + + +s4 builtin_f2i(float a) +{ + +return builtin_d2i((double) a); + +/* float f; + + if (isnanf(a)) + return 0; + if (finitef(a)) { + if (a > 2147483647) + return 2147483647; + if (a < (-2147483648)) + return (-2147483648); + return (s4) a; + } + f = copysignf((float) 1.0, a); + if (f > 0) + return 2147483647; + return (-2147483648); */ +} + + +s8 builtin_f2l (float a) +{ + +return builtin_d2l((double) a); + +/* float f; + + if (finitef(a)) { + if (a > 9223372036854775807L) + return 9223372036854775807L; + if (a < (-9223372036854775808L)) + return (-9223372036854775808L); + return (s8) a; + } + if (isnanf(a)) + return 0; + f = copysignf((float) 1.0, a); + if (f > 0) + return 9223372036854775807L; + return (-9223372036854775808L); */ +} + + +double builtin_f2d (float a) +{ + if (finitef(a)) return (double) a; + else { + if (isnanf(a)) return DBL_NAN; + else return copysign(DBL_POSINF, (double) copysignf(1.0, a) ); + } +} + + +s4 builtin_d2i (double a) +{ + double d; + + if (finite(a)) { + if (a >= 2147483647) + return 2147483647; + if (a <= (-2147483648)) + return (-2147483648); + return (s4) a; + } + if (isnan(a)) + return 0; + d = copysign(1.0, a); + if (d > 0) + return 2147483647; + return (-2147483648); +} + + +s8 builtin_d2l (double a) +{ + double d; + + if (finite(a)) { + if (a >= 9223372036854775807L) + return 9223372036854775807L; + if (a <= (-9223372036854775807L-1)) + return (-9223372036854775807L-1); + return (s8) a; + } + if (isnan(a)) + return 0; + d = copysign(1.0, a); + if (d > 0) + return 9223372036854775807L; + return (-9223372036854775807L-1); +} + + +float builtin_d2f (double a) +{ + if (finite(a)) return (float) a; + else { + if (isnan(a)) return FLT_NAN; + else return copysignf (FLT_POSINF, (float) copysign(1.0, a)); + } +} + diff --git a/builtin.h b/builtin.h new file mode 100644 index 000000000..b52afb437 --- /dev/null +++ b/builtin.h @@ -0,0 +1,125 @@ +/****************************** builtin.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the prototypes for the functions of file builtin.c which has + a more detailed description. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + +/***************************** Prototypes *************************************/ + +typedef struct builtin_descriptor { + functionptr bptr; + char *name; + } builtin_descriptor; + +extern builtin_descriptor builtin_desc[]; + +s4 builtin_instanceof(java_objectheader *obj, classinfo *class); +s4 builtin_checkcast(java_objectheader *obj, classinfo *class); +s4 new_builtin_checkcast(java_objectheader *obj, classinfo *class); +s4 builtin_arrayinstanceof + (java_objectheader *obj, constant_arraydescriptor *desc); +s4 builtin_checkarraycast + (java_objectheader *obj, constant_arraydescriptor *desc); +s4 new_builtin_checkarraycast + (java_objectheader *obj, constant_arraydescriptor *desc); + +java_objectheader *builtin_throw_exception (java_objectheader *exception); +java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr, + methodinfo *method, int *pos, int noindent); + +java_objectheader *builtin_new (classinfo *c); + + +java_objectarray *builtin_anewarray (s4 size, classinfo *elementtype); +java_arrayarray *builtin_newarray_array + (s4 size, constant_arraydescriptor *elementdesc); +java_booleanarray *builtin_newarray_boolean (s4 size); +java_chararray *builtin_newarray_char (s4 size); +java_floatarray *builtin_newarray_float (s4 size); +java_doublearray *builtin_newarray_double (s4 size); +java_bytearray *builtin_newarray_byte (s4 size); +java_shortarray *builtin_newarray_short (s4 size); +java_intarray *builtin_newarray_int (s4 size); +java_longarray *builtin_newarray_long (s4 size); +java_arrayheader *builtin_multianewarray (java_intarray *dims, + constant_arraydescriptor *desc); +java_arrayheader *builtin_nmultianewarray (int size, + constant_arraydescriptor *desc, long *dims); + +s4 builtin_canstore (java_objectarray *a, java_objectheader *o); +s4 builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o); +void new_builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o); + +void builtin_trace_args(long a0, long a1, long a2, long a3, long a4, long a5, methodinfo *method); +void builtin_displaymethodstart(methodinfo *method); +void builtin_displaymethodstop(methodinfo *method, long l, double d); +/* void builtin_displaymethodstop(methodinfo *method); */ +void builtin_displaymethodexception(methodinfo *method); + +void builtin_monitorenter (java_objectheader *o); +void new_builtin_monitorenter (java_objectheader *o); +void builtin_monitorexit (java_objectheader *o); +void new_builtin_monitorexit (java_objectheader *o); + +s4 builtin_idiv (s4 a, s4 b); +s4 new_builtin_idiv (s4 a, s4 b); +s4 builtin_irem (s4 a, s4 b); +s4 new_builtin_irem (s4 a, s4 b); + +s8 builtin_ladd (s8 a, s8 b); +s8 builtin_lsub (s8 a, s8 b); +s8 builtin_lmul (s8 a, s8 b); +s8 builtin_ldiv (s8 a, s8 b); +s8 new_builtin_ldiv (s8 a, s8 b); +s8 builtin_lrem (s8 a, s8 b); +s8 new_builtin_lrem (s8 a, s8 b); +s8 builtin_lshl (s8 a, s4 b); +s8 builtin_lshr (s8 a, s4 b); +s8 builtin_lushr (s8 a, s4 b); +s8 builtin_land (s8 a, s8 b); +s8 builtin_lor (s8 a, s8 b); +s8 builtin_lxor (s8 a, s8 b); +s8 builtin_lneg (s8 a); +s4 builtin_lcmp (s8 a, s8 b); + +float builtin_fadd (float a, float b); +float builtin_fsub (float a, float b); +float builtin_fmul (float a, float b); +float builtin_fdiv (float a, float b); +float builtin_frem (float a, float b); +float builtin_fneg (float a); +s4 builtin_fcmpl (float a, float b); +s4 builtin_fcmpg (float a, float b); + +double builtin_dadd (double a, double b); +double builtin_dsub (double a, double b); +double builtin_dmul (double a, double b); +double builtin_ddiv (double a, double b); +double builtin_drem (double a, double b); +double builtin_dneg (double a); +s4 builtin_dcmpl (double a, double b); +s4 builtin_dcmpg (double a, double b); + +s8 builtin_i2l (s4 i); +float builtin_i2f (s4 i); +double builtin_i2d (s4 i); +s4 builtin_l2i (s8 l); +float builtin_l2f (s8 l); +double builtin_l2d (s8 l); +s4 builtin_f2i (float a); +s8 builtin_f2l (float a); +double builtin_f2d (float a); +s4 builtin_d2i (double a); +s8 builtin_d2l (double a); +float builtin_d2f (double a); + diff --git a/callargs.h b/callargs.h new file mode 100644 index 000000000..514437582 --- /dev/null +++ b/callargs.h @@ -0,0 +1 @@ +#define TRACECALLARGS diff --git a/comp/block.c b/comp/block.c new file mode 100644 index 000000000..813c88cdb --- /dev/null +++ b/comp/block.c @@ -0,0 +1,405 @@ +/***************************** comp/block.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Basic block handling functions. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/01/18 + +*******************************************************************************/ + + +static u2 creatornum; /* Fortlaufende Nummerierung f"ur vom Compiler + generierte BasicBlocks (nur zu Debug-Zwecken) */ + +static subroutineinfo *actual_subroutine; +static u2 subroutinecounter=0; + + +/********************** Funktion: block_new *********************************** + + erzeugt eine neue 'basicblock'-Struktur und initialisiert alle + Komponenten + +******************************************************************************/ + +static basicblock *block_new (u2 type, u4 codepos) +{ + basicblock *b = DNEW (basicblock); + + b -> type = type; + b -> reached = false; + b -> finished = false; + b -> subroutine = NULL; + b -> jpc = codepos; + b -> stack = NULL; + list_init (&(b->pcmdlist), OFFSET (pcmd, linkage) ); + b -> mpc = 0; + + b -> exproto = NULL; + b -> throwpos = 0; + return b; +} + + + +/******************* Funktion: block_find ************************************* + + Sucht den Basicblock, der an einer gew"unschten Stelle im JavaVM-Code + anf"angt. + Wenn dort kein Block anf"angt -> Fehler + +******************************************************************************/ + +static basicblock *block_find (u4 codepos) +{ + basicblock *b = blocks[codepos]; + if (!b) panic ("Accessed JAVA-Command on no block boundary"); + return b; +} + + +/****************** Funktion: block_isany ************************************* + + "uberpr"uft, ob an einer Stelle ein Basicblock anf"angt + +******************************************************************************/ + +static bool block_isany (u4 codepos) +{ + return (blocks[codepos] != NULL); +} + + +/***************** Funktion: block_reach ************************************** + + H"angt einen Basicblock in die Liste der schon erreichten Bl"ocke ein, + und setzt seinen Blockeintrittsstack auf den aktuellen Stack und + setzt den Unterprogramminfoblock auf das aktuelle Unterprogramminfo + + Wenn der Block bereits vorher als erreicht markiert war (und er deshalb + schon einen definierten Stack hatte), dann wird im derzeit vom + Parser durchlaufenen Block (also dort, von wo dieser Block aus + angesprungen wird) ein entsprechende Codest"uck hinzugef"ugt, der + die beiden Stacks aufeinander abstimmt. + +******************************************************************************/ + +static void block_reach (basicblock *b) +{ + if (!b->reached) { + list_addlast (&reachedblocks, b); + b -> reached = true; + b -> subroutine = actual_subroutine; + b -> stack = stack_get(); + } + else { + if (b->subroutine != actual_subroutine) + panic ("Try to merge different subroutines"); + stack_addjoincode (b->stack); + } +} + +/*********************** Funktion: subroutine_set ***************************** + + setzt den aktuellen Subroutine-Infoblock + +*******************************************************************************/ + +static void subroutine_set (subroutineinfo *s) +{ + actual_subroutine = s; +} + + + +/*********************** Funktion: subroutine_new ***************************** + + erzeugt einen neuen Subroutine-Infoblock + +*******************************************************************************/ + +static subroutineinfo *subroutine_new () +{ + subroutineinfo *s = DNEW (subroutineinfo); + s -> returnfinished = false; + s -> returnstack = NULL; + s -> callers = chain_dnew(); + s -> counter = subroutinecounter++; + return s; +} + + + + + + +/********************** Funktion: block_insert ******************************** + + Erzeugt einen neuen Block, der an einer gew"unschten JavaVM-Code- Stelle + anf"angt. + Der Zeiger auf diesen Block wird im (globalen) 'blocks'-Array + abgelegt. + +******************************************************************************/ + +static void block_insert (u4 codepos) +{ + if (codepos>=jcodelength) { + sprintf (logtext,"Basic block border (%d) out of bounds",(int) codepos); + error (); + } + + if (blocks[codepos]) return; + + blocks[codepos] = block_new (BLOCKTYPE_JAVA, codepos); +} + + + +/******************** Funktion: block_createexcreator ************************* + + erzeugt einen neuen Basicblock vom Typ EXCREATOR (=Exception Creator) + +******************************************************************************/ + +static basicblock *block_createexcreator (java_objectheader *exproto, u4 throwpos) +{ + basicblock *b; + + b = block_new (BLOCKTYPE_EXCREATOR, creatornum++); + + b -> reached = true; + list_addlast (&reachedblocks, b); + b -> subroutine = actual_subroutine; + b -> exproto = exproto; + b -> throwpos = throwpos; + return b; +} + + +/******************* Funktion: block_createexforwarder *********************** + + erzeugt einen neuen Basicblock vom Typ EXFORWARDER (=Exception Forwarder) + +*****************************************************************************/ + +static basicblock *block_createexforwarder (varid exvar, u4 throwpos) +{ + basicblock *b; + + b = block_new (BLOCKTYPE_EXFORWARDER, creatornum++); + + b -> reached = true; + list_addlast (&reachedblocks, b); + b -> subroutine = actual_subroutine; + b -> exvar = exvar; + b -> throwpos = throwpos; + return b; +} + + +/********************** Funktion: block_genmcode ****************************** + + generiert f"ur einen vom Parser fertig abgearbeiteten Block den + Maschinencode. + Hintereinanderliegende Bl"ocke durch die der Kontrollflu"s ohne + Sprungbefehle durchgeht, m"ussen hier auch hintereinander + abgearbeitet werden. + +******************************************************************************/ + +/* definition of block_genmcode moved to gen.c for inlining by andi */ + + +/************************ Funktion: block_firstscann ************************** + + Liest den JavaVM-Code der ganzen Methode durch und erzeugt soviele + neue Bl"ocke, wie es verschiedene Sprungziele gibt. + +******************************************************************************/ + +static void block_firstscann () +{ + u4 p,nextp; + int i; + u1 opcode; + bool blockend; + + + creatornum=10001; + + + block_insert (0); + + for (i=0; i jcodelength) panic ("Command-sequence crosses code-boundary"); + p = nextp; + } + + if (!blockend) panic ("Code does not end with branch/return/athrow - stmt"); + +} + + + +/************* Funktion: block_display (nur zu Debug-Zwecken) ****************/ + +void block_display (basicblock *b) +{ + pcmd *p; + + if (b->subroutine) { + printf ("\n%ld in subroutine: %d", (long int) b->jpc, (int) b->subroutine->counter); + } + else { + printf ("\n%ld:", (long int) b->jpc); + } + + switch (b->type) { + case BLOCKTYPE_JAVA: printf ("(JavaVM code)\n"); break; + case BLOCKTYPE_EXCREATOR: printf ("(Exception creator)\n"); break; + case BLOCKTYPE_EXFORWARDER: printf ("(Exception forwarder)\n"); break; + } + + printf ("binding of stack: "); + stack_display (b->stack); printf ("\n"); + + p = list_first (&(b->pcmdlist)); + while (p) { + pcmd_display (p); + p = list_next (&(b->pcmdlist), p); + } +} + + diff --git a/comp/defines.c b/comp/defines.c new file mode 100644 index 000000000..09987a6ef --- /dev/null +++ b/comp/defines.c @@ -0,0 +1,772 @@ +/******************************** comp/defines.c ******************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + defines all the constants and data structures of the compiler + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Michael Gschwind EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/09/22 + +*******************************************************************************/ + +#include "../sysdep/types.h" + +/*********************** resolve typedef-cycles *******************************/ + +typedef struct stackinfo stackinfo; +typedef struct basicblock basicblock; +typedef struct varinfo varinfo; +typedef struct subroutineinfo subroutineinfo; + + +/***************************** basic block structure **************************/ + +#define BLOCKTYPE_JAVA 1 +#define BLOCKTYPE_EXCREATOR 2 +#define BLOCKTYPE_EXFORWARDER 3 + +/* there are three kinds of basic blocks: + JAVA ........ block which contains JavaVM code (normal case) + EXCREATOR ... block which creates an exception and calls the handler + EXFORWARDER .. block which does the dispatching to all possible handlers +*/ + +struct basicblock { + u2 type; /* block type */ + bool reached; /* true, when block has been reached; the field stack + contains the stack valid before entering block */ + bool finished; /* true, if 'pcmdlist' is finished */ + subroutineinfo *subroutine; /* info about blocks reachable by JSR */ + listnode linkage; /* list chaining */ + u4 jpc; /* JavaVM program counter at start of block */ + stackinfo *stack; /* stack description */ + list pcmdlist; /* list of pseudo commands */ + u4 mpc; /* program counter within compiled machine code */ + java_objectheader *exproto; + /* if (type==EXCREATOR) contains pointer to exception + raising object */ + varinfo *exvar; /* if (type==EXFORWARDER) contains exception variable */ + u4 throwpos; /* if (type!=JAVA) contains position in program where + the exception was raised */ + }; + + +/***************************** subroutine structure ***************************/ + +struct subroutineinfo { + bool returnfinished; /* true if return allready has been processed */ + + stackinfo *returnstack; /* stack structure at position of return */ + chain *callers; /* a list of all callers */ + u2 counter; + }; + + +/************************** stack element structure ***************************/ + +struct stackinfo { + stackinfo *prev; /* pointer to next element towards bootom */ + varinfo *var; /* pointer to variable which contains this value */ + }; + + +/************************* pseudo variable structure **************************/ + +struct varinfo { + listnode linkage; /* list chaining */ + + u2 type; /* basic type of variable */ + u2 number; /* sequential numbering (used for debugging) */ + + bool saved; /* true if variable sould survive subroutine calls */ + + struct reginfo *reg; /* registerused by variable */ + + /* temporary fields used during parsing */ + + list copies; /* list of all variables which are copies */ + listnode copylink; /* chaining for copy list */ + varinfo *original; /* pointer to original variable (self reference + is possible) */ + + bool globalscope; /* true if variable is activ in whole subroutine */ + bool active; /* true if variable is currently active (parsing + a block where the variable is valid ) */ + }; + + +typedef varinfo *varid; + +#define NOVAR NULL + + +/************************** pseudo command structure **************************/ + +/* pseudo command tags */ + +#define TAG_LOADCONST_I 1 /* load integer constant */ +#define TAG_LOADCONST_L 2 /* load long constant */ +#define TAG_LOADCONST_F 3 /* load float constant */ +#define TAG_LOADCONST_D 4 /* load double constant */ +#define TAG_LOADCONST_A 5 /* load address constant */ +#define TAG_MOVE 6 +#define TAG_OP 7 +#define TAG_MEM 8 +#define TAG_BRA 9 +#define TAG_TABLEJUMP 10 +#define TAG_METHOD 11 +#define TAG_DROP 12 +#define TAG_ACTIVATE 13 + + +typedef struct pcmd { + listnode linkage; /* list chaining */ + int tag; /* kind of pseudo command */ + int opcode; /* opcode and kind of pseudo command */ + + varinfo *dest; /* optional destination operand */ + varinfo *source1; /* 3 optional source operands */ + varinfo *source2; + varinfo *source3; + + union { + struct { /* load integer constant */ + s4 value; + } i; + struct { /* load long constant */ + s8 value; + } l; + struct { /* load float constant */ + float value; + } f; + struct { /* load double constant */ + double value; + } d; + struct { /* load address constant */ + voidptr value; + } a; + + struct { /* move */ + u2 type; /* type of value */ + } move; + + struct { /* memory access (load/store) */ + int type; /* access type */ + u4 offset; /* offset relative to base register */ + } mem; + + struct { /* branch */ + basicblock *target; /* branch target */ + } bra; + + struct { /* branch using table */ + u4 targetcount; /* number of entries */ + basicblock **targets; /* branch target */ + } tablejump; + + struct { /* method call */ + methodinfo *method; /* pointer to 'methodinfo'-structure */ + functionptr builtin; /* C function pointer or NULL */ + u2 paramnum; /* number of parameters */ + varid *params; /* table of parameter variables */ + varid exceptionvar; /* exception variable */ + } method; + + } u; + + } pcmd; + + + + + + +/***************** forward references in branch instructions ******************/ + +typedef struct mcodereference { + listnode linkage; /* list chaining */ + + bool incode; /* true if code address, false if data address */ + s4 msourcepos; /* patching position in code/data segment */ + basicblock *target; /* target basic block */ + } mcodereference; + + + + +/********** JavaVM operation codes (sortet) and instruction lengths ***********/ + +u1 jcommandsize[256] = { + +#define CMD_NOP 0 + 1, +#define CMD_ACONST_NULL 1 + 1, +#define CMD_ICONST_M1 2 + 1, +#define CMD_ICONST_0 3 + 1, +#define CMD_ICONST_1 4 + 1, +#define CMD_ICONST_2 5 + 1, +#define CMD_ICONST_3 6 + 1, +#define CMD_ICONST_4 7 + 1, +#define CMD_ICONST_5 8 + 1, +#define CMD_LCONST_0 9 + 1, +#define CMD_LCONST_1 10 + 1, +#define CMD_FCONST_0 11 + 1, +#define CMD_FCONST_1 12 + 1, +#define CMD_FCONST_2 13 + 1, +#define CMD_DCONST_0 14 + 1, +#define CMD_DCONST_1 15 + 1, +#define CMD_BIPUSH 16 + 2, +#define CMD_SIPUSH 17 + 3, +#define CMD_LDC1 18 + 2, +#define CMD_LDC2 19 + 3, +#define CMD_LDC2W 20 + 3, +#define CMD_ILOAD 21 + 2, +#define CMD_LLOAD 22 + 2, +#define CMD_FLOAD 23 + 2, +#define CMD_DLOAD 24 + 2, +#define CMD_ALOAD 25 + 2, +#define CMD_ILOAD_0 26 + 1, +#define CMD_ILOAD_1 27 + 1, +#define CMD_ILOAD_2 28 + 1, +#define CMD_ILOAD_3 29 + 1, +#define CMD_LLOAD_0 30 + 1, +#define CMD_LLOAD_1 31 + 1, +#define CMD_LLOAD_2 32 + 1, +#define CMD_LLOAD_3 33 + 1, +#define CMD_FLOAD_0 34 + 1, +#define CMD_FLOAD_1 35 + 1, +#define CMD_FLOAD_2 36 + 1, +#define CMD_FLOAD_3 37 + 1, +#define CMD_DLOAD_0 38 + 1, +#define CMD_DLOAD_1 39 + 1, +#define CMD_DLOAD_2 40 + 1, +#define CMD_DLOAD_3 41 + 1, +#define CMD_ALOAD_0 42 + 1, +#define CMD_ALOAD_1 43 + 1, +#define CMD_ALOAD_2 44 + 1, +#define CMD_ALOAD_3 45 + 1, +#define CMD_IALOAD 46 + 1, +#define CMD_LALOAD 47 + 1, +#define CMD_FALOAD 48 + 1, +#define CMD_DALOAD 49 + 1, +#define CMD_AALOAD 50 + 1, +#define CMD_BALOAD 51 + 1, +#define CMD_CALOAD 52 + 1, +#define CMD_SALOAD 53 + 1, +#define CMD_ISTORE 54 + 2, +#define CMD_LSTORE 55 + 2, +#define CMD_FSTORE 56 + 2, +#define CMD_DSTORE 57 + 2, +#define CMD_ASTORE 58 + 2, +#define CMD_ISTORE_0 59 + 1, +#define CMD_ISTORE_1 60 + 1, +#define CMD_ISTORE_2 61 + 1, +#define CMD_ISTORE_3 62 + 1, +#define CMD_LSTORE_0 63 + 1, +#define CMD_LSTORE_1 64 + 1, +#define CMD_LSTORE_2 65 + 1, +#define CMD_LSTORE_3 66 + 1, +#define CMD_FSTORE_0 67 + 1, +#define CMD_FSTORE_1 68 + 1, +#define CMD_FSTORE_2 69 + 1, +#define CMD_FSTORE_3 70 + 1, +#define CMD_DSTORE_0 71 + 1, +#define CMD_DSTORE_1 72 + 1, +#define CMD_DSTORE_2 73 + 1, +#define CMD_DSTORE_3 74 + 1, +#define CMD_ASTORE_0 75 + 1, +#define CMD_ASTORE_1 76 + 1, +#define CMD_ASTORE_2 77 + 1, +#define CMD_ASTORE_3 78 + 1, +#define CMD_IASTORE 79 + 1, +#define CMD_LASTORE 80 + 1, +#define CMD_FASTORE 81 + 1, +#define CMD_DASTORE 82 + 1, +#define CMD_AASTORE 83 + 1, +#define CMD_BASTORE 84 + 1, +#define CMD_CASTORE 85 + 1, +#define CMD_SASTORE 86 + 1, +#define CMD_POP 87 + 1, +#define CMD_POP2 88 + 1, +#define CMD_DUP 89 + 1, +#define CMD_DUP_X1 90 + 1, +#define CMD_DUP_X2 91 + 1, +#define CMD_DUP2 92 + 1, +#define CMD_DUP2_X1 93 + 1, +#define CMD_DUP2_X2 94 + 1, +#define CMD_SWAP 95 + 1, +#define CMD_IADD 96 + 1, +#define CMD_LADD 97 + 1, +#define CMD_FADD 98 + 1, +#define CMD_DADD 99 + 1, +#define CMD_ISUB 100 + 1, +#define CMD_LSUB 101 + 1, +#define CMD_FSUB 102 + 1, +#define CMD_DSUB 103 + 1, +#define CMD_IMUL 104 + 1, +#define CMD_LMUL 105 + 1, +#define CMD_FMUL 106 + 1, +#define CMD_DMUL 107 + 1, +#define CMD_IDIV 108 + 1, +#define CMD_LDIV 109 + 1, +#define CMD_FDIV 110 + 1, +#define CMD_DDIV 111 + 1, +#define CMD_IREM 112 + 1, +#define CMD_LREM 113 + 1, +#define CMD_FREM 114 + 1, +#define CMD_DREM 115 + 1, +#define CMD_INEG 116 + 1, +#define CMD_LNEG 117 + 1, +#define CMD_FNEG 118 + 1, +#define CMD_DNEG 119 + 1, +#define CMD_ISHL 120 + 1, +#define CMD_LSHL 121 + 1, +#define CMD_ISHR 122 + 1, +#define CMD_LSHR 123 + 1, +#define CMD_IUSHR 124 + 1, +#define CMD_LUSHR 125 + 1, +#define CMD_IAND 126 + 1, +#define CMD_LAND 127 + 1, +#define CMD_IOR 128 + 1, +#define CMD_LOR 129 + 1, +#define CMD_IXOR 130 + 1, +#define CMD_LXOR 131 + 1, +#define CMD_IINC 132 + 3, +#define CMD_I2L 133 + 1, +#define CMD_I2F 134 + 1, +#define CMD_I2D 135 + 1, +#define CMD_L2I 136 + 1, +#define CMD_L2F 137 + 1, +#define CMD_L2D 138 + 1, +#define CMD_F2I 139 + 1, +#define CMD_F2L 140 + 1, +#define CMD_F2D 141 + 1, +#define CMD_D2I 142 + 1, +#define CMD_D2L 143 + 1, +#define CMD_D2F 144 + 1, +#define CMD_INT2BYTE 145 + 1, +#define CMD_INT2CHAR 146 + 1, +#define CMD_INT2SHORT 147 + 1, +#define CMD_LCMP 148 + 1, +#define CMD_FCMPL 149 + 1, +#define CMD_FCMPG 150 + 1, +#define CMD_DCMPL 151 + 1, +#define CMD_DCMPG 152 + 1, +#define CMD_IFEQ 153 + 3, +#define CMD_IFNE 154 + 3, +#define CMD_IFLT 155 + 3, +#define CMD_IFGE 156 + 3, +#define CMD_IFGT 157 + 3, +#define CMD_IFLE 158 + 3, +#define CMD_IF_ICMPEQ 159 + 3, +#define CMD_IF_ICMPNE 160 + 3, +#define CMD_IF_ICMPLT 161 + 3, +#define CMD_IF_ICMPGE 162 + 3, +#define CMD_IF_ICMPGT 163 + 3, +#define CMD_IF_ICMPLE 164 + 3, +#define CMD_IF_ACMPEQ 165 + 3, +#define CMD_IF_ACMPNE 166 + 3, +#define CMD_GOTO 167 + 3, +#define CMD_JSR 168 + 3, +#define CMD_RET 169 + 2, +#define CMD_TABLESWITCH 170 + 0, /* length must be computed */ +#define CMD_LOOKUPSWITCH 171 + 0, /* length must be computed */ +#define CMD_IRETURN 172 + 1, +#define CMD_LRETURN 173 + 1, +#define CMD_FRETURN 174 + 1, +#define CMD_DRETURN 175 + 1, +#define CMD_ARETURN 176 + 1, +#define CMD_RETURN 177 + 1, +#define CMD_GETSTATIC 178 + 3, +#define CMD_PUTSTATIC 179 + 3, +#define CMD_GETFIELD 180 + 3, +#define CMD_PUTFIELD 181 + 3, +#define CMD_INVOKEVIRTUAL 182 + 3, +#define CMD_INVOKESPECIAL 183 + 3, +#define CMD_INVOKESTATIC 184 + 3, +#define CMD_INVOKEINTERFACE 185 + 5, + 1, /* unused */ +#define CMD_NEW 187 + 3, +#define CMD_NEWARRAY 188 + 2, +#define CMD_ANEWARRAY 189 + 3, +#define CMD_ARRAYLENGTH 190 + 1, +#define CMD_ATHROW 191 + 1, +#define CMD_CHECKCAST 192 + 3, +#define CMD_INSTANCEOF 193 + 3, +#define CMD_MONITORENTER 194 + 1, +#define CMD_MONITOREXIT 195 + 1, +#define CMD_WIDE 196 + 0, /* length must be computed */ +#define CMD_MULTIANEWARRAY 197 + 4, +#define CMD_IFNULL 198 + 3, +#define CMD_IFNONNULL 199 + 3, +#define CMD_GOTO_W 200 + 5, +#define CMD_JSR_W 201 + 5, +#define CMD_BREAKPOINT 202 + 1, + + 1,1,1,1,1,1,1,1,1,1, /* unused */ + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1 + }; + +#define CMD_TRACEBUILT 253 /* internal opcode */ +#define CMD_IFEQL 254 /* internal opcode */ +#define CMD_IF_UCMPGE 255 /* internal opcode */ + +#define CMD_LOADCONST_I (CMD_IF_UCMPGE+TAG_LOADCONST_I) /* internal opcodes */ +#define CMD_LOADCONST_L (CMD_IF_UCMPGE+TAG_LOADCONST_L) +#define CMD_LOADCONST_F (CMD_IF_UCMPGE+TAG_LOADCONST_F) +#define CMD_LOADCONST_D (CMD_IF_UCMPGE+TAG_LOADCONST_D) +#define CMD_LOADCONST_A (CMD_IF_UCMPGE+TAG_LOADCONST_A) +#define CMD_MOVE (CMD_IF_UCMPGE+TAG_MOVE) + +#define CMD_TABLEJUMP (CMD_IF_UCMPGE+TAG_TABLEJUMP) +#define CMD_BUILTIN (CMD_IF_UCMPGE+TAG_METHOD) +#define CMD_DROP (CMD_IF_UCMPGE+TAG_DROP) +#define CMD_ACTIVATE (CMD_IF_UCMPGE+TAG_ACTIVATE) + + +/******************* description of JavaVM instructions ***********************/ + +typedef struct { + u1 opcode; + u1 type_s1; + u1 type_s2; + u1 type_d; + functionptr builtin; + bool supported; + bool isfloat; +} stdopdescriptor; + +stdopdescriptor *stdopdescriptors[256]; + +stdopdescriptor stdopdescriptortable[] = { + { CMD_IADD, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_ISUB, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_IMUL, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_ISHL, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_ISHR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_IUSHR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_IAND, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_IOR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_IXOR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { CMD_INEG, TYPE_INT, TYPE_VOID,TYPE_INT, NULL, true, false }, + + { CMD_LADD, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_ladd , SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { CMD_LSUB, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lsub , SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { CMD_LMUL, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lmul , SUPPORT_LONG && SUPPORT_LONG_MULDIV, false }, + { CMD_LSHL, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lshl , SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { CMD_LSHR, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lshr, SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { CMD_LUSHR, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lushr, SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { CMD_LAND, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_land, SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { CMD_LOR, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lor , SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { CMD_LXOR, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lxor, SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { CMD_LNEG, TYPE_LONG, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_lneg, SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { CMD_LCMP, TYPE_LONG, TYPE_LONG, TYPE_INT, + (functionptr) builtin_lcmp, SUPPORT_LONG && SUPPORT_LONG_CMP, false }, + + { CMD_FADD, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fadd, SUPPORT_FLOAT, true }, + { CMD_FSUB, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fsub, SUPPORT_FLOAT, true }, + { CMD_FMUL, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fmul, SUPPORT_FLOAT, true }, + { CMD_FDIV, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fdiv, SUPPORT_FLOAT, true }, + { CMD_FREM, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_frem, SUPPORT_FLOAT, true }, + { CMD_FNEG, TYPE_FLOAT, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_fneg, SUPPORT_FLOAT, true }, + { CMD_FCMPL, TYPE_FLOAT, TYPE_FLOAT, TYPE_INT, + (functionptr) builtin_fcmpl, SUPPORT_FLOAT, true }, + { CMD_FCMPG, TYPE_FLOAT, TYPE_FLOAT, TYPE_INT, + (functionptr) builtin_fcmpg, SUPPORT_FLOAT, true }, + + { CMD_DADD, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dadd, SUPPORT_DOUBLE, true }, + { CMD_DSUB, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dsub, SUPPORT_DOUBLE, true }, + { CMD_DMUL, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dmul, SUPPORT_DOUBLE, true }, + { CMD_DDIV, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_ddiv, SUPPORT_DOUBLE, true }, + { CMD_DREM, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_drem, SUPPORT_DOUBLE, true }, + { CMD_DNEG, TYPE_DOUBLE, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_dneg, SUPPORT_DOUBLE, true }, + { CMD_DCMPL, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_INT, + (functionptr) builtin_dcmpl, SUPPORT_DOUBLE, true }, + { CMD_DCMPG, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_INT, + (functionptr) builtin_dcmpg, SUPPORT_DOUBLE, true }, + + { CMD_INT2BYTE, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { CMD_INT2CHAR, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { CMD_INT2SHORT, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { CMD_I2L, TYPE_INT, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_i2l, SUPPORT_LONG && SUPPORT_LONG_ICVT, false }, + { CMD_I2F, TYPE_INT, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_i2f, SUPPORT_FLOAT, true }, + { CMD_I2D, TYPE_INT, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_i2d, SUPPORT_DOUBLE, true }, + { CMD_L2I, TYPE_LONG, TYPE_VOID, TYPE_INT, + (functionptr) builtin_l2i, SUPPORT_LONG && SUPPORT_LONG_ICVT, false }, + { CMD_L2F, TYPE_LONG, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_l2f, SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_LONG_FCVT, true }, + { CMD_L2D, TYPE_LONG, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_l2d, SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_LONG_FCVT, true }, + { CMD_F2I, TYPE_FLOAT, TYPE_VOID, TYPE_INT, + (functionptr) builtin_f2i, SUPPORT_FLOAT, true }, + { CMD_F2L, TYPE_FLOAT, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_f2l, SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_LONG_FCVT, true }, + { CMD_F2D, TYPE_FLOAT, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_f2d, SUPPORT_FLOAT && SUPPORT_DOUBLE, true }, + { CMD_D2I, TYPE_DOUBLE, TYPE_VOID, TYPE_INT, + (functionptr) builtin_d2i, SUPPORT_DOUBLE, true }, + { CMD_D2L, TYPE_DOUBLE, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_d2l, SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_LONG_FCVT, true }, + { CMD_D2F, TYPE_DOUBLE, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_d2f, SUPPORT_DOUBLE && SUPPORT_FLOAT, true }, + +}; + + + +/***************************** register types *********************************/ + +#define REG_RES 0 /* reserved register for OS or code generator */ +#define REG_RET 1 /* return value register */ +#define REG_EXC 2 /* exception value register */ +#define REG_SAV 3 /* (callee) saved register */ +#define REG_TMP 4 /* scratch temporary register (caller saved) */ +#define REG_ARG 5 /* argument register (caller saved) */ + +#define REG_END -1 /* last entry in tables */ + +#define PARAMMODE_NUMBERED 0 +#define PARAMMODE_STUFFED 1 + +/***************************** register info block ****************************/ + +extern int regdescint[]; /* description of integer registers */ +extern int regdescfloat[]; /* description of floating point registers */ + +extern int reg_parammode; + diff --git a/comp/local.c b/comp/local.c new file mode 100644 index 000000000..37098bdfd --- /dev/null +++ b/comp/local.c @@ -0,0 +1,104 @@ +/**************************** comp/local.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + behandeln der lokalen Java-Variablen + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + /* es werden f"ur die lokalen Java-Variablen 5 Tabellen angelegt, + f"ur jeden m"oglichen Typ eine, weil mehrere Java-Variablen + verschiendenen Typs die selben Slots belegen k"onnen */ + +varid *locals[5]; + + +/*********************** Funktion: local_get ********************************** + + erzeugt eine neue Pseudo-Variable f"ur einen JavaVM-Slot und einen + gew"unschten Typ, oder eine bereits vorhandene Variable. + +******************************************************************************/ + +static varid local_get (int slot, int type) +{ + varid v; + int secondslot; + + secondslot = ((type==TYPE_DOUBLE) || (type==TYPE_LONG)) ? 1 : 0; + + if (slot+secondslot>=maxlocals) + panic ("Local-variable access out of bounds"); + v = locals[type][slot]; + + if (v==NULL) { + v = var_createwithspecialnumber (type, slot); + v -> globalscope = true; + locals[type][slot] = v; + } + + return v; +} + + + + +/************************* Funktion: local_init ******************************* + + legt die 5 Tabellen an, und erzeugt auch gleich die Belegungen + f"ur die Methodenparameter. + +******************************************************************************/ + +static void local_init() +{ + int t, i, slot; + + if (TYPE_INT != 0 || TYPE_ADDRESS != 4) + panic ("JAVA-Basictypes have been changed"); + + for (t=TYPE_INT; t<=TYPE_ADDRESS; t++) { + locals[t] = DMNEW (varid, maxlocals); + for (i=0; ireg == NULL) + v->reg = reg_allocate (v->type, v->saved, true); + } + } +} + diff --git a/comp/mcode.c b/comp/mcode.c new file mode 100644 index 000000000..ab7073400 --- /dev/null +++ b/comp/mcode.c @@ -0,0 +1,325 @@ +/***************************** comp/mcode.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + This file is an include file for "compiler.c" . It contains (mostly) + architecture independent functions for writing instructions into the + code area and constants into the data area. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Changes: Micheal Gschwind EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/04/13 + + + All functions assume the following code area / data area layout: + + +-----------+ + | | + | code area | code area grows to higher addresses + | | + +-----------+ <-- start of procedure + | | + | data area | data area grows to lower addresses + | | + +-----------+ + + The functions first write into a temporary code/data area allocated by + "mcode_init". "mcode_finish" copies the code and data area into permanent + memory. All functions writing values into the data area return the offset + relative the begin of the code area (start of procedure). + +*******************************************************************************/ + +#include +#include + +#define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */ +#define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */ + +static u1* mcodebase = NULL; /* base pointer of code area */ +static int mcodesize; /* complete size of code area (bytes) */ +static int mcodelen; /* used size of code area (bytes) */ + +static u1* dsegtop = NULL; /* pointer to top (end) of data area */ +static int dsegsize; /* complete size of data area (bytes) */ +static int dseglen; /* used size of data area (bytes) */ + /* data area grows from top to bottom */ + +static list mcodereferences; /* list of branch instruction adresses */ + /* and of jumptable target addresses */ + +static void mcode_init(); /* allocates code and data area */ +static void mcode_close(); /* releases temporary storage */ +static void mcode_finish(); /* makes code and data area permanent and */ + /* updates branch references to code/data */ +static void mcode_adds4(s4 code); /* adds an instruction to code area */ + +static s4 dseg_adds4(s4 value); /* adds an int to data area */ +static s4 dseg_adds8(s8 value); /* adds an long to data area */ +static s4 dseg_addfloat (float value); /* adds an float to data area */ +static s4 dseg_adddouble(double value); /* adds an double to data area */ + +/* s4 dseg_addaddress(void* value); */ +static s4 dseg_addtarget(basicblock *target); +static void mcode_addreference(basicblock *target); +static void dseg_display(); + +/* mcode_init allocates and initialises code area, data area and references */ + +static void mcode_init() +{ + if (!mcodebase) { + mcodebase = MNEW (u1, MCODEINITSIZE); + mcodesize = MCODEINITSIZE; + } + + if (!dsegtop) { + dsegtop = MNEW (u1, DSEGINITSIZE); + dsegsize = DSEGINITSIZE; + dsegtop += dsegsize; + } + + mcodelen = 0; + dseglen = 0; + + list_init (&mcodereferences, OFFSET(mcodereference, linkage) ); +} + + +/* mcode_close releases temporary code and data area */ + +static void mcode_close() +{ + if (mcodebase) { + MFREE (mcodebase, u1, mcodesize); + mcodebase = NULL; + } + if (dsegtop) { + MFREE (dsegtop - dsegsize, u1, dsegsize); + dsegtop = NULL; + } +} + + +/* mcode_adds4_increase doubles code area and adds instruction */ + +static void mcode_adds4_increase(s4 code) +{ + mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2); + mcodesize *= 2; + *((s4 *) (mcodebase + mcodelen - 4)) = code; +} + + +/* mcode_adds4 checks code area size and adds instruction */ + +static void mcode_adds4(s4 code) +{ + s4 *codeptr; + + codeptr = (s4 *) (mcodebase + mcodelen); + mcodelen += 4; + if (mcodelen <= mcodesize) + *codeptr = code; + else + mcode_adds4_increase(code); +} + + +/* desg_increase doubles data area */ + +static void dseg_increase() { + u1 *newstorage = MNEW (u1, dsegsize * 2); + memcpy ( newstorage + dsegsize, dsegtop - dsegsize, dsegsize); + MFREE (dsegtop - dsegsize, u1, dsegsize); + dsegtop = newstorage; + dsegsize *= 2; + dsegtop += dsegsize; +} + + +static s4 dseg_adds4_increase(s4 value) +{ + dseg_increase(); + *((s4 *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adds4(s4 value) +{ + s4 *dataptr; + + dseglen += 4; + dataptr = (s4 *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adds4_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_adds8_increase(s8 value) +{ + dseg_increase(); + *((s8 *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adds8(s8 value) +{ + s8 *dataptr; + + dseglen = ALIGN (dseglen + 8, 8); + dataptr = (s8 *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adds8_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_addfloat_increase(float value) +{ + dseg_increase(); + *((float *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_addfloat(float value) +{ + float *dataptr; + + dseglen += 4; + dataptr = (float *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_addfloat_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_adddouble_increase(double value) +{ + dseg_increase(); + *((double *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adddouble(double value) +{ + double *dataptr; + + dseglen = ALIGN (dseglen + 8, 8); + dataptr = (double *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adddouble_increase(value); + *dataptr = value; + return -dseglen; +} + + +#if POINTERSIZE==8 +#define dseg_addaddress(value) dseg_adds8((s8)(value)) +#else +#define dseg_addaddress(value) dseg_adds4((s4)(value)) +#endif + + +static s4 dseg_addtarget(basicblock *target) +{ + mcodereference *cr = DNEW(mcodereference); + + dseglen = ALIGN (dseglen + sizeof(void*), sizeof(void*)); + if (dseglen > dsegsize) + dseg_increase(); + + cr -> incode = false; + cr -> msourcepos = -dseglen; + cr -> target = target; + + list_addlast (&mcodereferences, cr); + + return -dseglen; +} + + +static void mcode_addreference(basicblock *target) +{ + mcodereference *cr = DNEW(mcodereference); + + cr -> incode = true; + cr -> msourcepos = mcodelen; + cr -> target = target; + + list_addlast (&mcodereferences, cr); +} + + + +static void mcode_blockstart (basicblock *b) +{ + b -> mpc = mcodelen; +} + + + +static void gen_resolvebranch(void* mcodepiece, s4 sourcepos, s4 targetpos); + +static void mcode_finish() +{ + mcodereference *cr; + + count_code_len += mcodelen; + count_data_len += dseglen; + + dseglen = ALIGN(dseglen, MAX_ALIGN); + + method->mcodelength = mcodelen + dseglen; + method->mcode = CNEW(u1, mcodelen + dseglen); + + memcpy ( method->mcode, dsegtop - dseglen, dseglen); + memcpy ( method->mcode + dseglen, mcodebase, mcodelen); + + method -> entrypoint = (u1*) (method->mcode + dseglen); + + cr = list_first (&mcodereferences); + while (cr != NULL) { + + if (cr->incode) { /* branch resolving */ + gen_resolvebranch ( ((u1*)(method->entrypoint)) + cr->msourcepos, + cr->msourcepos, + cr->target->mpc); + } + else { /* jump table resolving */ + void **p; + p = (void**) ( ((u1*)(method->entrypoint)) + cr->msourcepos); + + *p = ((u1*)(method->entrypoint)) + cr->target->mpc; + } + + cr = list_next (&mcodereferences, cr); + } + +#ifdef CACHE_FLUSH_BLOCK + synchronize_caches(method->mcode, (mcodelen>>2)); +#endif + +} + + +static void dseg_display() +{ + int i; + printf (" --- dump of datasegment\n"); + for (i = dseglen - 4; i >= 0 ; i -= 4) { + printf ("%6x: %8x\n", i, (int)(*((s4*)(dsegtop - i)))); + } +} diff --git a/comp/parse.c b/comp/parse.c new file mode 100644 index 000000000..9abb4e018 --- /dev/null +++ b/comp/parse.c @@ -0,0 +1,1662 @@ +/****************************** comp/parse.c *********************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt den Parser f"ur die Bytecode-Darstellung der Methoden + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/17 + +*******************************************************************************/ + + +/* Kurzschreibweise f"ur oft verwendete Funktionen */ + +#define LOADCONST_I pcmd_loadconst_i +#define LOADCONST_L pcmd_loadconst_l +#define LOADCONST_F pcmd_loadconst_f +#define LOADCONST_D pcmd_loadconst_d +#define LOADCONST_A pcmd_loadconst_a +#define MOVE pcmd_move +#define IINC pcmd_iinc +#define OP pcmd_op +#define MEM pcmd_mem +#define BRA pcmd_bra +#define TABLEJUMP pcmd_tablejump +#define METHOD pcmd_method + +#define BUILTIN1 pcmd_builtin1 +#define BUILTIN2 pcmd_builtin2 +#define BUILTIN3 pcmd_builtin3 + +#define DROP pcmd_drop +#define ACTIVATE pcmd_activate +#define BRA_N_DROP pcmd_bra_n_drop +#define MOVE_N_DROP pcmd_move_n_drop + +#define OP1(opcode,s,d) OP(opcode,s,NOVAR,NOVAR,d) +#define OP2(opcode,s1,s2,d) OP(opcode,s1,s2,NOVAR,d) +#define OP3(opcode,s1,s2,s3,d) OP(opcode,s1,s2,s3,d) + + +#define EXCREATOR(exclass) block_createexcreator (exclass, p) +#define EXFORWARDER(exvar) block_createexforwarder (exvar, p) + + + + +/****************** Funktion: addreturnlog ************************************ + + f"ugt in den Code einen Aufruf der Methoden-R"uckkehr-Protokollierung + ein. + +******************************************************************************/ + +static void addreturnhandling() +{ + if (checksync && (method->flags & ACC_SYNCHRONIZED) ) { + stack_makesaved (); +#ifdef USE_THREADS + if (method->flags & ACC_STATIC) { + varid v = var_create (TYPE_ADDRESS); + LOADCONST_A (class, v); + BUILTIN1 ( (functionptr) builtin_monitorexit, v, NOVAR); + } + else { + BUILTIN1 ( (functionptr) builtin_monitorexit, + local_get (0, TYPE_ADDRESS) , NOVAR); + } +#endif + } +} + + +/*************** Funktion: addreturnexceptionlog ***************************** + + f"ugt in den Code einen Aufruf der Methoden-R"uckkehr-Protokollierung + mit Exception ein. + +******************************************************************************/ + +static void addreturnexceptionhandling() +{ + + if (runverbose) { + varid v; + + stack_makesaved (); + v = var_create (TYPE_ADDRESS); + LOADCONST_A (method, v); + BUILTIN1 ( (functionptr) builtin_displaymethodexception, v, NOVAR); + } + + if (checksync && (method->flags & ACC_SYNCHRONIZED) ) { + stack_makesaved (); +#ifdef USE_THREADS + if (method->flags & ACC_STATIC) { + varid v = var_create (TYPE_ADDRESS); + LOADCONST_A (class, v); + BUILTIN1 ( (functionptr) builtin_monitorexit, v, NOVAR); + } + else { + BUILTIN1 ( (functionptr) builtin_monitorexit, + local_get (0, TYPE_ADDRESS) , NOVAR); + } +#endif + } +} + + + +/****************************************************************************** +*************** Funktion 'parse' zum Durcharbeiten des Bytecodes ************** +******************************************************************************/ + +static void parse (basicblock *b) +{ + varid v,v1,v2,v3,ve; + u4 poolindex; + s4 type; + u4 p,i; + basicblock *target=NULL; + bool iswide=false; + + stack_restore (b->stack); + subroutine_set (b->subroutine); + + + switch (b->type) { + + /* Code fuer einen Exception-Forwarder generieren */ + + + case BLOCKTYPE_EXFORWARDER: + if (!compileall) { + ACTIVATE (b->exvar); + stack_repush (b->exvar); + stack_makesaved (); + + for (i=0; ithrowpos + && extable[i].endpc > b->throwpos) { + + if (!extable[i].catchtype) goto exceptionfits; + + stack_makesaved(); + v1 = var_create (TYPE_ADDRESS); + v2 = var_create (TYPE_ADDRESS); + v = var_create (TYPE_INT); + MOVE (TYPE_ADDRESS, b->exvar, v1); + LOADCONST_A (extable[i].catchtype, v2); + BUILTIN2 ((functionptr) builtin_instanceof, v1,v2, v); + + block_reach (target); + BRA_N_DROP (CMD_IFNE, v,NOVAR, NOVAR, target); + } + } + target = NULL; + } + goto exceptionfits; + + + /* Code fuer einen Exception-Creator generieren */ + case BLOCKTYPE_EXCREATOR: + if (!compileall) { + java_objectheader *o = b->exproto; + LOADCONST_A (o, stack_push(TYPE_ADDRESS) ); + + for (i=0; ithrowpos + && extable[i].endpc > b->throwpos) { + + if (!extable[i].catchtype) goto exceptionfits; + if (builtin_instanceof (o, extable[i].catchtype) ) goto exceptionfits; + } + } + target = NULL; + } + + /*** Der Sprung zum Exception-Handler (oder Methodenbeendigung) ***/ + + exceptionfits: + if (!compileall) { + if (target) { + block_reach (target); + BRA (CMD_GOTO, NOVAR,NOVAR,NOVAR, target); + goto cleanup; + } + +#ifdef STATISTICS + count_pcmd_returnx++; +#endif + + switch (mreturntype) { + case TYPE_INT: + addreturnexceptionhandling(); + + v1 = var_create (TYPE_INT); + LOADCONST_I (0, v1); + BRA_N_DROP (CMD_IRETURN, v1,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + case TYPE_LONG: + addreturnexceptionhandling(); + + v1 = var_create (TYPE_LONG); + LOADCONST_I (0, v1); + BRA_N_DROP (CMD_LRETURN, v1,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + case TYPE_FLOAT: + addreturnexceptionhandling(); + + v1 = var_create (TYPE_FLOAT); + LOADCONST_F (0.0, v1); + BRA_N_DROP (CMD_FRETURN, v1,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + case TYPE_DOUBLE: + addreturnexceptionhandling(); + + v1 = var_create (TYPE_DOUBLE); + LOADCONST_D (0.0, v1); + BRA_N_DROP (CMD_DRETURN, v1,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + case TYPE_ADDRESS: + addreturnexceptionhandling(); + + v1 = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, v1); + BRA_N_DROP (CMD_ARETURN, v1,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + case TYPE_VOID: + addreturnexceptionhandling(); + + BRA (CMD_RETURN, NOVAR,stack_pop(TYPE_ADDRESS), NOVAR, NULL); + break; + } + } + goto cleanup; + } + + + /* Code fuer einen (normalen) JavaVM - Block generieren */ + + p = b->jpc; + + + + if ( p==0) { + /* Method call protocolling */ + + if (runverbose) { + stack_makesaved(); + pcmd_trace (method); + } + + /* Synchronization */ + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + stack_makesaved(); +#ifdef USE_THREADS + if (method->flags & ACC_STATIC) { + varid v = var_create (TYPE_ADDRESS); + LOADCONST_A (class, v); + BUILTIN1 ( (functionptr) builtin_monitorenter, v, NOVAR); + } + else { + BUILTIN1 ( (functionptr) builtin_monitorenter, + local_get (0, TYPE_ADDRESS), NOVAR ); + } +#endif + } + } + + for (;;) { + u1 opcode; + u4 nextp; + + opcode = code_get_u1 (p); + nextp = p + jcommandsize[opcode]; + + + count_javainstr++; + + + if (showstack) { + printf ("PC: %3d OPCODE: %3d Stack: ",(int) p, (int) opcode); + stack_display (stack_get()); + printf ("\n"); + } + + + switch (opcode) { + + + /*** Pushing constants onto the stack ***/ + + case CMD_BIPUSH: + LOADCONST_I (code_get_s1 (p+1), stack_push (TYPE_INT) ); + break; + + case CMD_SIPUSH: + LOADCONST_I (code_get_s2 (p+1), stack_push (TYPE_INT) ); + break; + + case CMD_LDC1: poolindex = code_get_u1 (p+1); + goto pushconstantitem; + case CMD_LDC2: + case CMD_LDC2W: poolindex = code_get_u2 (p+1); + pushconstantitem: + switch (class_constanttype(class, poolindex)) { + case CONSTANT_Integer: + { constant_integer *c; + c = class_getconstant (class, poolindex, CONSTANT_Integer); + LOADCONST_I (c->value, stack_push(TYPE_INT) ); + } + break; + case CONSTANT_Long: + { constant_long *c; + c = class_getconstant (class, poolindex, CONSTANT_Long); + LOADCONST_L (c->value, stack_push(TYPE_LONG) ); + } + break; + case CONSTANT_Float: + { constant_float *c; + c = class_getconstant (class, poolindex, CONSTANT_Float); + LOADCONST_F (c->value, stack_push(TYPE_FLOAT) ); + } + break; + case CONSTANT_Double: + { constant_double *c; + c = class_getconstant (class, poolindex, CONSTANT_Double); + LOADCONST_D (c->value, stack_push(TYPE_DOUBLE) ); + } + break; + + case CONSTANT_String: + { unicode *s; + + s = class_getconstant (class, poolindex, CONSTANT_String); + + LOADCONST_A ( literalstring_new (s), + stack_push(TYPE_ADDRESS) ); + } + break; + + default: panic ("Invalid constant type to push"); + } + break; + + + case CMD_ACONST_NULL: + LOADCONST_A (0, stack_push (TYPE_ADDRESS) ); + break; + + case CMD_ICONST_M1: + case CMD_ICONST_0: + case CMD_ICONST_1: + case CMD_ICONST_2: + case CMD_ICONST_3: + case CMD_ICONST_4: + case CMD_ICONST_5: + LOADCONST_I (opcode - CMD_ICONST_0, stack_push (TYPE_INT) ); + break; + + case CMD_LCONST_0: + case CMD_LCONST_1: +#if U8_AVAILABLE + LOADCONST_L (opcode - CMD_LCONST_0, stack_push (TYPE_LONG) ); +#else + { u8 v; + v.low = opcode - CMD_LCONST_0; + v.high = 0; + LOADCONST_L (v, stack_push(TYPE_LONG) ); + } +#endif + break; + + case CMD_FCONST_0: + case CMD_FCONST_1: + case CMD_FCONST_2: + LOADCONST_F (opcode - CMD_FCONST_0, stack_push (TYPE_FLOAT) ); + break; + + case CMD_DCONST_0: + case CMD_DCONST_1: + LOADCONST_D (opcode - CMD_DCONST_0, stack_push (TYPE_DOUBLE) ); + break; + + + /*** Loading variables onto the Stack ***/ + + case CMD_ILOAD: + if (!iswide) { + MOVE ( TYPE_INT, + local_get (code_get_u1 (p+1), TYPE_INT), + stack_push (TYPE_INT) ); + } + else { + MOVE ( TYPE_INT, + local_get (code_get_u2 (p+1), TYPE_INT), + stack_push (TYPE_INT) ); + nextp = p+3; + iswide = false; + } + break; + + case CMD_ILOAD_0: + case CMD_ILOAD_1: + case CMD_ILOAD_2: + case CMD_ILOAD_3: + MOVE ( TYPE_INT, + local_get (opcode - CMD_ILOAD_0, TYPE_INT), + stack_push (TYPE_INT) ); + break; + + case CMD_LLOAD: + if (!iswide) { + MOVE ( TYPE_LONG, + local_get (code_get_u1 (p+1), TYPE_LONG), + stack_push (TYPE_LONG) ); + } + else { + MOVE ( TYPE_LONG, + local_get (code_get_u2 (p+1), TYPE_LONG), + stack_push (TYPE_LONG) ); + nextp = p+3; + iswide = false; + } + break; + + case CMD_LLOAD_0: + case CMD_LLOAD_1: + case CMD_LLOAD_2: + case CMD_LLOAD_3: + MOVE ( TYPE_LONG, + local_get (opcode - CMD_LLOAD_0, TYPE_LONG), + stack_push (TYPE_LONG) ); + break; + + case CMD_FLOAD: + if (!iswide) { + MOVE ( TYPE_FLOAT, + local_get (code_get_u1 (p+1), TYPE_FLOAT), + stack_push (TYPE_FLOAT) ); + } + else { + MOVE ( TYPE_FLOAT, + local_get (code_get_u2 (p+1), TYPE_FLOAT), + stack_push (TYPE_FLOAT) ); + nextp = p+3; + iswide = false; + } + break; + + case CMD_FLOAD_0: + case CMD_FLOAD_1: + case CMD_FLOAD_2: + case CMD_FLOAD_3: + MOVE ( TYPE_FLOAT, + local_get (opcode - CMD_FLOAD_0, TYPE_FLOAT), + stack_push (TYPE_FLOAT) ); + break; + + case CMD_DLOAD: + if (!iswide) { + MOVE ( TYPE_DOUBLE, + local_get (code_get_u1 (p+1), TYPE_DOUBLE), + stack_push (TYPE_DOUBLE) ); + } + else { + MOVE ( TYPE_DOUBLE, + local_get (code_get_u2 (p+1), TYPE_DOUBLE), + stack_push (TYPE_DOUBLE) ); + nextp = p+3; + iswide = false; + } + break; + + case CMD_DLOAD_0: + case CMD_DLOAD_1: + case CMD_DLOAD_2: + case CMD_DLOAD_3: + MOVE ( TYPE_DOUBLE, + local_get (opcode - CMD_DLOAD_0, TYPE_DOUBLE), + stack_push (TYPE_DOUBLE) ); + break; + + case CMD_ALOAD: + if (!iswide) { + MOVE ( TYPE_ADDRESS, + local_get (code_get_u1 (p+1), TYPE_ADDRESS), + stack_push (TYPE_ADDRESS) ); + } + else { + MOVE ( TYPE_ADDRESS, + local_get (code_get_u2 (p+1), TYPE_ADDRESS), + stack_push (TYPE_ADDRESS) ); + nextp = p+3; + iswide = false; + } + break; + + case CMD_ALOAD_0: + case CMD_ALOAD_1: + case CMD_ALOAD_2: + case CMD_ALOAD_3: + MOVE ( TYPE_ADDRESS, + local_get (opcode - CMD_ALOAD_0, TYPE_ADDRESS), + stack_push (TYPE_ADDRESS) ); + break; + + + /*** Storing Stack Values into Local Variables ***/ + + case CMD_ISTORE: + v = stack_pop (TYPE_INT); + if (!iswide) { + MOVE_N_DROP (TYPE_INT, v, + local_get (code_get_u1 (p+1), TYPE_INT) ); + } + else { + MOVE_N_DROP (TYPE_INT, v, + local_get (code_get_u2 (p+1), TYPE_INT) ); + iswide=false; + nextp = p+3; + } + break; + + case CMD_ISTORE_0: + case CMD_ISTORE_1: + case CMD_ISTORE_2: + case CMD_ISTORE_3: + v = stack_pop (TYPE_INT); + MOVE_N_DROP (TYPE_INT, + v, local_get (opcode - CMD_ISTORE_0, TYPE_INT) ); + break; + + case CMD_LSTORE: + v = stack_pop (TYPE_LONG); + if (!iswide) { + MOVE_N_DROP (TYPE_LONG, v, + local_get (code_get_u1 (p+1), TYPE_LONG) ); + } + else { + MOVE_N_DROP (TYPE_LONG, v, + local_get (code_get_u2 (p+1), TYPE_LONG) ); + iswide=false; + nextp = p+3; + } + break; + + case CMD_LSTORE_0: + case CMD_LSTORE_1: + case CMD_LSTORE_2: + case CMD_LSTORE_3: + v = stack_pop (TYPE_LONG); + MOVE_N_DROP (TYPE_LONG, + v, local_get (opcode - CMD_LSTORE_0, TYPE_LONG) ); + break; + + case CMD_FSTORE: + v = stack_pop (TYPE_FLOAT); + if (!iswide) { + MOVE_N_DROP (TYPE_FLOAT, v, + local_get (code_get_u1 (p+1), TYPE_FLOAT) ); + } + else { + MOVE_N_DROP (TYPE_FLOAT, v, + local_get (code_get_u2 (p+1), TYPE_FLOAT) ); + iswide=false; + nextp = p+3; + } + break; + + case CMD_FSTORE_0: + case CMD_FSTORE_1: + case CMD_FSTORE_2: + case CMD_FSTORE_3: + v = stack_pop (TYPE_FLOAT); + MOVE_N_DROP (TYPE_FLOAT, + v, local_get (opcode - CMD_FSTORE_0, TYPE_FLOAT) ); + break; + + case CMD_DSTORE: + v = stack_pop (TYPE_DOUBLE); + if (!iswide) { + MOVE_N_DROP (TYPE_DOUBLE, v, + local_get (code_get_u1 (p+1), TYPE_DOUBLE) ); + } + else { + MOVE_N_DROP (TYPE_DOUBLE, v, + local_get (code_get_u2 (p+1), TYPE_DOUBLE) ); + iswide=false; + nextp = p+3; + } + break; + + case CMD_DSTORE_0: + case CMD_DSTORE_1: + case CMD_DSTORE_2: + case CMD_DSTORE_3: + v = stack_pop (TYPE_DOUBLE); + MOVE_N_DROP (TYPE_DOUBLE, + v, local_get (opcode - CMD_DSTORE_0, TYPE_DOUBLE) ); + break; + + case CMD_ASTORE: + v = stack_pop (TYPE_ADDRESS); + if (!iswide) { + MOVE_N_DROP (TYPE_ADDRESS, v, + local_get (code_get_u1 (p+1), TYPE_ADDRESS) ); + } + else { + MOVE_N_DROP (TYPE_ADDRESS, v, + local_get (code_get_u2 (p+1), TYPE_ADDRESS) ); + iswide=false; + nextp = p+3; + } + break; + + case CMD_ASTORE_0: + case CMD_ASTORE_1: + case CMD_ASTORE_2: + case CMD_ASTORE_3: + v = stack_pop (TYPE_ADDRESS); + MOVE_N_DROP (TYPE_ADDRESS, + v, local_get (opcode - CMD_ASTORE_0, TYPE_ADDRESS) ); + break; + + + case CMD_IINC: + if (!iswide) { + v1 = local_get (code_get_u1 (p+1), TYPE_INT); + IINC (code_get_s1 (p+2), v1 ); + DROP (v1); + } + else { + v1 = local_get (code_get_u2 (p+1), TYPE_INT); + IINC (code_get_s2 (p+3), v1 ); + DROP (v1); + iswide = false; + nextp = p+5; + } + break; + + + /*** Wider index for Loading, Storing and Incrementing ***/ + + case CMD_WIDE: + iswide=true; + nextp = p+1; + break; + + + /******************** Managing Arrays **************************/ + + case CMD_NEWARRAY: + v1 = stack_pop (TYPE_INT); + BRA (CMD_IFLT, v1,NOVAR, NOVAR, EXCREATOR(proto_java_lang_NegativeArraySizeException) ); + + stack_makesaved (); + v = stack_push (TYPE_ADDRESS); + switch ( code_get_s1 (p+1) ) { + case 4: BUILTIN1 ((functionptr) builtin_newarray_boolean, v1, v); + break; + case 5: BUILTIN1 ((functionptr) builtin_newarray_char, v1, v); + break; + case 6: BUILTIN1 ((functionptr) builtin_newarray_float, v1, v); + break; + case 7: BUILTIN1 ((functionptr) builtin_newarray_double, v1, v); + break; + case 8: BUILTIN1 ((functionptr) builtin_newarray_byte, v1, v); + break; + case 9: BUILTIN1 ((functionptr) builtin_newarray_short, v1, v); + break; + case 10: BUILTIN1 ((functionptr) builtin_newarray_int, v1, v); + break; + case 11: BUILTIN1 ((functionptr) builtin_newarray_long, v1, v); + break; + default: panic ("Invalid array-type to create"); + } + + BRA (CMD_IFNULL, v,NOVAR, NOVAR, EXCREATOR(proto_java_lang_OutOfMemoryError) ); + + break; + + case CMD_ANEWARRAY: + poolindex = code_get_u2(p+1); + if (class_constanttype (class, poolindex) == CONSTANT_Arraydescriptor) { + /* anewarray mit Array-Typ! */ + constant_arraydescriptor *desc = + class_getconstant (class, poolindex, CONSTANT_Arraydescriptor); + + v1 = stack_pop (TYPE_INT); + BRA (CMD_IFLT, v1,NOVAR, NOVAR, EXCREATOR(proto_java_lang_NegativeArraySizeException) ); + + v2 = var_create (TYPE_ADDRESS); + LOADCONST_A (desc, v2); + + stack_makesaved (); + v = stack_push (TYPE_ADDRESS); + BUILTIN2 ((functionptr) builtin_newarray_array, v1,v2, v); + BRA (CMD_IFNULL, v,NOVAR, NOVAR, EXCREATOR(proto_java_lang_OutOfMemoryError) ); + } + else { + classinfo *c = class_getconstant (class, poolindex, CONSTANT_Class); + + v1 = stack_pop (TYPE_INT); + BRA (CMD_IFLT, v1,NOVAR, NOVAR, EXCREATOR(proto_java_lang_NegativeArraySizeException) ); + + v2 = var_create (TYPE_ADDRESS); + LOADCONST_A (c, v2); + + stack_makesaved (); + v = stack_push (TYPE_ADDRESS); + BUILTIN2 ((functionptr) builtin_anewarray, v1,v2, v); + BRA (CMD_IFNULL, v,NOVAR, NOVAR, EXCREATOR(proto_java_lang_OutOfMemoryError) ); + } + + break; + + + case CMD_MULTIANEWARRAY: + { constant_arraydescriptor *desc = + class_getconstant (class, code_get_u2(p+1), CONSTANT_Arraydescriptor); + int i, n = code_get_u1 (p+3); + varid dims = var_create (TYPE_ADDRESS); /* array for dimensions */ + varid dimsdim = var_create (TYPE_INT); /* groesse des arrays */ + + stack_makesaved (); + LOADCONST_I (n, dimsdim); + BUILTIN1 ((functionptr) builtin_newarray_int, dimsdim, dims); + BRA (CMD_IFNULL, dims,NOVAR, NOVAR, EXCREATOR(proto_java_lang_OutOfMemoryError) ); + + for (i=0; isubroutine; + if (!sub) { + sub = subroutine_new(); + target->subroutine = sub; + } + + subroutine_set (sub); + block_reach (target); + subroutine_set (b->subroutine); + + BRA (CMD_JSR, NOVAR,NOVAR, stack_pop(TYPE_ADDRESS), target ); + + while (! stack_isempty() ) { + v = stack_popany ( stack_topslots() ); + DROP (v); + } + + if (sub->returnfinished) { + stackinfo *s = sub->returnstack; + stack_restore (s); + while (s) { + ACTIVATE (s->var); + s = s->prev; + } + block_reach ( block_find(nextp) ); + } + else { + basicblock *n = block_find(nextp); + n -> subroutine = b->subroutine; + + chain_addlast (sub->callers, n ); + } + + } + goto cleanup; + + + case CMD_RET: + if (!iswide) { + v = local_get (code_get_u1 (p+1), TYPE_ADDRESS); + } + else { + v = local_get (code_get_u2 (p+1), TYPE_ADDRESS); + nextp = p+3; + iswide = false; + } + + { + subroutineinfo *sub; + basicblock *bb; + + sub = b->subroutine; + if (!sub) panic ("RET outside of subroutine"); + if (sub->returnfinished) panic ("Multiple RET in a subroutine"); + + sub->returnfinished = true; + sub->returnstack = stack_get() ; + + while ( (bb = chain_first(sub->callers)) ) { + chain_remove (sub->callers); + + subroutine_set (bb->subroutine); + block_reach ( bb ); + subroutine_set (sub); + } + + BRA (CMD_RET, v,NOVAR, NOVAR, NULL); + } + goto cleanup; + + + + /*************** Function Return **************/ + + case CMD_IRETURN: + addreturnhandling(); + + v = stack_pop (TYPE_INT); + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + BRA_N_DROP (opcode, v, ve, NOVAR, NULL); +#ifdef STATISTICS + count_pcmd_return++; +#endif + goto cleanup; + + case CMD_LRETURN: + addreturnhandling(); + + v = stack_pop (TYPE_LONG); + var_proposereg (v, reg_parlistresult(TYPE_LONG) ); + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + var_proposereg (ve, reg_parlistexception() ); + BRA_N_DROP (opcode, v, ve, NOVAR, NULL); +#ifdef STATISTICS + count_pcmd_return++; +#endif + goto cleanup; + + case CMD_FRETURN: + addreturnhandling(); + + v = stack_pop (TYPE_FLOAT); + var_proposereg (v, reg_parlistresult(TYPE_FLOAT) ); + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + var_proposereg (ve, reg_parlistexception() ); + BRA_N_DROP (opcode, v, ve, NOVAR, NULL); +#ifdef STATISTICS + count_pcmd_return++; +#endif + goto cleanup; + + case CMD_DRETURN: + addreturnhandling(); + + v = stack_pop (TYPE_DOUBLE); + var_proposereg (v, reg_parlistresult(TYPE_DOUBLE) ); + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + var_proposereg (ve, reg_parlistexception() ); + BRA_N_DROP (opcode, v, ve, NOVAR, NULL); +#ifdef STATISTICS + count_pcmd_return++; +#endif + goto cleanup; + + case CMD_ARETURN: + addreturnhandling(); + + v = stack_pop (TYPE_ADDRESS); + var_proposereg (v, reg_parlistresult(TYPE_ADDRESS) ); + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + var_proposereg (ve, reg_parlistexception() ); + BRA_N_DROP (opcode, v, ve, NOVAR, NULL); + goto cleanup; +#ifdef STATISTICS + count_pcmd_return++; +#endif + + case CMD_RETURN: + addreturnhandling(); + + ve = var_create (TYPE_ADDRESS); + LOADCONST_A (NULL, ve); + var_proposereg (ve, reg_parlistexception() ); + BRA_N_DROP (opcode, NOVAR,ve, NOVAR, NULL); +#ifdef STATISTICS + count_pcmd_return++; +#endif + goto cleanup; + + + case CMD_BREAKPOINT: + break; + + + + /**************** Table Jumping *****************/ + + case CMD_LOOKUPSWITCH: + { u4 p2 = ALIGN((p+1), 4); + basicblock *defaulttarget; + u4 num, i; + + defaulttarget = block_find (p + code_get_s4 (p2) ); + num = code_get_s4 (p2+4); + + v = stack_pop (TYPE_INT); + for (i=0; iclass, fr->name, fr->descriptor); + + switch (opcode) { + case CMD_PUTSTATIC: + compiler_addinitclass (fr->class); + + v1 = var_create (TYPE_ADDRESS); + v = stack_pop (fi->type); + LOADCONST_A (&(fi->value), v1); + + MEM (CMD_PUTFIELD, fi->type, v1,v, NOVAR, 0); + DROP (v); + DROP (v1); + break; + + case CMD_GETSTATIC: + compiler_addinitclass (fr->class); + + v1 = var_create (TYPE_ADDRESS); + v = stack_push (fi->type); + LOADCONST_A (&(fi->value), v1); + + MEM (CMD_GETFIELD, fi->type, v1,NOVAR, v, 0); + DROP (v1); + break; + + + case CMD_PUTFIELD: + v = stack_pop (fi->type); + v1 = stack_pop (TYPE_ADDRESS); + if (checknull) { +#ifdef STATISTICS + count_check_null++; +#endif + BRA (CMD_IFNULL, v1,NOVAR, NOVAR, EXCREATOR(proto_java_lang_NullPointerException) ); + } + MEM (CMD_PUTFIELD, fi->type, v1,v, NOVAR, fi->offset); + DROP (v); + DROP (v1); + break; + + case CMD_GETFIELD: + v1 = stack_pop (TYPE_ADDRESS); + v = stack_push (fi->type); + if (checknull) { +#ifdef STATISTICS + count_check_null++; +#endif + BRA (CMD_IFNULL, v1,NOVAR, NOVAR, EXCREATOR(proto_java_lang_NullPointerException) ); + } + MEM (CMD_GETFIELD, fi->type, v1,NOVAR, v, fi->offset); + DROP (v1); + break; + + + } + } + break; + + + /*** Method invocation ***/ + + case CMD_INVOKEVIRTUAL: + case CMD_INVOKESPECIAL: + case CMD_INVOKESTATIC: + case CMD_INVOKEINTERFACE: + + count_calls ++; + + { constant_FMIref *mr; + methodinfo *mi; + u4 i; + s4 paramnum; + u1 *paramtypes; + s4 returntype; + varid *params; + bool stat = (opcode == CMD_INVOKESTATIC); + + if (opcode==CMD_INVOKEINTERFACE) { + poolindex = code_get_u2 (p+1); + mr = class_getconstant (class, poolindex, CONSTANT_InterfaceMethodref); + } + else { + poolindex = code_get_u2 (p+1); + mr = class_getconstant (class, poolindex, CONSTANT_Methodref); + } + + mi = class_findmethod (mr->class, mr->name, mr->descriptor); + + if ( ((mi->flags & ACC_STATIC) != 0) != stat) + panic ("Static/Nonstatic mismatch on method call"); + + descriptor2types (mi->descriptor, stat, + ¶mnum, ¶mtypes, &returntype); + mi->paramcount = paramnum; + + params = DMNEW (varid, paramnum); + for (i=0; itype_s2 != TYPE_VOID) v2 = stack_pop(s->type_s2); + v1 = stack_pop(s->type_s1); + + if (s->supported) { + v = stack_push (s->type_d); + if (v2) { + OP2 (opcode, v1,v2, v); + DROP (v1); + DROP (v2); + } + else { + OP1 (opcode, v1, v); + DROP (v1); + } + } + else { + stack_makesaved (); + v = stack_push (s->type_d); + if (v2) { + BUILTIN2 (s->builtin, v1,v2, v); + } + else { + BUILTIN1 (s->builtin, v1, v); + } + } + } + + + /*************** invalid Opcode ***************/ + + else { + sprintf (logtext, "Invalid opcode %d at position %ld", + opcode, (long int) p); + error (); + } + + } + + break; + + + } /* end switch */ + + + p = nextp; + + if ( block_isany (p) ) { + block_reach ( block_find (p) ); + goto cleanup; + } + + } /* end for */ + + +cleanup: + pcmd_untieall(); +} + diff --git a/comp/pcmd.c b/comp/pcmd.c new file mode 100644 index 000000000..8279fa3eb --- /dev/null +++ b/comp/pcmd.c @@ -0,0 +1,706 @@ +/********************************** comp/pcmd.c ******************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + contains the parser functions which generate pseude commands and + eliminating unnecessary copy instructions + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/09/22 + +*******************************************************************************/ + + +list *pcmdlist; /* list of pseudo commands */ + + +/***************************** support functions ******************************/ + +static void pcmd_init (list *pl) +{ + pcmdlist = pl; +} + + +static void pcmd_realmove (u2 type, varid source, varid dest) +{ + pcmd *c = DNEW(pcmd); + c -> tag = TAG_MOVE; + c -> opcode = CMD_MOVE; + c -> source1 = source; + c -> source2 = NOVAR; + c -> source3 = NOVAR; + c -> dest = dest; + c -> u.move.type = type; + list_addlast (pcmdlist, c); +#ifdef STATISTICS + count_pcmd_move++; +#endif +} + + +static void pcmd_invalidatevar (varid v) +{ + varid c; + + if (!var_isoriginal(v) ) { + var_unlinkcopy (v); + } + else { + while ( (c = var_nextcopy (v)) != NULL) { + pcmd_realmove (var_type(v), v,c); + var_unlinkcopy (c); + } + + } +} + + +static void pcmd_untievar (varid v) +{ + varid c; + + if (!var_isoriginal(v)) { + pcmd_realmove (var_type(v), var_findoriginal(v), v); + var_unlinkcopy (v); + } + else { + while ( (c = var_nextcopy(v)) != NULL) { + pcmd_realmove (var_type(v), v, c); + var_unlinkcopy (c); + } + } +} + + +static void pcmd_untieall () +{ + varid v; + + while ( (v = var_nextcopiedvar()) != NULL) { + pcmd_realmove (var_type(v), var_findoriginal(v), v); + var_unlinkcopy (v); + } +} + + +/********************** generation of pseudo commands *************************/ + +static void pcmd_drop (varid var) +{ + pcmd *c = DNEW(pcmd); + + if (var_isoriginal(var)) { + pcmd_invalidatevar (var); + + c -> tag = TAG_DROP; + c -> opcode = CMD_DROP; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + list_addlast (pcmdlist, c); +#ifdef STATISTICS + count_pcmd_drop++; +#endif + } + else { + pcmd_invalidatevar (var); + } +} + + +static void pcmd_activate (varid var) +{ + pcmd *c = DNEW(pcmd); + + pcmd_untieall(); + + c -> tag = TAG_ACTIVATE; + c -> opcode = CMD_ACTIVATE; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_activ++; +#endif +} + + +static void pcmd_loadconst_i (s4 val, varid var) +{ + pcmd *c = DNEW (pcmd); + c -> tag = TAG_LOADCONST_I; + c -> opcode = CMD_LOADCONST_I; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + c -> u.i.value = val; + + pcmd_invalidatevar (var); + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + if (val == 0) + count_pcmd_zero++; + count_pcmd_load++; +#endif +} + + +static void pcmd_loadconst_l (s8 val, varid var) +{ + pcmd *c = DNEW (pcmd); + c -> tag = TAG_LOADCONST_L; + c -> opcode = CMD_LOADCONST_L; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + c -> u.l.value = val; + + pcmd_invalidatevar (var); + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + if (val == 0) + count_pcmd_zero++; + count_pcmd_load++; +#endif +} + + +static void pcmd_loadconst_f (float val, varid var) +{ + pcmd *c = DNEW (pcmd); + c -> tag = TAG_LOADCONST_F; + c -> opcode = CMD_LOADCONST_F; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + c -> u.f.value = val; + + pcmd_invalidatevar (var); + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_load++; +#endif +} + + +static void pcmd_loadconst_d (double val, varid var) +{ + pcmd *c = DNEW (pcmd); + c -> tag = TAG_LOADCONST_D; + c -> opcode = CMD_LOADCONST_D; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + c -> u.d.value = val; + + pcmd_invalidatevar (var); + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_load++; +#endif +} + + +static void pcmd_loadconst_a (void *val, varid var) +{ + pcmd *c = DNEW (pcmd); + c -> tag = TAG_LOADCONST_A; + c -> opcode = CMD_LOADCONST_A; + c -> dest = var; + c -> source1 = c -> source2 = c -> source3 = NOVAR; + c -> u.a.value = val; + + pcmd_invalidatevar (var); + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + if (val == NULL) + count_pcmd_zero++; + count_pcmd_load++; +#endif +} + + +static void pcmd_move (u2 type, varid source, varid dest) +{ + pcmd_invalidatevar (dest); + var_makecopy ( var_findoriginal(source), dest); +} + + +static void pcmd_move_n_drop (u2 type, varid source, varid dest) +{ + pcmd *c; + + pcmd_untievar (source); + pcmd_untievar (dest); + +#ifdef STATISTICS + count_pcmd_store++; +#endif + c = list_last (pcmdlist); + while (c) { + switch (c->tag) { + case TAG_LOADCONST_I: + if (c->dest == source) { c->dest = dest; return; } +#ifdef STATISTICS + count_pcmd_const_store++; +#endif + goto nothingfound; + case TAG_LOADCONST_L: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + case TAG_LOADCONST_F: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + case TAG_LOADCONST_D: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + case TAG_LOADCONST_A: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + case TAG_OP: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + case TAG_MEM: + if (c->dest == source) { c->dest = dest; return; } + goto nothingfound; + + case TAG_DROP: + break; + default: + goto nothingfound; + } /* end switch */ + + c = list_prev (pcmdlist, c); + } + +nothingfound: + var_makecopy ( source, dest); + pcmd_drop (source); +#ifdef STATISTICS + count_pcmd_store_comb++; +#endif +} + + +static void pcmd_iinc (s4 val, varid sourcedest) +{ + pcmd *c = DNEW (pcmd); + + pcmd_invalidatevar (sourcedest); + + c -> tag = TAG_OP; + c -> opcode = CMD_IINC; + c -> source1 = var_findoriginal(sourcedest); + c -> source2 = NOVAR; + c -> source3 = NOVAR; + c -> dest = sourcedest; + c -> u.i.value = val; + + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_op++; +#endif +} + + +static void pcmd_op (u1 opcode, + varid source1, varid source2, varid source3, varid dest) +{ + pcmd *c; + +#ifdef STATISTICS + c = list_last (pcmdlist); + if (c && (c->tag == TAG_LOADCONST_I)) + switch (opcode) { + case CMD_IASTORE: + case CMD_BASTORE: + case CMD_CASTORE: + case CMD_SASTORE: + count_pcmd_const_store++; + break; + case CMD_IADD: + case CMD_ISUB: + case CMD_IMUL: + case CMD_ISHL: + case CMD_ISHR: + case CMD_IUSHR: + case CMD_IAND: + case CMD_IOR: + case CMD_IXOR: + count_pcmd_const_alu++; + } +#endif + c = DNEW(pcmd); + if (dest) pcmd_invalidatevar (dest); + + c -> tag = TAG_OP; + c -> opcode = opcode; + c -> source1 = source1 ? var_findoriginal(source1) : NOVAR; + c -> source2 = source2 ? var_findoriginal(source2) : NOVAR; + c -> source3 = source3 ? var_findoriginal(source3) : NOVAR; + c -> dest = dest; + list_addlast (pcmdlist, c); +#ifdef STATISTICS + count_pcmd_op++; +#endif +} + + +static void pcmd_mem (u1 opcode, u2 type, varid base, varid source, + varid dest, u2 offset) +{ + pcmd *c; + +#ifdef STATISTICS + c = list_last (pcmdlist); + if (c && (c->tag == TAG_LOADCONST_I) && (opcode == CMD_PUTFIELD)) + count_pcmd_const_store++; +#endif + c = DNEW(pcmd); + if (dest) pcmd_invalidatevar (dest); + + c -> tag = TAG_MEM; + c -> opcode = opcode; + c -> source1 = base ? var_findoriginal(base) : NOVAR; + c -> source2 = source ? var_findoriginal(source) : NOVAR; + c -> source3 = NOVAR; + c -> dest = dest; + c -> u.mem.type = type; + c -> u.mem.offset = offset; + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_mem++; +#endif +} + + +static void pcmd_bra (u1 opcode, varid s1, varid s2, varid dest, basicblock *target) +{ + pcmd *c; + varid or1,or2; + +#ifdef STATISTICS + c = list_last (pcmdlist); + if (c && (c->tag == TAG_LOADCONST_I)) + switch (opcode) { + case CMD_IF_ICMPEQ: + case CMD_IF_ICMPNE: + case CMD_IF_ICMPLT: + case CMD_IF_ICMPGT: + case CMD_IF_ICMPLE: + case CMD_IF_ICMPGE: + count_pcmd_const_bra++; + } +#endif + c = DNEW(pcmd); + or1 = s1 ? var_findoriginal (s1) : NOVAR; + or2 = s2 ? var_findoriginal (s2) : NOVAR; + + pcmd_untieall(); + + c -> tag = TAG_BRA; + c -> opcode = opcode; + c -> source1 = or1; + c -> source2 = or2; + c -> source3 = NOVAR; + c -> dest = dest; + c -> u.bra.target = target; + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_bra++; +#endif +} + + +static void pcmd_trace (void *method) +{ + pcmd *c; + + isleafmethod = false; + + c = DNEW(pcmd); + c -> tag = TAG_BRA; + c -> opcode = CMD_TRACEBUILT; + c -> source1 = NOVAR; + c -> source2 = NOVAR; + c -> source3 = NOVAR; + c -> dest = NOVAR; + c -> u.a.value = method; + list_addlast (pcmdlist, c); +} + + +static void pcmd_bra_n_drop (u1 opcode, varid s1, varid s2, varid dest, basicblock *target) +{ + pcmd *c; + varid or1=NOVAR,or2=NOVAR; + bool isor1=false,isor2=false; + +#ifdef STATISTICS + c = list_last (pcmdlist); + if (c && (c->tag == TAG_LOADCONST_I)) + switch (opcode) { + case CMD_IF_ICMPEQ: + case CMD_IF_ICMPNE: + case CMD_IF_ICMPLT: + case CMD_IF_ICMPGT: + case CMD_IF_ICMPLE: + case CMD_IF_ICMPGE: + count_pcmd_const_bra++; + } +#endif + c = DNEW(pcmd); + if (s1!=NOVAR) { + or1 = var_findoriginal (s1); + if (! (isor1 = var_isoriginal(s1)) ) var_unlinkcopy (s1); + } + if (s2!=NOVAR) { + or2 = var_findoriginal (s2); + if (! (isor2 = var_isoriginal (s2)) ) var_unlinkcopy (s2); + } + + pcmd_untieall(); + + c -> tag = TAG_BRA; + c -> opcode = opcode; + c -> source1 = or1; + c -> source2 = or2; + c -> source3 = NOVAR; + c -> dest = dest; + c -> u.bra.target = target; + list_addlast (pcmdlist, c); + + if (isor1) pcmd_drop (s1); + if (isor2) pcmd_drop (s2); + +#ifdef STATISTICS + count_pcmd_bra++; +#endif +} + + +static void pcmd_tablejump (varid s, u4 targetcount, basicblock **targets) +{ + pcmd *c = DNEW(pcmd); + + pcmd_untieall(); + + c -> tag = TAG_TABLEJUMP; + c -> opcode = CMD_TABLEJUMP; + c -> source1 = var_findoriginal(s); + c -> source2 = NOVAR; + c -> source3 = NOVAR; + c -> dest = NOVAR; + c -> u.tablejump.targetcount = targetcount; + c -> u.tablejump.targets = targets; + list_addlast (pcmdlist, c); + +#ifdef STATISTICS + count_pcmd_table++; +#endif +} + + +/******* ATTENTION: Method does DROP automatically !!!!! ****/ + +static void pcmd_method (int opcode, methodinfo *mi, functionptr builtin, + int paramnum, varid *params, varid result, varid exceptionvar) +{ + varid v; + int i; + + pcmd *c = DNEW(pcmd); + + pcmd_untieall(); + + isleafmethod = false; + + reg_parlistinit(); + for (i = 0; i < paramnum; i++) { + v = params[i]; + var_proposereg(v, reg_parlistpar(var_type(v))); + } + + if (result) { + var_proposereg(result, reg_parlistresult(var_type(result))); + } + if (exceptionvar) { + exceptionvar -> reg = reg_parlistexception(); + } + + c -> tag = TAG_METHOD; + c -> opcode = opcode; + c -> source1 = c -> source2 = c -> source3 = NULL; + c -> dest = result; + c -> u.method.method = mi; + c -> u.method.builtin = builtin; + c -> u.method.paramnum = paramnum; + c -> u.method.params = params; + c -> u.method.exceptionvar = exceptionvar; + list_addlast (pcmdlist, c); + + for (i = 0; i < paramnum; i++) pcmd_drop(params[i]); + +#ifdef STATISTICS + count_pcmd_met++; +#endif +} + + + +static void pcmd_builtin1 (functionptr builtin, varid v1, varid result) +{ + varid *args = DMNEW (varid, 1); + args[0] = v1; + pcmd_method (CMD_BUILTIN, NULL, builtin, 1, args, result,NOVAR); +} + +static void pcmd_builtin2 (functionptr builtin, varid v1, varid v2, varid result) +{ + varid *args = DMNEW (varid, 2); + args[0] = v1; + args[1] = v2; + pcmd_method (CMD_BUILTIN, NULL, builtin, 2, args, result, NOVAR); +} + +static void pcmd_builtin3 (functionptr builtin, varid v1, varid v2, varid v3, varid result) +{ + varid *args = DMNEW (varid, 3); + args[0] = v1; + args[1] = v2; + args[2] = v3; + pcmd_method (CMD_BUILTIN, NULL, builtin, 3, args, result, NOVAR); +} + + +static void pcmd_display (pcmd *c) +{ + int i; + + switch (c -> tag) { + case TAG_LOADCONST_I: + printf (" LOADCONST_I #%ld -> ", + (long int) c -> u.i.value); + var_display (c -> dest); + printf ("\n"); + break; + case TAG_LOADCONST_L: +#if U8_AVAILABLE + printf (" LOADCONST_L #%ld -> ", (long int) c -> u.l.value); +#else + printf (" LOADCONST_L #HI: %ld LO: %ld -> ", + (long int) c->u.l.value.high, (long int) c->u.l.value.low ); +#endif + var_display (c -> dest); + printf ("\n"); + break; + case TAG_LOADCONST_F: + printf (" LOADCONST_F #%f -> ", (double) c -> u.f.value); + var_display (c -> dest); + printf ("\n"); + break; + case TAG_LOADCONST_D: + printf (" LOADCONST_D #%f -> ", c -> u.d.value); + var_display (c -> dest); + printf ("\n"); + break; + case TAG_LOADCONST_A: + printf (" LOADCONST_A #%p -> ", c -> u.a.value); + var_display (c -> dest); + printf ("\n"); + break; + + case TAG_MOVE: + printf (" MOVE_%1d ", c -> u.move.type); + var_display (c-> source1); + printf (" -> "); + var_display (c -> dest); + printf ("\n"); + break; + + case TAG_OP: + printf (" OP%3d ", c -> opcode); + var_display (c -> source1); + printf (", "); + var_display (c -> source2); + printf (", "); + var_display (c -> source3); + printf (" -> "); + var_display (c -> dest ); + printf ("\n"); + break; + + case TAG_BRA: + printf (" BRA%3d (", c -> opcode); + var_display (c -> source1); + printf (", "); + var_display (c -> source2); + printf (" -> "); + var_display (c -> dest); + if (c->u.bra.target) { + printf (") to pos %ld\n", + (long int) c -> u.bra.target -> jpc ); + } + else printf (")\n"); + break; + + case TAG_TABLEJUMP: + printf (" TABLEJUMP "); + var_display (c -> source1); + printf ("\n"); + for (i=0; i < (int) c->u.tablejump.targetcount; i++) { + printf (" %d: to pos %ld\n", (int) i, + (long int) c ->u.tablejump.targets[i] -> jpc ); + } + break; + + case TAG_MEM: + printf (" MEM%3d_%d ", c -> opcode, c -> u.mem.type); + var_display (c -> source2); + printf ("/"); + var_display (c -> dest); + printf (" <-> "); + printf ("%d [", (int) (c -> u.mem.offset) ); + var_display (c -> source1 ); + printf ("]\n"); + break; + + case TAG_METHOD: + printf (" METHOD%3d ", c -> opcode); + for (i=0; i < c -> u.method.paramnum; i++) { + var_display (c -> u.method.params[i]); + } + printf (" -> "); + var_display (c -> dest); + printf ("/"); + var_display (c->u.method.exceptionvar); + printf ("\n"); + break; + + case TAG_DROP: + printf (" [ DROP "); + var_display (c-> dest); + printf (" ]\n"); + break; + case TAG_ACTIVATE: + printf (" [ ACTIVATE "); + var_display (c-> dest); + printf (" ]\n"); + break; + + default: + printf (" ???\n"); + break; + } + +} diff --git a/comp/reg.c b/comp/reg.c new file mode 100644 index 000000000..c4b9bcfbe --- /dev/null +++ b/comp/reg.c @@ -0,0 +1,525 @@ +/******************************* comp/reg.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + The register-manager. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/23 + +*******************************************************************************/ + +/*********************** Structure of a register info *************************/ + +#define REG_TYPE_FLT 1 /* integer or floating point type */ +#define REG_SIZE_DBL 2 /* int/single or long/double */ +#define REG_INMEMORY 4 /* true if register is in memory */ +#define REG_ISFREE 8 /* true if register is currently free */ +#define REG_ISUNUSED 16 /* true if register never has been used */ +#define REG_ISFREEUNUSED 24 + +#define IS_INT_LNG_REG(a) (!((a)®_TYPE_FLT)) +#define IS_FLT_DBL_REG(a) ((a)®_TYPE_FLT) + +#define REGTYPE_INT 0 +#define REGTYPE_FLT 1 +#define REGTYPE_LNG 2 +#define REGTYPE_DBL 3 + +#define REGTYPE(a) ((a) & 3) + +typedef struct reginfo { + int typeflags; /* register type, size and flags */ + int num; /* register number or stack offset */ + list *waitlist; /* free list for register allocation */ + listnode linkage; +} reginfo; + + + +static reginfo *intregs = NULL; /* table for the integer registers */ +static reginfo *floatregs = NULL; /* table for the float registers */ +static int intregsnum; /* absolute number of integer registers */ +static int floatregsnum; /* absolute number of float registers */ + +static int intreg_ret; /* register to return integer values */ +static int intreg_exc; /* register to return exception value */ +static int intreg_arg1; /* register for first integer argument */ +static int intreg_argnum; /* number of integer argument registers */ + +static int floatreg_ret; /* register for return float values */ +static int floatreg_arg1; /* register for first float argument */ +static int floatreg_argnum; /* number of float argument registers */ + + +static list savedintslist; /* free saved int registers during allocation */ +static list savedfloatslist; /* free saved float registers during allocation*/ +static list scratchintslist; /* free temp int registers during allocation */ +static list scratchfloatslist; /* free temp float registers during allocation */ +static int *freeintregs; /* free int registers table */ +static int *freefloatregs; /* free float registers table */ + +static int savedregs_num; /* total number of registers to be saved */ +static int localvars_num; /* total number of variables to spilled */ +static int arguments_num; /* size of parameter field in the stackframe */ + + + +/****************** function reg_init ****************************************** + + initialises the register-allocator + +*******************************************************************************/ + +static void reg_init() +{ + int n; + + if (!intregs) { + for (intregsnum=0; regdescint[intregsnum] != REG_END; intregsnum++); + intregs = MNEW (reginfo, intregsnum); + freeintregs = MNEW (int, intregsnum + 2); + *freeintregs++ = 0; + freeintregs[intregsnum] = 0; + + intreg_arg1 = -1; + for (n=0; n typeflags |= REG_ISFREE; + + if (ri->waitlist) { + if (ri->typeflags & REG_INMEMORY) + list_addlast (ri->waitlist, ri); + else { +#if (WORDSIZE == 4) + reginfo *ri1; + + if (ri->typeflags & REG_TYPE_FLT) { + if (ri->typeflags & REG_SIZE_DBL) { + freefloatregs[ri->num] = 0; + freefloatregs[ri->num + 1] = 0; + ri1 = &floatregs[ri->num + 1]; + list_addfirst (ri1->waitlist, ri1); + } + else + freefloatregs[ri->num] = 0; + } + else { + if (ri->typeflags & REG_SIZE_DBL) { + freeintregs[ri->num] = 0; + freeintregs[ri->num + 1] = 0; + ri1 = &intregs[ri->num + 1]; + list_addfirst (ri1->waitlist, ri1); + } + else + freeintregs[ri->num] = 0; + } +#endif + list_addfirst (ri->waitlist, ri); + } + } +} + + +/******************* internal function reg_suckregister ************************ + + searches for the first register of a list which fullfills the requirements: + if argument isunused is true ri->typeflags®_ISUNUSED has to be true too + if register pairs are required two adjacent register are searched + if a register can be found it is removed from the free list and the + fields 'isunused' and 'isfree' are set to false + +*******************************************************************************/ + +static reginfo *reg_remove (list *l, int num) { + reginfo *ri; + + ri = list_first (l); + while (ri->num != num) + ri = list_next (l, ri); + if (ri->typeflags & REG_TYPE_FLT) + freefloatregs[num] = 0; + else + freeintregs[num] = 0; + list_remove (l, ri); + ri -> typeflags &= ~REG_ISFREEUNUSED; + return ri; +} + + +static reginfo *reg_suckregister (list *l, bool isunused) +{ + reginfo *ri; + + ri = list_first (l); + + while (ri) { + if ( (!isunused) || (ri->typeflags & REG_ISUNUSED)) { +#if (WORDSIZE == 4) + reginfo *retreg = NULL; + + if (ri->typeflags & REG_SIZE_DBL) { + if (ri->typeflags & REG_TYPE_FLT) + if (ri->num & 1) { + if(freefloatregs[ri->num - 1]) { + freefloatregs[ri->num] = 0; + retreg = reg_remove(l, ri->num - 1); + } + } + else { + if (freefloatregs[ri->num + 1]) { + freefloatregs[ri->num] = 0; + retreg = ri; + (void) reg_remove(l, ri->num + 1); + } + } + else if (freeintregs[ri->num + 1]) { + freeintregs[ri->num] = 0; + retreg = ri; + (void) reg_remove(l, ri->num + 1); + } + else if(freeintregs[ri->num - 1]) { + freeintregs[ri->num] = 0; + retreg = reg_remove(l, ri->num - 1); + } + if (retreg) { + list_remove (l, ri); + ri -> typeflags &= ~REG_ISFREEUNUSED; + return retreg; + } + } + else { + if (ri->typeflags & REG_TYPE_FLT) + freefloatregs[ri->num] = 0; + else + freeintregs[ri->num] = 0; + list_remove (l, ri); + ri -> typeflags &= ~REG_ISFREEUNUSED; + return ri; + } +#else + list_remove (l, ri); + ri -> typeflags &= ~REG_ISFREEUNUSED; + return ri; +#endif + } + ri = list_next (l, ri); + } + return NULL; +} + + +/******************** Funktion: reg_allocate ********************************** + + versucht, ein Register zu belegen, das vom richtigen Typ ist, und + allen gew"unschten Anforderungen entspricht. + + Parameter: + type .... JAVA-Grundtyp (INT,LONG,DOUBLE,FLOAT,ADDRESS) + saved ... Das Register soll bei Methodenaufrufen nicht zerst"ort werden + new ..... Das Register soll noch nie vorher verwendet worden sein + + Wenn es (aus verschiedenen Gr"unden) kein geeignetes freies Register f"ur + den Zweck mehr gibt, dann erzeugt diese Funktion einen Verweis auf + einen Platz am aktuellen Stackframe (diese Stackframe-Eintr"age erf"ullen + auf jeden Fall alle obigen Forderungen) + +*******************************************************************************/ + +static reginfo *reg_allocate (u2 type, bool saved, bool new) +{ + u2 t; + reginfo *ri; + + switch (type) { + case TYPE_LONG: + t = REG_SIZE_DBL; + break; + case TYPE_INT: + t = 0; + break; + case TYPE_FLOAT: + t = REG_TYPE_FLT; + break; + case TYPE_DOUBLE: + t = REG_TYPE_FLT | REG_SIZE_DBL; + break; + default: + t = 0; + } + + if (!saved) { + if (IS_INT_LNG_REG(t)) + ri = reg_suckregister (&scratchintslist, new); + else + ri = reg_suckregister (&scratchfloatslist, new); + if (ri) return ri; + } + + if (IS_INT_LNG_REG(t)) + ri = reg_suckregister (&savedintslist, new); + else + ri = reg_suckregister (&savedfloatslist, new); + if (ri) return ri; + + ri = DNEW (reginfo); + ri -> typeflags = t | REG_INMEMORY; +#if (WORDSIZE == 4) + ri -> num = localvars_num; + if (t & REG_SIZE_DBL) + localvars_num += 2; + else + localvars_num++; +#else + ri -> num = (localvars_num++); +#endif + ri -> waitlist = (IS_INT_LNG_REG(t)) ? &savedintslist : &savedfloatslist; + return ri; +} + + +/********************* Funktion: reg_reallocate ******************************* + + versucht, ein schon einmal angefordertes (aber in der Zwischenzeit + wieder freigegebenens) Register neuerlich anzufordern. + Wenn das Register immer noch unbenutzt ist, dann ist alles OK + (R"uckgabewert true), sonst wird 'false' zur"uckgeben, und aus der + neuerlichen Belegung wird nichts. + +******************************************************************************/ + +static bool reg_reallocate (reginfo *ri) +{ + if (!(ri->typeflags & REG_ISFREE)) return false; + + ri->typeflags &= ~REG_ISFREEUNUSED; + + if (ri->waitlist) list_remove (ri->waitlist, ri); + + return true; +} + + + +/****************** Funktion: reg_parlistresult ******************************* + + Erzeugt eine Registerreferenz auf das Register, das vom System zur + R"uckgabe von Werten aus Methoden verwendet wird. + Parameter: + type ... Der JAVA-Grundtyp des R"uckgabewertes + +******************************************************************************/ + +static reginfo *reg_parlistresult (u2 type) +{ + if (type==TYPE_FLOAT || type==TYPE_DOUBLE) return &(floatregs[floatreg_ret]); + else return &(intregs[intreg_ret]); +} + + + +/*************** Funktion: reg_parlistexception ****************************** + + Erzeugt eine Registerreferenz auf das Register, in dem das System die + Zeiger auf allf"allige Exception-Objekte bei Methodenaufrufen + zur"uckliefert. + +******************************************************************************/ + +static reginfo *reg_parlistexception () +{ + return &(intregs[intreg_exc]); +} + + + +/************************ Funktion: reg_parlistpar **************************** + + Erzeugt eine Registerreferenz auf ein Register, in dem das n"achste + Argument (in der Z"ahlung ab dem Zeitpunkt von Aufruf von 'reg_parlistinit') + bei Methodenaufrufen eingetragen wird. + Wenn es in Summe mehr als die m"oglichen Parameter-Register werden, dann + wird auch noch Platz am Stack f"ur die "uberz"ahligen Werte reserviert + +******************************************************************************/ + +static int usedintpar, usedfloatpar; +static int usedparoverflow; + +static reginfo *reg_parlistpar (u2 type) +{ + reginfo *f; + + if (type == TYPE_FLOAT || type == TYPE_DOUBLE) { + usedfloatpar++; + if (reg_parammode == PARAMMODE_NUMBERED) usedintpar++; + + if (usedfloatpar <= floatreg_argnum) { + f = &floatregs[floatreg_arg1 + (usedfloatpar - 1) ]; + f->typeflags &= ~REG_ISUNUSED; + return f; + } + else goto overflow; + } + else { + usedintpar++; + if (reg_parammode == PARAMMODE_NUMBERED) usedfloatpar++; + + if (usedintpar <= intreg_argnum) { + f = &intregs[intreg_arg1 + (usedintpar - 1) ]; + f->typeflags &= ~REG_ISUNUSED; + return f; + } + else goto overflow; + } + + + +overflow: + usedparoverflow++; + if (usedparoverflow > arguments_num) arguments_num = usedparoverflow; + return NULL; +} + + +/****************** Funktion: reg_parlistinit ********************************* + + initialisiert die Z"ahlung der Parameter-Register + +*******************************************************************************/ + +static void reg_parlistinit() +{ + usedintpar = 0; + usedfloatpar = 0; + usedparoverflow = 0; +} + + + + + +/***************** Funktion: reg_display ************************************* + + gibt eine Register-Referenz in lesbarer Form auf 'stdout' aus. + +******************************************************************************/ + +static void reg_display (reginfo *ri) +{ + if (ri->typeflags & REG_INMEMORY) { + printf ("[%d]", (int) (ri->num) ); + } + else { + printf ("%s%d", + (IS_INT_LNG_REG(ri->typeflags)) ? "$" : "f$", + (int) (ri->num) ); + } +} + + diff --git a/comp/regalloc.c b/comp/regalloc.c new file mode 100644 index 000000000..be3510357 --- /dev/null +++ b/comp/regalloc.c @@ -0,0 +1,148 @@ +/************************** comp/regalloc.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + The register-allocator. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/03/05 + +*******************************************************************************/ + + +/******************** Funktion: regalloc_doalloc ****************************** + + versucht f"ur ein Pseudoregister ein tats"achliches CPU-Register zu + belegen. + Wenn noch keine Belegung stattgefunden hat, dann wird ein passendes + gerade freies Register angefordert. + Wenn das Pseudoregsiter bereits vorher schon einmal ein Belegung + hatte, dann wird versucht, das selbe CPU-Register wie vorher wieder + anzufordern. Wenn es nicht gelingt (weil es schon wieder anderwertig + verwendet wird), wann wird eben ein ganz neues Register angefordert. + +******************************************************************************/ + +static void regalloc_doalloc (varinfo *v) +{ + if (v->reg) { + if (! reg_reallocate (v->reg)) { + v->reg = reg_allocate (v->type, v->saved, true); + } + } + else { + v->reg = reg_allocate (v->type, v->saved, false); + } +} + + + +/********************* Funktion: regalloc_activate **************************** + + setzt ein Pseudoregister auf aktiv (wenn es nicht schon + bereits aktiv ist), und fordert gegebenenfalls gleich ein passendes + CPU-Register an + Diese Operation wird aber nur bei Variablen mit lokalen Scope + gemacht. + +******************************************************************************/ + +static void regalloc_activate (varinfo *v) +{ + if (! v->globalscope) { + if (! var_isactive(v) ) { + regalloc_doalloc (v); + var_activate (v); + } + } +} + + +/******************** Funktion: regalloc_deactivate *************************** + + setzt ein Pseudoregister auf inaktiv (wenn es nicht schon inaktiv war) + +******************************************************************************/ + +static void regalloc_deactivate (varinfo *v) +{ + if (! v->globalscope) { + if (var_isactive(v) ) { + var_deactivate (v); + if (v->reg) reg_free (v->reg); + } + } +} + + +/******************** Funktion: regalloc_cmd ********************************** + + f"uhrt f"ur ein Pseudo-Command die Registerbelegung durch. + Wird von regalloc in einer Schleife aufgerufen. + +******************************************************************************/ + +static void regalloc_cmd (pcmd *c) +{ + switch (c->tag) { + case TAG_DROP: + regalloc_deactivate (c->dest); + break; + case TAG_METHOD: + if (c->u.method.exceptionvar) + regalloc_activate (c->u.method.exceptionvar); + if (c->dest) + regalloc_activate (c->dest); + break; + default: + if (c->dest) regalloc_activate (c->dest); + break; + } +} + + +/******************** Funktion: regalloc ************************************** + + f"uhrt f"ur einen ganzen Block die Registerbelegung durch. + +******************************************************************************/ + +static void regalloc (basicblock *b) +{ + stackinfo *tos; + pcmd *c; + varinfo *v; + + /* alle Pseudoregister am Stack, die schon eine Belegung haben, + wieder aktivieren */ + tos = b->stack; + while (tos) { + if (tos -> var -> reg) regalloc_activate(tos->var); + tos = tos->prev; + } + + /* alle anderen Pseudoregister am Stack belegen */ + tos = b->stack; + while (tos) { + regalloc_activate(tos->var); + tos = tos->prev; + } + + + /* alle Befehle abarbeiten und Registerbelegung machen */ + c = list_first (&b->pcmdlist); + while (c) { + regalloc_cmd (c); + c = list_next (&b->pcmdlist, c); + } + + + /* alle noch aktiven Pseudoregister deaktivieren */ + while ( (v = var_nextactive ()) != NULL) { + regalloc_deactivate (v); + } +} + diff --git a/comp/stack.c b/comp/stack.c new file mode 100644 index 000000000..a53beb227 --- /dev/null +++ b/comp/stack.c @@ -0,0 +1,241 @@ +/***************************** alpha/gen.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + behandeln des Java-Stacks + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + +static stackinfo *tos; /* Top of Stack */ + + + +/********************* Verwaltungsfunktionen *********************************/ + +static void stack_init() { tos = NULL; } + +static stackinfo *stack_get () { return tos; } + +static void stack_restore (stackinfo *s) { tos = s; } + +static bool stack_isempty () { return tos == NULL; } + + + +/********************** Funktion: stack_topslots ****************************** + + liefert die Anzahl der JavaVM-slots, die die oberste Pseudovariable am + Stack belegt (entweder 2 bei LONG und DOUBLE, oder 1 sonst) + +******************************************************************************/ + +static u2 stack_topslots () +{ + u2 t; + if (!tos) panic ("Stack is empty on attempt to determine top slots"); + + t = var_type (tos->var); + return ( (t==TYPE_LONG) || (t==TYPE_DOUBLE) ) ? 2 : 1; +} + + +/********************* Funktion: stack_push *********************************** + + erzeugt eine neues Pseudoregister eines gew"unschten Typs und gibt + es oben auf den Stack. + Ausserdem liefert die Funktion den Zeiger auf dieses Pseudoregister + +******************************************************************************/ + +static varinfo *stack_push (u2 type) +{ + stackinfo *s = DNEW (stackinfo); + + s -> prev = tos; + s -> var = var_create (type); + + tos = s; + return s -> var; +} + + +/********************** Funktion: stack_repush ******************************** + + Gibt ein bereits vorhandenen Pseudoregister auf den Stack + +******************************************************************************/ + +static void stack_repush (varinfo *v) +{ + stackinfo *s = DNEW (stackinfo); + + s -> prev = tos; + s -> var = v; + + tos = s; +} + + +/********************** Funktion: stack_pop *********************************** + + nimmt das oberste Pseudoregister vom Stack, dabei wird aber + "uberpr"uft, ob der Typ stimmt. + +******************************************************************************/ + +static varinfo *stack_pop (u2 type) +{ + varinfo *v; + + if (!tos) panic ("Stack is empty on attempt to pop"); + + v = tos -> var; + tos = tos -> prev; + + if (var_type (v) != type) panic ("Popped invalid element from stack"); + return v; +} + + +/********************* Funktion: stack_popany ******************************** + + nimmt das oberste Pseudoregister vom stack, ohne Typ"uberpr"ufung + durchzuf"uhren, wobei aber zumindest die Anzahl der notwendigen + Slots "ubereinstimmen muss. + +******************************************************************************/ + +static varinfo *stack_popany (u2 slots) +{ + varinfo *v; + + if (!tos) panic ("Stack is empty on attempt to pop"); + if (slots != stack_topslots() ) + panic ("Pop would tear LONG/DOUBLE-Datatype apart"); + + v = tos -> var; + tos = tos -> prev; + + return v; +} + + + +/********************** Funktion: stack_popmany ******************************* + + nimmt vom Stack soviele Pseudoregister, dass die Anzahl der von + ihnen belegten Slots die gew"unschte Menge ergeben. + Zeiger auf dieses Pseudoregister werden im Array vars gespeichert, und + deren tats"achliche Anzahl als Funktionswert zur"uckgeliefert. + (Haupts"achlich f"ur die Typneutralen DUP/POP.. Operationen) + +******************************************************************************/ + +static u2 stack_popmany (varid *vars, u2 slots) +{ + u2 ts; + u2 varcount=0; + + while (slots>0) { + ts=stack_topslots(); + if (ts > slots) panic ("POP would tear LONG/DOUBLE-Datatype apart"); + vars[(varcount)++] = stack_popany(ts); + slots -= ts; + } + return varcount; +} + + +/********************** Funktion: stack_pushmany ****************************** + + Gibt eine Anzahl von Pseudoregister auf den Stack. + +******************************************************************************/ + +static void stack_repushmany (u2 varcount, varid *vars) +{ + u2 i; + for (i=0; ivar; + v2 = then->var; + if (v1 != v2) { + t = var_type (v1); + if (t != var_type (v2)) + panic ("Mismatching stack types on join of control flow"); + + pcmd_move_n_drop (t, v1,v2); + } + + stack_jointail (now -> prev, then -> prev); + return; +} + +static void stack_addjoincode (stackinfo *targetstack) +{ + stack_jointail (tos, targetstack); + tos = targetstack; +} + + +/******************* Funktion: stack_makesaved ******************************** + + Kennzeichnet alle am Stack befindlichen Pseudoregister als + zu sichernde Register. + +*******************************************************************************/ + +static void stack_makesaved () +{ + stackinfo *s = tos; + while (s) { + var_makesaved (s->var); + s = s->prev; + } +} + + +/******************* Funktion: stack_display ********************************** + + Gibt den Inhalt des Stacks aus (also die Pseudoregister, die am + Stack liegen) + (Nur zu Debug-Zwecken) + +******************************************************************************/ + +static void stack_display (stackinfo *s) +{ + if (s) { + stack_display (s->prev); + var_display (s->var); + } +} + diff --git a/comp/tools.c b/comp/tools.c new file mode 100644 index 000000000..6a9216a79 --- /dev/null +++ b/comp/tools.c @@ -0,0 +1,208 @@ +/***************************** comp/tools.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Ein paar zus"atzlich notwendige Funktionen, die sonst nirgends + hinpassen. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + +/***************** Funktion: compiler_addinitclass **************************** + + zum Eintragen einer Klasse in die Liste der noch zu initialisierenden + Klassen + +******************************************************************************/ + +void compiler_addinitclass (classinfo *c) +{ + classinfo *cl; + + if (c->initialized) return; + + cl = chain_first(uninitializedclasses); + if (cl == c) + return; + + if (cl == class) + cl = chain_next(uninitializedclasses); + for (;;) { + if (cl == c) + return; + if (cl == NULL) { + if (runverbose) { + sprintf(logtext, "compiler_addinitclass: "); + unicode_sprint(logtext+strlen(logtext), c->name); + dolog(); + } + chain_addlast(uninitializedclasses, c); + return; + } + if (c < cl) { + if (runverbose) { + sprintf(logtext, "compiler_addinitclass: "); + unicode_sprint(logtext+strlen(logtext), c->name); + dolog(); + } + chain_addbefore(uninitializedclasses, c); + return; + } + cl = chain_next(uninitializedclasses); + } +} + + + +/***************** Hilfsfunktionen zum Decodieren des Bytecodes *************** + + lesen ein Datum des gew"unschten Typs aus dem Bytecode an der + angegebenen Stelle + +******************************************************************************/ + +static u1 code_get_u1 (u4 pos) +{ + return jcode[pos]; +} + +static s1 code_get_s1 (u4 pos) +{ + return code_get_u1 (pos); +} + +static u2 code_get_u2 (u4 pos) +{ + return ( ((u2) jcode[pos]) << 8 ) + jcode[pos+1]; +} + +static s2 code_get_s2 (u4 pos) +{ + return code_get_u2 (pos); +} + +static u4 code_get_u4 (u4 pos) +{ + return ( ((u4) jcode[pos]) << 24 ) + + ( ((u4) jcode[pos+1]) << 16 ) + + ( ((u4) jcode[pos+2]) << 8 ) + + ( jcode[pos+3] ); +} + +static s4 code_get_s4 (u4 pos) +{ + return code_get_u4 (pos); +} + + + +/******************** Funktion: descriptor2types ***************************** + + Decodiert einen Methoddescriptor. + Beim Aufruf dieser Funktion MUSS (!!!) der Descriptor ein + gueltiges Format haben (wird eh vorher vom loader ueberprueft). + + Die Funktion erzeugt ein Array von integers (u2), in das die + Parametertypen eingetragen werden, und liefert einen Zeiger auf + das Array in einem Referenzparameter ('paramtypes') zur"uck. + Die L"ange dieses Arrays und der Methodenr"uckgabewert werden ebenfalls + in Referenzparametern zur"uckgeliefert. + + Der Parameter 'isstatic' gibt an (wenn true), dass kein zus"atzlicher + erster Eintrag f"ur den this-Zeiger in das Array eingetragen + werden soll (sonst wird er n"amlich automatisch erzeugt, mit dem + Typ TYPE_ADDRESS). + +******************************************************************************/ + +static void descriptor2types (unicode *desc, bool isstatic, + s4 *paramnum, u1 **paramtypes, s4 *returntype) +{ + u2 *text = desc->text; + s4 pos; + u1 *types; + s4 tnum; + + tnum = (isstatic) ? 0 : 1; + pos=1; + while (text[pos] != ')') { + repeatcounting: + + switch (text[pos]) { + case '[': pos++; + goto repeatcounting; + case 'L': while (text[pos]!=';') pos++; + break; + } + pos++; + tnum++; + } + + types = DMNEW (u1, tnum); + + if (isstatic) tnum=0; + else { + types[0] = TYPE_ADDRESS; + tnum = 1; + } + pos=1; + while (text[pos] != ')') { + switch (text[pos]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': types[tnum++] = TYPE_INT; + break; + case 'J': types[tnum++] = TYPE_LONG; + break; + case 'F': types[tnum++] = TYPE_FLOAT; + break; + case 'D': types[tnum++] = TYPE_DOUBLE; + break; + case 'L': types[tnum++] = TYPE_ADDRESS; + while (text[pos] != ';') pos++; + break; + case '[': types[tnum++] = TYPE_ADDRESS; + while (text[pos] == '[') pos++; + if (text[pos] == 'L') while (text[pos] != ';') pos++; + break; + default: panic ("Ill formed methodtype-descriptor"); + } + pos++; + } + + pos++; /* ueberlesen von ')' */ + + switch (text[pos]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': *returntype = TYPE_INT; + break; + case 'J': *returntype = TYPE_LONG; + break; + case 'F': *returntype = TYPE_FLOAT; + break; + case 'D': *returntype = TYPE_DOUBLE; + break; + case '[': + case 'L': *returntype = TYPE_ADDRESS; + break; + case 'V': *returntype = TYPE_VOID; + break; + + default: panic ("Ill formed methodtype-descriptor"); + } + + *paramnum = tnum; + *paramtypes = types; +} + diff --git a/comp/var.c b/comp/var.c new file mode 100644 index 000000000..a1355a611 --- /dev/null +++ b/comp/var.c @@ -0,0 +1,361 @@ +/****************************** comp/var.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + verwaltet die Pseudoregister (die ich manchmal auch einfach nur + 'Variablen' nenne, daher der Namen des Programmteiles) + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + +s4 varnum; /* Anzahl der bereits vergebenen Variablen + (eigentlich nur, um den Variablen forlaufende + Nummern zu geben, damit man sie beim Debuggen + eindeutig kennzeichnen kann) */ + +list copiedvars; /* Liste aller Variablen die nur eine Kopie einer + anderen Variablen sind (w"ahrend der + Parse-Phase notwendig) */ +list activevars; /* Liste aller gerade aktiven Variablen + (f"ur die Registerbelegungs-phase notwendig) */ + +list vars; /* Liste aller Variablen, die nicht in einer der + obigen Listen sind */ + + +/********************** Funktion: var_init ************************************ + + initialisiert die Listen und den Variablen-Index-Z"ahler + +******************************************************************************/ + +static void var_init () +{ + varnum = maxlocals; + list_init (&vars, OFFSET (varinfo, linkage) ); + list_init (&copiedvars, OFFSET (varinfo, linkage) ); + list_init (&activevars, OFFSET (varinfo, linkage) ); +} + + +/********************* Funktion: var_type ************************************* + + Liefert den JavaVM-Grundtyp einer Variablen + +******************************************************************************/ + +static u2 var_type (varid v) +{ + return v->type; +} + + +/********************* Funktion: var_create *********************************** + + Erzeugt eine neue Variable des gew"unschten Typs + +******************************************************************************/ + +static varid var_create (u2 type) +{ + varinfo *v = DNEW (varinfo); + + list_addlast (&vars, v); + + list_init (&(v -> copies), OFFSET (varinfo, copylink) ); + v -> original = v; + + v -> type = type; + v -> number = varnum++; + v -> active = false; + v -> globalscope = false; + v -> saved = false; + + v -> reg = NULL; + + return v; +} + + +/***************** Funktion: var_createwithspecialnumber ********************** + + Erzeugt eine neue Variable des gew"unschten Typs, dabei wird aber als + Kennzeichnungsnummer eine vorgegebene Zahl verwendet (das brauche ich + um die lokalen Java-Variablen mit der Nummer des ihres Slots zu + kennzeichnen). + +******************************************************************************/ + +static varid var_createwithspecialnumber(u2 type, u4 num) +{ + varinfo *v = var_create (type); + varnum--; + v -> number = num; + return v; +} + + +/*************** Funktion: var_makesaved ************************************** + + Kennzeichnet eine Variable daf"ur, dass sie bei Methodenaufrufen nicht + zerst"ort werden darf. + +******************************************************************************/ + +static void var_makesaved (varid v) +{ + v -> saved = true; + v -> reg = NULL; +} + + +/*************** Funktion: var_proposereg ************************************* + + Macht dem Regiserallokator einen Vorschlag, mit welchem Register + eine Variable belegt werden sollte (bei Methodenaufrufen k"onnen so + viele Umlade-Befehle in die Argumentregister vermieden werden). + Aber: Die Anforderung, dass ein Register gesichert sein soll, hat auf + jeden Fall Priorit"at "uber so einen Vorschlag. + +******************************************************************************/ + +static void var_proposereg (varid v, reginfo *r) +{ + if (v -> saved) return; + + v -> reg = r; +} + + +/******************** Funktion: var_makecopy ********************************** + + kennzeichnet eine Variable daf"ur, dass sie nur eine Kopie einer anderen + Variable enth"alt. + +******************************************************************************/ + +static void var_makecopy (varid original, varid copy) +{ + list_addlast (&(original->copies), copy); + copy -> original = original; + + list_remove (&vars, copy); + list_addlast (&copiedvars, copy); +} + + +/******************** Funktion: var_unlinkcopy ******************************** + + eine Variable, die bis jetzt in der Liste der Kopien eingetragen + war, wird wieder auf normalen Zustand gebracht. + +******************************************************************************/ + +static void var_unlinkcopy (varid copy) +{ + list_remove (&(copy->original->copies), copy); + copy -> original = copy; + + list_remove (&copiedvars, copy); + list_addlast (&vars, copy); +} + + +/******************* Funktion: var_isoriginal ********************************* + + Liefert true, wenn die Variable selber das Original ist, und keine + Kopie einer anderen Variablen (das heisst, wenn sie nicht in der Liste + der Kopien eingetragen ist) + +******************************************************************************/ + +static bool var_isoriginal (varid copy) +{ + return (copy -> original == copy) ? true : false; +} + + +/******************* Funktion: var_findoriginal ******************************* + + Sucht zu einer Variablen das Original (wenn die Variable eine Kopie ist), + oder gibt die Variable selbst zur"uck (im anderen Fall). + +******************************************************************************/ + +static varid var_findoriginal (varid v) +{ + return v->original; +} + + +/******************* Funktion: var_nextcopy *********************************** + + Gibt die erste noch eingetragene Kopie einer Variablen zur"uck. + (oder NILL, wenn die Variable keine Kopien hat) + +******************************************************************************/ + +static varid var_nextcopy (varid original) +{ + return list_first (&original->copies); +} + + +/******************* Funktion: var_nextcopiedvar ****************************** + + Gibt die erste "uberhaupt noch vorhandene Variable zu"uck, die eine + Kopie irgendeiner anderen Variablen ist. + +******************************************************************************/ + +static varid var_nextcopiedvar () +{ + return list_first (&copiedvars); +} + + + +/*********************** Funktion: var_isactive ******************************* + + Lieftert true, wenn die Variable gerade aktiviert ist (d.h., wenn + irgendwann vorher 'var_activate' aufgerufen wurde) + +******************************************************************************/ + +static bool var_isactive (varinfo *v) +{ + return v->active; +} + + +/******************** Funktion: var_activate ********************************** + + Aktiviert eine Variable, d.h. sie wird in die Liste der aktiven + Variablen eingetragen. + +******************************************************************************/ + +static void var_activate (varinfo *v) +{ + list_remove (&vars, v); + list_addlast (&activevars, v); + v -> active = true; +} + + +/******************** Funktion: var_deactivate ******************************** + + Deaktiviert eine Variable (Gegenst"uck zu var_activate) + +******************************************************************************/ + +static void var_deactivate (varinfo *v) +{ + list_remove (&activevars, v); + list_addlast (&vars, v); + v -> active = false; +} + + +/****************** Funktion: var_nextactive ********************************** + + Liefert die erste noch aktivierte Variable + +******************************************************************************/ + +static varinfo *var_nextactive () +{ + return list_first (&activevars); +} + + + +/**************************** Funktion: var_display ************************** + + Gibt eine abdruckbare Darstellung einer Variablen aus. + (nur zu Debug-Zwecken) + +*****************************************************************************/ + +static void var_display (varinfo *v) +{ + if (v==NOVAR) { + printf ("_ "); + return; + } + + switch (v->type) { + case TYPE_INT: printf ("I"); break; + case TYPE_LONG: printf ("L"); break; + case TYPE_FLOAT: printf ("F"); break; + case TYPE_DOUBLE: printf ("D"); break; + case TYPE_ADDRESS: printf ("A"); break; + default: printf ("?"); + } + printf ("%d", v->number); + + if (v->reg) { + printf ("(="); + reg_display (v->reg); + printf (")"); + } + printf (" "); +} + + +/************************ Funktion: var_displayall ************************** + + Gibt eine abdruckbare Darstellung aller Variablen aus. + (nur zu Debug-Zwecken) + +*****************************************************************************/ + +void var_displayall () +{ + varid v; + int num=0; + varid *sorted = DMNEW (varid, varnum); + + printf ("\n Types of all pseudo-variables:\n"); + + for (num=0; numnumber]) { + printf (" Local variable overlay: "); + if (v->saved) printf ("* "); + else printf (" "); + + var_display (v); + printf ("\n"); + } + else sorted[v->number] = v; + + v = list_next (&vars, v); + } + + + for (num=0; numsaved) printf ("* "); + else printf (" "); + + var_display (v); + if (!v->reg) printf (" "); + + if ( (num%5) == 4 ) printf ("\n"); + else printf ("\t"); + } + } + + printf ("\n"); +} + + diff --git a/compiler.c b/compiler.c new file mode 100644 index 000000000..18f0949c6 --- /dev/null +++ b/compiler.c @@ -0,0 +1,429 @@ +/****************************** compiler.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt die Funktionen mit denen die JavaVM - Methoden in Maschinencode + "ubersetzt werden. + Ein Aufruf vom compiler_compile "ubersetzt genau eine Methode. + Alle in diesem Modul global definierten Variablen gelten nur f"ur + eben diese gerade in der "Ubersetzung befindlichen Methode. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/22 + +*******************************************************************************/ + +#include "global.h" +#include "compiler.h" + +#include "loader.h" +#include "tables.h" +#include "builtin.h" +#include "native.h" +#include "asmpart.h" + +#include "threads/thread.h" /* schani */ + + +/*************************** globale Schalter ********************************/ + +extern int newcompiler; +methodptr new_compile (methodinfo *m); /* compile a method with new compiler */ + +/************************** no all in newcomp.c + +bool compileverbose = false; +bool showstack = false; +bool showintermediate = false; +bool showdisassemble = false; +int optimizelevel = 0; + +bool checkbounds = true; +bool checknull = true; +bool checkfloats = true; +bool checksync = true; + +bool getcompilingtime = false; +long int compilingtime = 0; +int has_ext_instr_set = 0; + +bool statistics = false; + +int count_jit_calls = 0; +int count_methods = 0; +int count_spills = 0; +int count_pcmd_activ = 0; +int count_pcmd_drop = 0; +int count_pcmd_zero = 0; +int count_pcmd_const_store = 0; +int count_pcmd_const_alu = 0; +int count_pcmd_const_bra = 0; +int count_pcmd_load = 0; +int count_pcmd_move = 0; +int count_pcmd_store = 0; +int count_pcmd_store_comb = 0; +int count_pcmd_op = 0; +int count_pcmd_mem = 0; +int count_pcmd_met = 0; +int count_pcmd_bra = 0; +int count_pcmd_table = 0; +int count_pcmd_return = 0; +int count_pcmd_returnx = 0; +int count_check_null = 0; +int count_javainstr = 0; +int count_javacodesize = 0; +int count_javaexcsize = 0; +int count_calls = 0; +int count_tryblocks = 0; +int count_code_len = 0; +int count_data_len = 0; +int count_cstub_len = 0; +int count_nstub_len = 0; + +********************/ + + +/************************ die Datentypen f"ur den Compiler *******************/ + +#include "comp/defines.c" + + + +/******************* globale Variablen fuer den Compiler *********************/ + +static methodinfo *method; /* Zeiger auf die Methodenstruktur */ +static unicode *descriptor; /* Typbeschreibung der Methode */ +static classinfo *class; /* Klasse, in der die Methode steht */ + +static s4 maxstack; /* maximale Gr"osse des JavaVM-Stacks */ +static s4 maxlocals; /* maximale Anzahl der JavaVM-Variablen */ +static u4 jcodelength; /* L"ange des JavaVM-Codes */ +static u1 *jcode; /* Zeiger auf den JavaVM-Code */ +static s4 exceptiontablelength; /* L"ange der Exceptiontable */ +static exceptiontable *extable; /* Zeiger auf die Exceptiontable */ + + +static list reachedblocks; /* Die Listenstruktur f"ur alle vom Parser + bereits irgendwie erreichten Bl"ocke */ +static list finishedblocks; /* Die Listenstruktur f"ur alle Bl"ocke, die + vom Parser bereits durchgearbeitet wurden */ + +static basicblock **blocks; /* Eine Tabelle, so lang wie der JavaVM-Code, */ + /* in der an jeder Stelle, an der ein */ + /* Basicblock beginnt, der Zeiger auf die */ + /* ensprechende Basicblock-Struktur einge- */ + /* tragen ist. */ + +static bool isleafmethod; /* true, wenn die Methode KEINE weiteren + Unterprogramme mehr aufruft */ + +static s4 mparamnum; /* Die Anzahl der Parameter (incl. this) */ +static u1 *mparamtypes; /* Die Typen aller Parameter (TYPE_INT,...) */ +static s4 mreturntype; /* R"uckgabewert der Methode */ +static varinfo **mparamvars; /* Die PCMD-Variablen, die die Parameter */ + /* zu Methodenstart enthalten sollen */ + + +static chain *uninitializedclasses; + /* Eine Tabelle aller von der Methode */ + /* irgendwie ben"otigten Klassen, die */ + /* vor dem Start der Methode initialisiert */ + /* werden m"ussen (wenn sie es noch nicht */ + /* sind) */ + + +/************************ Subsysteme des Compilers ***************************/ + + +#include "comp/tools.c" /* ein paar n"utzliche Hilfsfunktionen */ +#include "comp/mcode.c" /* systemUNabh"angiger Teil des Codegenerators */ + +#include "comp/reg.c" /* Registerverwaltung */ +#include "comp/var.c" /* Die Verwaltung der PCMD-Variblen */ +#include "comp/pcmd.c" /* Funktionen f"ur die Pseudocommandos (=PCMD) */ +#include "comp/local.c" /* Verwaltung der lokalen JavaVM-Variablen */ +#include "comp/stack.c" /* Verwaltung des JavaVM-Stacks */ +#include "comp/regalloc.c" /* Registerallokator */ + +#include "sysdep/gen.c" /* systemABh"angiger Codegenerator */ +#include "sysdep/disass.c" /* Disassembler (nur zu Debug-Zwecken) */ + +#include "comp/block.c" /* Verwaltung der basic blocks */ +#include "comp/parse.c" /* JavaVM - parser */ + + + + +/****** Die Dummy-Function (wird verwendet, wenn kein Code vorhanden ist) ****/ + +static void* do_nothing_function() +{ + return NULL; +} + + + + +/******************************************************************************/ +/*********************** eine Methode compilieren *****************************/ +/******************************************************************************/ + + +methodptr compiler_compile (methodinfo *m) +{ + u4 i; + basicblock *b; + long int starttime=0,stoptime=0; + long int dumpsize; + + if (newcompiler) { + return new_compile(m); + } + + /*** Wenn schon ein Maschinencode vorliegt, dann sofort beenden ****/ + + count_jit_calls++; /* andi */ + if (m->entrypoint) return m->entrypoint; + + intsDisable(); /* schani */ + + + /**************** Marke fuer den DUMP-Speicher aufheben *****************/ + + dumpsize = dump_size (); + + + /**************** Zeit messen *******************************************/ + + count_methods++; /* andi */ + if (getcompilingtime) starttime=getcputime(); + + /*** Meldung ausgeben. Wenn kein JavaVM-Code vorhanden ist, beenden ****/ + + if (m->jcode) { + if (compileverbose) { + sprintf (logtext, "Compiling: "); + unicode_sprint (logtext+strlen(logtext), m->class->name); + strcpy (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), m->name); + unicode_sprint (logtext+strlen(logtext), m->descriptor); + dolog (); + } + } + else { + sprintf (logtext, "No code given for: "); + unicode_sprint (logtext+strlen(logtext), m->class->name); + strcpy (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), m->name); + unicode_sprint (logtext+strlen(logtext), m->descriptor); + dolog (); + intsRestore(); /* schani */ + return (methodptr) do_nothing_function; + } + + + /*********** Initialisieren der Variablen und Subsysteme *****************/ + + isleafmethod = true; /* bis sich das Gegenteil herausstellt */ + + method = m; + descriptor = m->descriptor; + class = m->class; + + maxstack = m->maxstack; + maxlocals = m->maxlocals; + jcodelength = m->jcodelength; + jcode = m->jcode; + count_tryblocks += (exceptiontablelength = m->exceptiontablelength); + extable = m->exceptiontable; + +#ifdef STATISTICS + count_javacodesize += jcodelength + 18; + count_javaexcsize += exceptiontablelength * 8; +#endif + + list_init (&reachedblocks, OFFSET(basicblock, linkage) ); + list_init (&finishedblocks, OFFSET(basicblock, linkage) ); + + blocks = DMNEW (basicblock*, jcodelength); + for (i=0; iflags & ACC_STATIC) != 0, + &mparamnum, &mparamtypes, &mreturntype); + m->paramcount = mparamnum; + m->returntype = mreturntype; + mparamvars = DMNEW (varid, mparamnum); + + reg_init (); + mcode_init (); + var_init(); + local_init(); + + uninitializedclasses = chain_new(); + /* aktuelle Klasse zur Liste der m"oglicherweise zu + initialisierenden Klassen dazugeben */ + compiler_addinitclass (m->class); + + + /************************ Compilieren ************************/ + + /* Fuer jedes Sprungziel einen eigenen Block erzeugen */ + block_firstscann (); + + /* Den ersten Block als erreicht markieren, der Stack ist leer */ + stack_init(); + subroutine_set(NULL); + block_reach ( block_find(0) ); + + /* Alle schon erreichten Bl"ocke durchgehen und fertig machen */ + while ( (b = list_first (&reachedblocks)) ) { + list_remove (&reachedblocks, b); + list_addlast (&finishedblocks, b); + b -> finished = true; + + pcmd_init ( &(b->pcmdlist) ); + parse (b); + } + + input_args_prealloc (); + + /* F"ur alle Bl"ocke die Registerbelegung durchfuehren */ + b = list_first (&finishedblocks); + while (b) { + regalloc (b); + b = list_next (&finishedblocks, b); + } + + + /* Registerbelegung fuer die lokalen JAVA-Variablen */ + local_regalloc (); + + + + + /**************** Maschinencode generieren **********************/ + + gen_computestackframe (); + gen_header (); + + + for (i=0; ireached) block_genmcode (b); + } + + b = list_first (&finishedblocks); + while (b) { + if (b->type != BLOCKTYPE_JAVA) block_genmcode (b); + b = list_next (&finishedblocks, b); + } + + + mcode_finish (); + + + /*********** Zwischendarstellungen auf Wunsch ausgeben **********/ + + if (showintermediate) { + printf ("Leaf-method: %s\n", isleafmethod ? "YES":"NO"); + printf ("Parameters: "); + for (i=0; ireached) block_display (b); + } + b = list_first (&finishedblocks); + while (b) { + if (b->type != BLOCKTYPE_JAVA) block_display (b); + b = list_next (&finishedblocks, b); + } + + var_displayall(); + fflush (stdout); + } + + if (showdisassemble) { + dseg_display (); + disassemble ( (void*) (m->mcode + dseglen), mcodelen); + fflush (stdout); + } + + + + /***************** Dump-Speicher zurueckgeben *************/ + + dump_release (dumpsize); + + + /******************* Zeit messen **************************/ + + if (getcompilingtime) { + stoptime = getcputime(); + compilingtime += (stoptime-starttime); + } + + /******** Alle Klassen initialisieren, die gebraucht wurden *******/ + + { + chain *u = uninitializedclasses; /* wegen reentrant-F"ahigkeit */ + classinfo *c; /* d"urfen ab hier keine */ + /* globalen Variablen verwendet */ + while ( (c = chain_first(u)) ) { /* werden */ + chain_remove (u); + + class_init (c); /* ruft unter Umst"anden wieder */ + /* den Compiler auf */ + } + chain_free (u); + } + + intsRestore(); /* schani */ + + + + /****** Return pointer to the methods entry point **********/ + + return m -> entrypoint; + +} + + + +/***************** Funktionen zum Initialisieren und Terminieren *************/ + +void compiler_init () +{ + u4 i; + + has_ext_instr_set = ! has_no_x_instr_set(); + + for (i=0; i<256;i++) stdopdescriptors[i]=NULL; + + for (i=0; i siehe oben) enth"alt. +Der Codegenerator kann sich darauf verlassen, dass jeder varinfo-Struktur, +die "uber ein pcmd erreichbar ist, auch ein entsprechendes reginfo zugewiesen +wurde. + + + +------------------------------------------------------------------------------ +Die pcmd-Struktur +------------------------------------------------------------------------------ + +Hier finden sich alle Informationen, die die Funktion 'gen_pcmd' +braucht, um damit Maschinencode f"ur ein Pseudokommando zu erzeugen. +Die Syntax dieser Struktur (mit Kommentaren) befindet sich unter anderem +in der Datei 'defines.c'. + +F"ur verschiedene Typen von Kommandos muss die Struktur verschiedene +Daten enthalten, deshalb ist sie mit Hilfe einer 'union' realisiert, +und ein tag-Feld gibt den tats"achlichen Typ der Struktur an (jaja, in +C gibt es eben keine abgeleiteten Datentypen ...). +Die Werte und Bezeichnung f"ur dieses Tag-Feld steht ebenfalls in der +Datei 'defines.c' + + +Beschreibung der allgemeinen Felder der 'pcmd'. + + linkage ... interne Verkettung, f"ur den Codegenerator ohne Bedeutung) + tag ....... Kennzeichnung des Typs des Kommandos + + dest ...... Pseudoregister f"ur eine optionalen Zieloperanden + source1 ... Pseudoregister f"ur den 1. optionalen Quelloperanden + source2 ... 2. + source3 ... 3. + +Alle Kommandos (ausser unbedingten Spr"ungen) haben in irgendeiner Form +Operanden-Register. Dabei stehen Register aus denen ein Wert geholt wird +in den Feldern source1-source3, und ein Register in das ein Wert geschrieben +wird, steht im Feld dest. Alle unbenutzen Felder haben immer den +Wert NULL. + +Alle Befehle haben eine genau definierte Anzahl von Operanden, deren +Typ ausserdem auf jeden Fall stimmt (die Register wurden zuvor mit +'reg_allocate' unter Angabe des richtigen Typs angefordert). + + +Die Befehlstypen +---------------- + + LOADCONST_I + LOADCONST_L + LOADCONST_F + LOADCONST_D + LOADCONST_A + Jeder dieser Befehle l"adt einen Wert vom entsprechenden + Typ in das Zielregister. + Diese konstanten Werte selber stehen in + pcmd->i.value, pcmd->l.value ... + + MOVE + Kopiert einen Wert vom Quellregister 1 ins Zielregister. + Beide Register haben den Typ pcmd->move.type . + + OP + F"uhrt eine JavaVM-Grundoperation aus. + Im Feld pcmd->op.opcode steht der JavaVM-Opcode des gew"unschten + Befehls. + Die Anzahl und die Typen der Operanden sind f"ur jede Operation + anders. Eine genaue Beschreibung der Semantik findet sich + in der JavaVM-Spezifikation. Dabei sind die Quelloperanden + in der Reihenfolge wie sie in der Spezifikation am Stack stehen + (von links nach rechts), in die Quellregister 1 bis 3 aufgeteilt. + Bei Operanden vom Typ LONG oder DOUBLE sind beide 'value-words' + in einem Register zusammengefasst. + + MEM + L"adt entweder einen Wert aus dem Speicher, oder schreibt + einen Wert dorthin. + Das Feld pcmd->mem.opcode enth"alt dazu entweder CMD_GETFIELD + oder CMD_PUTFIELD. + In pcmd->mem.type steht der Java-Grunddatentyp dieses + Feldes, und in pcmd->mem.offset steht der konstante Offset (in Byte), + der zum Basisregister (pcmd->source1) addiert werden soll, um die + tats"achliche Speicheradresse des Felds zu bekommen. + Bei Ladeoperationen steht das Ergebnis nachher im Register + pcmd->dest, bei Speicheroperationen steht der zu speichernde + Wert im Register pcmd->source2. + + BRA + F"uhrt bedingte oder unbedingte Spr"unge aus. Im Feld + pcmd->bra.opcode steht der entsprechende JavaVM-Opcode. + Die Operanden (die laut JavaVM-Spec am Stack stehen m"ussen) + sind in den Registern pcmd->source1 und pcmd-source2 zu finden + (ganz analog zu dene OP-Kommandos). + Spezielle Formen: + JSR: Hier soll die R"ucksprungadresse ins Register pcmd-dest + geschrieben werden. + RET: Obwohl laut JavaVM-Spec dieser Befehl den Stack nicht + beeinflusst, hat er dennoch einen Operanden: pcmd->source1 + enth"alt die R"ucksprungadresse + + IRETURN bis ARETURN + und RETURN: + in pcmd->source1 befindet sich der R"uckgabewert + (ausgenommen bei RETURN), und + in pcmd->source2 ist der Zeiger auf die zu werfende + Exception. + + Das Sprungziel (insofern bei dem Befehl eines m"oglich ist) wird + als Zeiger auf eine basicblock-Struktur "ubergeben. + Zum Aufl"osen der Sprungziele siehe: mcode_addreference. + + TABLEJUMP + Fu"hrt eine Programmverzweigung "uber eine Sprungtabelle durch. + Der einzige Operand (pcmd->source1) ist im Bereich von + i = 0 .. pcmd->tablejump.targetcount-1. Der Befehl soll an das + dementsprechende Sprungziel pcmd->tablejump.targets[i] verzweigen. + Zur Konstruktion einer Sprungtabelle siehe: dseg_addtarget. + + + METHOD + F"uhrt einen Methoden (bzw. C-Funktions-) -aufruf durch. + Die Felder pcmd->method.paramnum und pcmd->method.params[..] + geben die Anzahl und die Register an, in denen die Parameter + stehen. Unter (g"unstigen) Umst"anden sind einige der Register + schon diejenigen, die durch die Aufrufkonventionen die Parameter + enthalten sollen (wenn das nicht der Fall ist, dann m"ussen + die Werte vor dem Aufruf noch umgeladen werden). + Das Feld pcmd->method.exceptionvar enth"alt (wenn es nicht + NULL ist) die Variable, in der eine allf"allig aufgetretene + Exception zur"uckerwartet wird. + Der normale R"uckgabewert der Methode soll ins Register + pcmd->dest geschrieben werden. + + Dieses Pseudokommando wird sowohl f"ur Aufrufe von normalen + C-Funktionen (dann steht im Feld pcmd->method->builtin der + Zeiger auf diese Funktion) als auch f"ur Aufrufe von Java-Methoden + verwendet (dann steht im Feld pcmd->method->builtin der + Wert NULL). + + Im zweiten Fall enth"alt das Feld pcmd->method->method einen + Zeiger auf die methodinfo-Struktur der gew"unschten Methode. + Bei Aufrufen vom Typ INVOKESTATIC und INVOKESPECIAL + (der Typ steht in pcmd->method->opcode) braucht dazu nur + der Funktionszeiger von dort geladen werden. + Bei INVOKEVIRTUAL und INVOKEINTERFACE muss der Funktionszeiger + aus der Virtual Function Table der Klasse des tats"achlichen + Objektes geholt werden. Der Zeiger auf dieses Objekt ist immer + im Register pcmd->method->params[0] zu finden. + Eine Beschreibung dieser Tabellen steht in der Datei "global.h". + + WICHTIG: Dieses System compiliert alle Methoden beim ersten + Aufruf, deshalb m"ussen alle Methodenaufrufe immer mit dem + Umweg "uber die methodinfo-Struktur passieren, weil nur dort + dann der tats"achliche Funktionszeiger eingetragen wird. + Wenn die Methode n"amlich noch nicht aufgerufen wurde, dann + steht dort ein Zeiger auf den Compiler selbst. + Der Compiler ben"otigt f"ur seine Arbeit aber noch zus"atzlich + den Zeiger auf die methodinfo-Struktur in einem fixen + Register. Auf der DEC-ALPHA verwende ich hier das Register 28. + Die Aufrufsequenz auf der DEC-ALPHA f"ur einen normalen + INVOKESTATIC-Aufruf w"urde ungef"ahr so aussehen: + + LDQ (28, 27, position_des_methodinfo_zeigers_im_datensegment) + LDQ (27, 28, OFFSET(methodinfo, func) ) + JSR (26, 27) + LDA (27, 26, -position_dieses_befehls_im_code) + + + + +------------------------------------------------------------------------------- +Anhang: Notwendige Opcodes + +F"ur die Befehle vom Typ OP m"ussen folgende Opcodes unterst"utzt werden: + CMD_INEG + CMD_LNEG + CMD_FNEG + CMD_DNEG + CMD_I2L + CMD_L2I + CMD_INT2BYTE + CMD_INT2CHAR + CMD_INT2SHORT + CMD_IADD + CMD_LADD + CMD_FADD + CMD_DADD + CMD_ISUB + CMD_LSUB + CMD_FSUB + CMD_DSUB + CMD_IMUL + CMD_LMUL + CMD_FMUL + CMD_DMUL + CMD_FDIV + CMD_DDIV + CMD_FREM + CMD_DREM + CMD_ISHL + CMD_ISHR + CMD_IUSHR + CMD_LSHL + CMD_LSHR + CMD_LUSHR + CMD_IAND + CMD_LAND + CMD_IOR + CMD_LOR + CMD_IXOR + CMD_LXOR + CMD_I2F + CMD_L2F + CMD_I2D + CMD_L2D + CMD_F2I + CMD_D2I + CMD_F2L + CMD_D2L + CMD_F2D + CMD_D2F + CMD_LCMP + CMD_FCMPL + CMD_DCMPL + CMD_FCMPG + CMD_DCMPG + CMD_ARRAYLENGTH + CMD_AALOAD + CMD_LALOAD + CMD_IALOAD + CMD_FALOAD + CMD_DALOAD + CMD_CALOAD + CMD_SALOAD + CMD_BALOAD + CMD_AASTORE + CMD_LASTORE + CMD_IASTORE + CMD_FASTORE + CMD_DASTORE + CMD_CASTORE + CMD_SASTORE + CMD_BASTORE + +F"ur die Befehle vom Typ MEM m"ussen folgende Opcodes unterst"utzt werden: + CMD_PUTFIELD: + CMD_GETFIELD: + + +F"ur die Befehle vom Typ BRA m"ussen folgende Opcodes unterst"utzt werden: + CMD_GOTO + CMD_JSR + CMD_RET + CMD_IFEQ + CMD_IFNULL + CMD_IFLT + CMD_IFLE + CMD_IFNE + CMD_IFNONNULL + CMD_IFGT + CMD_IFGE + CMD_IF_ICMPEQ + CMD_IF_ACMPEQ + CMD_IF_ICMPNE + CMD_IF_ACMPNE + CMD_IF_ICMPLT + CMD_IF_ICMPGT + CMD_IF_ICMPLE + CMD_IF_ICMPGE + CMD_IRETURN + CMD_LRETURN + CMD_ARETURN + CMD_FRETURN + CMD_DRETURN + CMD_RETURN + + + +F"ur die Befehle vom Typ METHOD m"ussen folgene Opcodes unterst"utzt werden: + CMD_INVOKESTATIC + CMD_INVOKESPECIAL + CMD_INVOKEVIRTUAL + CMD_INVOKEINTERFACE diff --git a/global.h b/global.h new file mode 100644 index 000000000..e92f7f116 --- /dev/null +++ b/global.h @@ -0,0 +1,542 @@ +/****************************** global.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains global definitions which are used in the whole program, includes + some files and contains global used macros. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Chages: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/28 + +*******************************************************************************/ + +#ifndef __global_h_ +#define __global_h_ /* schani */ + +#define STATISTICS /* andi */ + +/***************************** standard includes ******************************/ + +#include +#include +#include +#include + +#include "toolbox/memory.h" +#include "toolbox/chain.h" +#include "toolbox/list.h" +#include "toolbox/loging.h" + + +/**************************** system dependent types **************************/ + +#include "sysdep/types.h" + + +/**************************** additional data types ***************************/ + +typedef void *voidptr; /* generic pointer */ + + +typedef u1 bool; /* boolean data type */ + +#define true 1 +#define false 0 + +typedef void (*functionptr) (); /* generic function pointer */ + + +#define MAX_ALIGN 8 /* most generic alignment for JavaVM values */ + + +/**************************** shutdown function *******************************/ + +void cacao_shutdown(s4 status); + + +/**************************** basic data types ********************************/ + +#define TYPE_INT 0 /* the JavaVM types must numbered in the */ +#define TYPE_LONG 1 /* same order as the ICMD_Ixxx to ICMD_Axxx */ +#define TYPE_FLOAT 2 /* instructions (LOAD and STORE) */ +#define TYPE_DOUBLE 3 /* integer, long, float, double, address */ +#define TYPE_ADDRESS 4 /* all other types can be numbered arbitrarily*/ + +#define TYPE_VOID 10 + + +/**************************** Java class file constants ***********************/ + +#define MAGIC 0xcafebabe +#define MINOR_VERSION 3 +#define MAJOR_VERSION 45 + +#define CONSTANT_Class 7 +#define CONSTANT_Fieldref 9 +#define CONSTANT_Methodref 10 +#define CONSTANT_InterfaceMethodref 11 +#define CONSTANT_String 8 +#define CONSTANT_Integer 3 +#define CONSTANT_Float 4 +#define CONSTANT_Long 5 +#define CONSTANT_Double 6 +#define CONSTANT_NameAndType 12 +#define CONSTANT_Utf8 1 + +#define CONSTANT_Arraydescriptor 13 +#define CONSTANT_UNUSED 0 + + +#define ACC_PUBLIC 0x0001 +#define ACC_PRIVATE 0x0002 +#define ACC_PROTECTED 0x0004 +#define ACC_STATIC 0x0008 +#define ACC_FINAL 0x0010 +#define ACC_SYNCHRONIZED 0x0020 +#define ACC_VOLATILE 0x0040 +#define ACC_TRANSIENT 0x0080 +#define ACC_NATIVE 0x0100 +#define ACC_INTERFACE 0x0200 +#define ACC_ABSTRACT 0x0400 + + + +/**************************** resolve typedef-cycles **************************/ + +typedef struct unicode unicode; +typedef struct classinfo classinfo; +typedef struct vftbl vftbl; +typedef u1* methodptr; + + +/********************** data structures of UNICODE symbol *********************/ + +struct unicode { + unicode *hashlink; /* externe Verkettung f"ur die unicode-Hashtabelle */ + u4 key; /* Hash-Schl"ussel (h"angt nur vom Text ab) */ + int length; /* L"ange des Textes */ + u2 *text; /* Zeiger auf den Text (jeder Buchstabe 16 Bit) */ + classinfo *class; /* gegebenenfalls Referenz auf die Klasse dieses + Namens (oder NULL, wenn es keine solche gibt) */ + struct java_objectheader *string; + /* gegebenenfalls Referenz auf einen konstanten + String mit dem entsprechenden Wert */ + }; + + /* Alle Unicode-Symbole werden in einer einzigen globalen Tabelle + (Hashtabelle) verwaltet, jedes Symbol wird nur einmal angelegt. + -> Speicherersparnis, und "Uberpr"ufung auf Gleichheit durch einfachen + Zeigervergleich */ + + +/************ data structures of remaining constant pool entries **************/ + + +typedef struct { + classinfo *class; + unicode *name; + unicode *descriptor; + } constant_FMIref; + + +typedef struct { + s4 value; + } constant_integer; + +typedef struct { + float value; + } constant_float; + +typedef struct { + s8 value; + } constant_long; + +typedef struct { + double value; + } constant_double; + + +typedef struct { + unicode *name; + unicode *descriptor; + } constant_nameandtype; + + +typedef struct constant_arraydescriptor { + int arraytype; + classinfo *objectclass; + struct constant_arraydescriptor *elementdescriptor; + } constant_arraydescriptor; + + /* Mit einem Arraydescriptor kann ein Array-Typ dargestellt werden. + Bei normalen Arrays (z.B. Array von Bytes,...) gen"ugt dazu, + dass das Feld arraytype die entsprechende Kennzahl enth"alt + (z.B. ARRAYTYPE_BYTE). + Bei Arrays von Objekten (arraytype=ARRAYTYPE_OBJECT) muss das + Feld objectclass auf die Klassenstruktur der m"oglichen + Element-Objekte zeigen. + Bei Arrays von Arrays (arraytype=ARRAYTYPE_ARRAY) muss das + Feld elementdescriptor auf eine weiter arraydescriptor-Struktur + zeigen, die die Element-Typen beschreibt. + */ + + + +/********* Anmerkungen zum Constant-Pool: + + Die Typen der Eintr"age in den Constant-Pool werden durch die oben + definierten CONSTANT_.. Werte angegeben. + Bei allen Typen muss zus"atzlich noch eine Datenstruktur hinzugef"ugt + werden, die den wirklichen Wert angibt. + Bei manchen Typen reicht es, einen Verweis auf eine schon bereits + existierende Struktur (z.B. unicode-Texte) einzutragen, bei anderen + muss diese Struktur erst extra erzeugt werden. + Ich habe folgende Datenstrukturen f"ur diese Typen verwendet: + + Typ Struktur extra erzeugt? + ---------------------------------------------------------------------- + CONSTANT_Class classinfo nein + CONSTANT_Fieldref constant_FMIref ja + CONSTANT_Methodref constant_FMIref ja + CONSTANT_InterfaceMethodref constant_FMIref ja + CONSTANT_String unicode nein + CONSTANT_Integer constant_integer ja + CONSTANT_Float constant_float ja + CONSTANT_Long constant_long ja + CONSTANT_Double constant_double ja + CONSTANT_NameAndType constant_nameandtype ja + CONSTANT_Utf8 unicode nein + CONSTANT_Arraydescriptor constant_arraydescriptor ja + CONSTANT_UNUSED - + +*******************************/ + + + +/***************** Die Datenstrukturen fuer das Laufzeitsystem ***************/ + + + /********* Objekte ********** + + Alle Objekte (und Arrays), die am Heap gespeichert werden, m"ussen eine + folgende spezielle Datenstruktur ganz vorne stehen haben: + + */ + +typedef struct java_objectheader { /* Der Header f"ur alle Objekte */ + vftbl *vftbl; /* Zeiger auf die Function Table */ +} java_objectheader; + + + + /********* Arrays *********** + + Alle Arrays in Java sind auch gleichzeitig Objekte (d.h. sie haben auch + den obligatorischen Object-Header und darin einen Verweis auf eine Klasse) + Es gibt aber (der Einfachheit halber) nur eine einzige Klasse f"ur alle + m"oglichen Typen von Arrays, deshalb wird der tats"achliche Typ in einem + Feld im Array-Objekt selbst gespeichert. + Die Typen sind: */ + +#define ARRAYTYPE_INT 0 +#define ARRAYTYPE_LONG 1 +#define ARRAYTYPE_FLOAT 2 +#define ARRAYTYPE_DOUBLE 3 +#define ARRAYTYPE_BYTE 4 +#define ARRAYTYPE_CHAR 5 +#define ARRAYTYPE_SHORT 6 +#define ARRAYTYPE_BOOLEAN 7 +#define ARRAYTYPE_OBJECT 8 +#define ARRAYTYPE_ARRAY 9 + + + /** Der Header f"ur ein Java-Array **/ + +typedef struct java_arrayheader { /* Der Arrayheader f"ur alle Arrays */ + java_objectheader objheader; /* Der Object-Header */ + s4 size; /* Gr"osse des Arrays */ + s4 arraytype; /* Typ der Elemente */ +} java_arrayheader; + + + + /** Die Unterschiedlichen Strukturen f"ur alle Typen von Arrays **/ + +typedef struct java_chararray { + java_arrayheader header; + u2 data[1]; +} java_chararray; + +typedef struct java_floatheader { + java_arrayheader header; + float data[1]; +} java_floatarray; + +typedef struct java_doublearray { + java_arrayheader header; + double data[1]; +} java_doublearray; + + + /* achtung: die beiden Stukturen booleanarray und bytearray m"ussen + identisches memory-layout haben, weil mit den selben Funktionen + darauf zugegriffen wird */ + +typedef struct java_booleanarray { + java_arrayheader header; + u1 data[1]; +} java_booleanarray; + +typedef struct java_bytearray { + java_arrayheader header; + s1 data[1]; +} java_bytearray; + +typedef struct java_shortarray { + java_arrayheader header; + s2 data[1]; +} java_shortarray; + +typedef struct java_intarray { + java_arrayheader header; + s4 data[1]; +} java_intarray; + +typedef struct java_longarray { + java_arrayheader header; + s8 data[1]; +} java_longarray; + + + /* ACHTUNG: die beiden folgenden Strukturen m"ussen unbedingt gleiches + Memory-Layout haben, weil mit ein und der selben Funktion auf die + data-Eintr"age beider Typen zugegriffen wird !!!! */ + +typedef struct java_objectarray { + java_arrayheader header; + classinfo *elementtype; + java_objectheader *data[1]; +} java_objectarray; + +typedef struct java_arrayarray { + java_arrayheader header; + constant_arraydescriptor *elementdescriptor; + java_arrayheader *data[1]; +} java_arrayarray; + + + + +/************** Strukturen f"ur Klassen, Felder & Methoden *****************/ + + + /*** Struktur: fieldinfo ***/ + +typedef struct fieldinfo { /* Struktur f"ur ein Feld einer Klasse */ + s4 flags; /* die ACC-Flags */ + s4 type; /* Grunddatentyp */ + unicode *name; /* Name des Felds */ + unicode *descriptor; /* Typedescriptor in JavaVM-Form */ + + s4 offset; /* Offset vom Anfang des Objektes */ + /* (bei Instanzvariablen) */ + + union { /* Speicher f"ur den Wert */ + s4 i; /* (bei Klassenvariablen) */ + s8 l; + float f; + double d; + void *a; + } value; + + } fieldinfo; + + + /*** Struktur: exceptiontable ***/ + +typedef struct exceptiontable { /* Exceptionhandler-Eintrag in einer Methode */ + s4 startpc; /* Anfang des G"ultigkeitsbereichs */ + s4 endpc; /* Ende des Bereichs (exklusive) */ + s4 handlerpc; /* JavaVM-Position des Handlers */ + classinfo *catchtype; /* Typ der behandelten Exceptions (oder + NULL, wenn alle behandelt werden sollen) */ + } exceptiontable; + + + + /*** Struktur: methodinfo ***/ + +typedef struct methodinfo { /* Struktur f"ur eine Methode einer Klasse */ + s4 flags; /* die ACC-Flags */ + unicode *name; /* Name der Methode */ + unicode *descriptor; /* der JavaVM-Descriptorstring f"ur Methoden */ + s4 returntype; /* only temporary valid, return type */ + s4 paramcount; /* only temporary valid, number of parameters */ + u1 *paramtypes; /* only temporary valid, parameter types */ + classinfo *class; /* Die Klasse, der die Methode geh"ort */ + u4 vftblindex; /* Index dieser Methode f"ur die Virtual + Function Table (wenn es keine statische + Methode ist) */ + + s4 maxstack; /* maximale Stacktiefe des JavaVM-Codes */ + s4 maxlocals; /* maximale Anzahl der JavaVM-Variablen */ + u4 jcodelength; /* L"ange des JavaVM-Codes */ + u1 *jcode; /* und Zeiger auf den JavaVM-Code */ + + s4 exceptiontablelength; /* L"ange der Exceptintable */ + exceptiontable *exceptiontable; /* Die Exceptiontable selber */ + + u1 *stubroutine; /* STUB-Routine for compiling or calling + natives */ + u4 mcodelength; /* L"ange des generierten Maschinencodes */ + u1 *mcode; /* Zeiger auf den Maschinencode */ + u1 *entrypoint; /* Entrypoint to the Maschine-Code */ + + + } methodinfo; + + + /*** Struktur: classinfo ***/ + +struct classinfo { /* Datenstruktur f"ur eine Klasse */ + java_objectheader header; /* Weil auch Klassen als Objekte angesprochen + werden */ + + s4 flags; /* Die ACC-Flags */ + unicode *name; /* Name der Klasse */ + + s4 cpcount; /* Anzahl der Eintr"age im Constant-Pool */ + u1 *cptags; /* Die TAGs f"ur den Constant-Pool */ + voidptr *cpinfos; /* Die Zeiger auf die Info-Strukturen */ + + classinfo *super; /* Zeiger auf die "ubergeordnete Klasse */ + + s4 interfacescount; /* Anzahl der Interfaces */ + classinfo **interfaces; /* Zeiger auf die Interfaces */ + + s4 fieldscount; /* Anzahl der Felder */ + fieldinfo *fields; /* Die Tabelle der Felder */ + + s4 methodscount; /* Anzahl der Methoden */ + methodinfo *methods; /* Die Tabelle der Methoden */ + + + listnode listnode; /* Verkettungsstruktur (f"ur Listen) */ + + bool initialized; /* true, wenn Klasse bereits Initialisiert */ + bool linked; /* wird von `class_link` auf true gesetzt */ + s4 index; /* Hierarchietiefe (bei normalen Klassen) + oder fortlaufende Nummer (bei Interfaces)*/ + u4 instancesize; /* Gr"osse eines Objektes dieser Klasse */ + + vftbl *vftbl; + + methodinfo *finalizer; /* Finalizer-Methode f"ur die Klasse */ + }; + + +struct vftbl { + classinfo *class; /* Class, the function table belongs to */ + + s4 vftbllength; /* L"aenge der Virtual Function Table */ + + s4 interfacetablelength; /* L"ange der Interfacetable */ + u4 *interfacevftbllength; /* -> siehe unten */ + methodptr **interfacevftbl; + + methodptr table[1]; + }; + +/*********** Anmerkungen zur Interfacetable: + + "Ahnlich wie die 'normalen' virtuellen Methoden k"onnen auch die + Interface-Methoden mit Hilfe einer Art Virtual Function Table + aufgerufen werden. + Dazu werden alle Interfaces im System fortlaufend nummeriert (beginnend + bei 0), und f"ur jede Klasse wird eine ganze Tabelle von + Virtual Function Tables erzeugt, n"amlich zu jedem Interface, das die + Klasse implementiert, eine. + + z.B. Nehmen wir an, eine Klasse implementiert zwei Interfaces (die durch + die Nummerierung die Indizes 0 und 3 bekommen haben) + + Das sieht dann ungef"ahr so aus: + -------------- ------------- + interfacevftbl ---> | Eintrag 0 |---------> | Methode 0 |---> Methode X + | Eintrag 1 |--> NULL | Methode 1 |---> Methode Y + | Eintrag 2 |--> NULL | Methode 2 |---> Methode Z + | Eintrag 3 |-----+ ------------- + -------------- | + +---> ------------- + | Methode 0 |---> Methode X + | Methode 1 |---> Methode A + ------------- + --------------- + interfacevftlblength ---> | Wert 0 = 3 | + | Wert 1 = 0 | + | Wert 2 = 0 | + | Wert 3 = 2 | + --------------- + + Der Aufruf einer Interface-Methode geht dann so vor sich: + Zur Compilezeit steht der Index (i) des Interfaces und die Stelle (s), wo + in der entsprechenden Untertabelle die Methode eingetragen ist, schon fest. + Also muss zur Laufzeit nur mehr der n-te Eintrag aus der Interfacetable + gelesen werden, von dieser Tabelle aus wird der s-te Eintrag geholt, + und diese Methode wird angesprungen. + +****************/ + + + +/************************* Referenzen auf die wichtigen Systemklassen ********************/ + +extern classinfo *class_java_lang_Object; +extern classinfo *class_java_lang_String; +extern classinfo *class_java_lang_ClassCastException; +extern classinfo *class_java_lang_NullPointerException; +extern classinfo *class_java_lang_ArrayIndexOutOfBoundsException; +extern classinfo *class_java_lang_NegativeArraySizeException; +extern classinfo *class_java_lang_OutOfMemoryError; +extern classinfo *class_java_lang_ArithmeticException; +extern classinfo *class_java_lang_ArrayStoreException; +extern classinfo *class_java_lang_ThreadDeath; /* schani */ + +extern classinfo *class_array; + + +/********************** Vorgefertigte Instanzen einiger Systemklassen ********************/ + +extern java_objectheader *proto_java_lang_ClassCastException; +extern java_objectheader *proto_java_lang_NullPointerException; +extern java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException; +extern java_objectheader *proto_java_lang_NegativeArraySizeException; +extern java_objectheader *proto_java_lang_OutOfMemoryError; +extern java_objectheader *proto_java_lang_ArithmeticException; +extern java_objectheader *proto_java_lang_ArrayStoreException; +extern java_objectheader *proto_java_lang_ThreadDeath; /* schani */ + + +/********************** flag variables *********************/ + +extern bool compileall; +extern bool runverbose; +extern bool verbose; + + +/********************** trace variables ********************/ + +extern int count_class_infos; +extern int count_const_pool_len; +extern int count_vftbl_len; +extern int count_unicode_len; +extern int count_all_methods; +extern int count_vmcode_len; +extern int count_extable_len; + +#endif diff --git a/headers.c b/headers.c new file mode 100644 index 000000000..dce631e1a --- /dev/null +++ b/headers.c @@ -0,0 +1,465 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** headers.c ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Dieser Modul ersetzt f"ur den Headerfile-Betrieb den Modul 'main', + und 'f"alscht' einige Verweise auf externe Module (damit nicht schon + alle Module des eigentlichen Programmes fertig sein m"ussen, was ja + unm"oglich w"are, da die Headerfile-Tabellen ja erst hier und jetzt + generiert werden). + + Dieser Modul ist ein ziemlich schneller Hack und dementsprechend + schlecht (nicht) kommentiert. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/05/23 + +*******************************************************************************/ + +#include "global.h" + +#include "tables.h" +#include "loader.h" + + +/******* verschiedene externe Funktionen "faelschen" (=durch Dummys ersetzen), + damit der Linker zufrieden ist *********/ + +functionptr native_findfunction + (unicode *cname, unicode *mname, unicode *desc, bool isstatic) +{ return NULL; } + +java_objectheader *literalstring_new (unicode *text) +{ return NULL; } + +java_objectheader *javastring_new (unicode *text) /* schani */ +{ return NULL; } + +void synchronize_caches() { } +void asm_call_jit_compiler () { } +void asm_calljavamethod () { } +void asm_dumpregistersandcall () { } + +s4 new_builtin_idiv (s4 a, s4 b) {return 0;} +s4 new_builtin_irem (s4 a, s4 b) {return 0;} +s8 new_builtin_ldiv (s8 a, s8 b) {return 0;} +s8 new_builtin_lrem (s8 a, s8 b) {return 0;} + + +void new_builtin_monitorenter (java_objectheader *o) {} +void new_builtin_monitorexit (java_objectheader *o) {} + +s4 new_builtin_checkcast(java_objectheader *o, classinfo *c) + {return 0;} +s4 new_builtin_checkarraycast + (java_objectheader *o, constant_arraydescriptor *d) + {return 0;} + +void new_builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o) {} + +u1 *createcompilerstub (methodinfo *m) {return NULL;} +u1 *createnativestub (functionptr f, methodinfo *m) {return NULL;} +u1 *ncreatenativestub (functionptr f, methodinfo *m) {return NULL;} + +void removecompilerstub (u1 *stub) {} +void removenativestub (u1 *stub) {} + +void perform_alpha_threadswitch (u1 **from, u1 **to) {} +u1* initialize_thread_stack (void *func, u1 *stack) { return NULL; } +u1* used_stack_top (void) { return NULL; } + +java_objectheader *native_new_and_init (void *p) { return NULL; } + +/************************ globale Variablen **********************/ + +java_objectheader *exceptionptr; /* schani */ +int newcompiler = true; +bool verbose = false; + +static chain *nativechain; +static FILE *file = NULL; + +static void printIDpart (int c) +{ + if ( (c>='a' && c<='z') + || (c>='A' && c<='Z') + || (c>='0' && c<='9') + || (c=='_') ) + putc (c,file); + else putc ('_',file); + +} + +static void printID (unicode *name) +{ + int i; + for (i=0; ilength; i++) { + printIDpart (name->text[i]); + } +} + + +u4 outputsize; +bool dopadding; + +static void addoutputsize (int len) +{ + u4 newsize,i; + if (!dopadding) return; + + newsize = ALIGN (outputsize, len); + + for (i=outputsize; isuper); + + for (i=0; ifieldscount; i++) { + f = &(c->fields[i]); + + if (! (f->flags & ACC_STATIC) ) { + fprintf (file," "); + printtype (f->descriptor->text); + fprintf (file, " "); + unicode_fprint (file, f->name); + fprintf (file, ";\n"); + } + } +} + + + + +static void remembermethods (classinfo *c) +{ + u2 i; + methodinfo *m; + + for (i=0; imethodscount; i++) { + m = &(c->methods[i]); + + if (m->flags & ACC_NATIVE) { + chain_addlast (nativechain, m); + } + + } +} + + + + +static void printmethod (methodinfo *m) +{ + u2 *d; + u2 paramnum=1; + + d = m->descriptor->text; + while (*(d++) != ')'); + + printtype (d); + fprintf (file," "); + printID (m->class->name); + fprintf (file,"_"); + printID (m->name); + fprintf (file," ("); + + d = m->descriptor->text+1; + + if (! (m->flags & ACC_STATIC) ) { + fprintf (file, "struct "); + printID (m->class->name); + fprintf (file, "* this"); + if ((*d)!=')') fprintf (file, ", "); + } + + while ((*d)!=')') { + d = printtype (d); + fprintf (file, " par%d", paramnum++); + if ((*d)!=')') fprintf (file, ", "); + } + + fprintf (file, ");\n"); +} + + +static void headers_generate (classinfo *c) +{ + fprintf (file, "/* Structure information for class: "); + unicode_fprint (file, c->name); + fprintf (file, " */\n\n"); + + fprintf (file, "typedef struct "); + printID (c->name); + fprintf (file, " {\n"); + + outputsize=0; + dopadding=true; + printfields (c); + + fprintf (file, "} "); + printID (c->name); + fprintf (file, ";\n\n"); + + remembermethods (c); + + + fprintf (file, "\n\n"); +} + + + +static void printnativetableentry (methodinfo *m) +{ + fprintf (file, " { \""); + unicode_fprint (file, m->class->name); + fprintf (file, "\",\n \""); + unicode_fprint (file, m->name); + fprintf (file, "\",\n \""); + unicode_fprint (file, m->descriptor); + fprintf (file, "\",\n "); + if ( (m->flags & ACC_STATIC) !=0) fprintf (file, "true"); + else fprintf (file, "false"); + fprintf (file, ",\n "); + fprintf (file, "(functionptr) "); + printID (m->class->name); + fprintf (file,"_"); + printID (m->name); + fprintf (file,"\n },\n"); +} + + + + + +static void headers_start () +{ + file = fopen ("nativetypes.hh", "w"); + if (!file) panic ("Can not open file 'native.h' to store header information"); + + fprintf (file, "/* Headerfile for native methods: nativetypes.hh */\n"); + fprintf (file, "/* This file is machine generated, don't edit it !*/\n\n"); + + nativechain = chain_new (); +} + + +static void headers_finish () +{ + methodinfo *m; + + fprintf (file, "\n/* Prototypes for native methods */\n\n"); + + m = chain_first (nativechain); + while (m) { + dopadding=false; + printmethod (m); + + m = chain_next (nativechain); + } + + + file = fopen ("nativetable.hh", "w"); + if (!file) panic ("Can not open file 'nativetable' to store native-link-table"); + + fprintf (file, "/* Table of native methods: nativetables.hh */\n"); + fprintf (file, "/* This file is machine generated, don't edit it !*/\n\n"); + + while ( (m = chain_first (nativechain)) != NULL) { + chain_remove (nativechain); + + printnativetableentry (m); + + } + + chain_free (nativechain); + fclose (file); +} + + + + + +/******************** interne Funktion: print_usage ************************ + +Gibt die richtige Aufrufsyntax des JAVA-Header-Generators auf stdout aus. + +***************************************************************************/ + +static void print_usage() +{ + printf ("USAGE: jch class [class..]\n"); +} + + + + +/************************** Funktion: main ******************************* + + Das Hauptprogramm. + Wird vom System zu Programstart aufgerufen (eh klar). + +**************************************************************************/ + +int main(int argc, char **argv) +{ + s4 i,a; + char *cp; + classinfo *topclass; + void *dummy; + + + /********** interne (nur fuer main relevante Optionen) **************/ + + char classpath[500] = ""; + u4 heapsize = 100000; + + /*********** Optionen, damit wirklich nur headers generiert werden ***/ + + makeinitializations=false; + + + /************ Infos aus der Environment lesen ************************/ + + cp = getenv ("CLASSPATH"); + if (cp) { + strcpy (classpath + strlen(classpath), ":"); + strcpy (classpath + strlen(classpath), cp); + } + + if (argc < 2) { + print_usage (); + exit(10); + } + + + /**************************** Programmstart *****************************/ + + log_init (NULL); + log_text ("Java - header-generator started"); + + + suck_init (classpath); + + unicode_init (); + heap_init (heapsize, heapsize, &dummy); + loader_init (); + + + /*********************** JAVA-Klassen laden ***************************/ + + headers_start (); + + + for (a=1; a=0; i--) { /* Punkte im Klassennamen */ + if (cp[i]=='.') cp[i]='/'; /* auf slashes umbauen */ + } + + topclass = loader_load ( unicode_new_char (cp) ); + + headers_generate (topclass); + } + + + headers_finish (); + + + /************************ Freigeben aller Resourcen *******************/ + + loader_close (); + heap_close (); + unicode_close (NULL); + + + /* Endemeldung ausgeben und mit entsprechendem exit-Status terminieren */ + + log_text ("Java - header-generator stopped"); + log_cputime (); + mem_usagelog(1); + + return 0; +} + + diff --git a/loader.c b/loader.c new file mode 100644 index 000000000..c94327c4e --- /dev/null +++ b/loader.c @@ -0,0 +1,1994 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** loader.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the functions of the class loader. + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/06/03 + +*******************************************************************************/ + + +#include + +#include "global.h" +#include "loader.h" + +#include "tables.h" +#include "native.h" +#include "builtin.h" +#include "compiler.h" +#include "asmpart.h" + +#include "threads/thread.h" /* schani */ + + +/*************************** globale Variablen *******************************/ + +extern bool newcompiler; + +int count_class_infos = 0; +int count_const_pool_len = 0; +int count_vftbl_len = 0; +int count_all_methods = 0; +int count_vmcode_len = 0; +int count_extable_len = 0; + +bool loadverbose = false; /* Switches f"ur mehr Debug-Meldungen */ +bool linkverbose = false; +bool initverbose = false; + +bool makeinitializations = true; + +bool getloadingtime = false; +long int loadingtime = 0; + + +static u4 interfaceindex; /* fortlaufende Nummer f"ur Interfaces */ + +static list unloadedclasses; /* Liste alle referenzierten, aber noch nicht + geladenen Klassen */ +static list unlinkedclasses; /* Liste aller geladenen, aber noch nicht + gelinkten Klassen */ + list linkedclasses; /* Liste aller fertig gelinkten Klassen */ + + + +/***************** die Referenzen auf die wichtigen Systemklassen ************/ + +classinfo *class_java_lang_Object; +classinfo *class_java_lang_String; +classinfo *class_java_lang_ClassCastException; +classinfo *class_java_lang_NullPointerException; +classinfo *class_java_lang_ArrayIndexOutOfBoundsException; +classinfo *class_java_lang_NegativeArraySizeException; +classinfo *class_java_lang_OutOfMemoryError; +classinfo *class_java_lang_ArithmeticException; +classinfo *class_java_lang_ArrayStoreException; +classinfo *class_java_lang_ThreadDeath; /* schani */ + +classinfo *class_array; + + +/************ einige vorgefertigte Instanzen wichtiger Systemklassen *********/ + +java_objectheader *proto_java_lang_ClassCastException; +java_objectheader *proto_java_lang_NullPointerException; +java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException; +java_objectheader *proto_java_lang_NegativeArraySizeException; +java_objectheader *proto_java_lang_OutOfMemoryError; +java_objectheader *proto_java_lang_ArithmeticException; +java_objectheader *proto_java_lang_ArrayStoreException; +java_objectheader *proto_java_lang_ThreadDeath; /* schani */ + + + + +/****************************************************************************/ +/******************* Einige Support-Funkionen *******************************/ +/****************************************************************************/ + + +/********** interne Funktion: printflags (nur zu Debug-Zwecken) ************/ + +static void printflags (u2 f) +{ + if ( f & ACC_PUBLIC ) printf (" PUBLIC"); + if ( f & ACC_PRIVATE ) printf (" PRIVATE"); + if ( f & ACC_PROTECTED ) printf (" PROTECTED"); + if ( f & ACC_STATIC ) printf (" STATIC"); + if ( f & ACC_FINAL ) printf (" FINAL"); + if ( f & ACC_SYNCHRONIZED ) printf (" SYNCHRONIZED"); + if ( f & ACC_VOLATILE ) printf (" VOLATILE"); + if ( f & ACC_TRANSIENT ) printf (" TRANSIENT"); + if ( f & ACC_NATIVE ) printf (" NATIVE"); + if ( f & ACC_INTERFACE ) printf (" INTERFACE"); + if ( f & ACC_ABSTRACT ) printf (" ABSTRACT"); +} + + +/************************* Funktion: skipattribute **************************** + + "uberliest im ClassFile eine (1) 'attribute'-Struktur + +******************************************************************************/ + +static void skipattribute () +{ + u4 len; + + suck_u2 (); + len = suck_u4 (); + skip_nbytes (len); +} + +/********************** Funktion: skipattributebody *************************** + + "uberliest im Classfile ein attribut, wobei die 16-bit - attribute_name - + Referenz schon gelesen worden ist. + +******************************************************************************/ + +static void skipattributebody () +{ + u4 len = suck_u4 (); + skip_nbytes (len); +} + + +/************************* Funktion: skipattributes *************************** + + "uberliest im ClassFile eine gew"unschte Anzahl von attribute-Strukturen + +******************************************************************************/ + +static void skipattributes (u4 num) +{ + u4 i; + for (i=0; i 0) { + b1 = suck_u1 (); + utflen --; + if (b1<0x80) letter = b1; + else { + b2 = suck_u1 (); + utflen --; + if (b1<0xe0) letter = ((b1 & 0x1f) << 6) | (b2 & 0x3f); + else { + b3 = suck_u1 (); + utflen --; + letter = ((b1 & 0x0f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f); + } + } + + + if (unicodelen >= MAXUNICODELEN) { + panic ("String constant too long"); + } + + unicodebuffer[unicodelen++] = letter; + } + + + return unicode_new_u2 (unicodebuffer, unicodelen); +} + + + +/******************** interne Funktion: checkfieldtype ***********************/ + +static void checkfieldtype (u2 *text, u4 *count, u4 length) +{ + u4 l; + + if (*count >= length) panic ("Type-descriptor exceeds unicode length"); + + l = text[(*count)++]; + + switch (l) { + default: panic ("Invalid symbol in type descriptor"); + return; + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': return; + + case '[': checkfieldtype (text, count, length); + return; + + case 'L': + { + u4 tlen,tstart = *count; + + if (*count >= length) + panic ("Objecttype descriptor of length zero"); + + while ( text[*count] != ';' ) { + (*count)++; + if (*count >= length) + panic ("Missing ';' in objecttype-descriptor"); + } + + tlen = (*count) - tstart; + (*count)++; + + if (tlen == 0) panic ("Objecttype descriptor with empty name"); + + class_get ( unicode_new_u2 (text+tstart, tlen) ); + } + } +} + + +/******************* Funktion: checkfielddescriptor *************************** + + "uberpr"uft, ob ein Field-Descriptor ein g"ultiges Format hat. + Wenn nicht, dann wird das System angehalten. + Au"serdem werden alle Klassen, die hier referenziert werden, + in die Liste zu ladender Klassen eingetragen. + +******************************************************************************/ + +void checkfielddescriptor (unicode *d) +{ + u4 count=0; + checkfieldtype (d->text, &count, d->length); + if (count != d->length) panic ("Invalid type-descritor encountered"); +} + + +/******************* Funktion: checkmethoddescriptor ************************** + + "uberpr"uft, ob ein Method-Descriptor ein g"ultiges Format hat. + Wenn nicht, dann wird das System angehalten. + Au"serdem werden alle Klassen, die hier referenziert werden, + in die Liste zu ladender Klassen eingetragen. + +******************************************************************************/ + +void checkmethoddescriptor (unicode *d) +{ + u2 *text=d->text; + u4 length=d->length; + u4 count=0; + + if (length<2) panic ("Method descriptor too short"); + if (text[0] != '(') panic ("Missing '(' in method descriptor"); + count=1; + + while (text[count] != ')') { + checkfieldtype (text,&count,length); + if ( count > length-2 ) panic ("Unexpected end of descriptor"); + } + + count++; + if (text[count] == 'V') count++; + else checkfieldtype (text, &count,length); + + if (count != length) panic ("Method-descriptor has exceeding chars"); +} + + +/******************** Funktion: buildarraydescriptor **************************** + + erzeugt zu einem namentlich als u2-String vorliegenden Arraytyp eine + entsprechende constant_arraydescriptor - Struktur + +********************************************************************************/ + +static constant_arraydescriptor * buildarraydescriptor(u2 *name, u4 namelen) +{ + constant_arraydescriptor *d; + + if (name[0]!='[') panic ("Attempt to build arraydescriptor for non-array"); + d = NEW (constant_arraydescriptor); + d -> objectclass = NULL; + d -> elementdescriptor = NULL; + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_arraydescriptor); +#endif + + switch (name[1]) { + case 'Z': d -> arraytype = ARRAYTYPE_BOOLEAN; break; + case 'B': d -> arraytype = ARRAYTYPE_BYTE; break; + case 'C': d -> arraytype = ARRAYTYPE_CHAR; break; + case 'D': d -> arraytype = ARRAYTYPE_DOUBLE; break; + case 'F': d -> arraytype = ARRAYTYPE_FLOAT; break; + case 'I': d -> arraytype = ARRAYTYPE_INT; break; + case 'J': d -> arraytype = ARRAYTYPE_LONG; break; + case 'S': d -> arraytype = ARRAYTYPE_SHORT; break; + + case '[': + d -> arraytype = ARRAYTYPE_ARRAY; + d -> elementdescriptor = buildarraydescriptor (name+1, namelen-1); + break; + + case 'L': + d -> arraytype = ARRAYTYPE_OBJECT; + d -> objectclass = class_get ( unicode_new_u2 (name+2, namelen-3) ); + break; + } + return d; +} + + +/******************* Funktion: freearraydescriptor **************************** + + entfernt eine mit buildarraydescriptor erzeugte Struktur wieder + aus dem Speicher + +*******************************************************************************/ + +static void freearraydescriptor (constant_arraydescriptor *d) +{ + while (d) { + constant_arraydescriptor *n = d->elementdescriptor; + FREE (d, constant_arraydescriptor); + d = n; + } +} + +/*********************** Funktion: displayarraydescriptor *********************/ + +static void displayarraydescriptor (constant_arraydescriptor *d) +{ + switch (d->arraytype) { + case ARRAYTYPE_BOOLEAN: printf ("boolean[]"); break; + case ARRAYTYPE_BYTE: printf ("byte[]"); break; + case ARRAYTYPE_CHAR: printf ("char[]"); break; + case ARRAYTYPE_DOUBLE: printf ("double[]"); break; + case ARRAYTYPE_FLOAT: printf ("float[]"); break; + case ARRAYTYPE_INT: printf ("int[]"); break; + case ARRAYTYPE_LONG: printf ("long[]"); break; + case ARRAYTYPE_SHORT: printf ("short[]"); break; + case ARRAYTYPE_ARRAY: displayarraydescriptor(d->elementdescriptor); printf("[]"); break; + case ARRAYTYPE_OBJECT: unicode_display(d->objectclass->name); printf("[]"); break; + } +} + + + +/*****************************************************************************/ +/******************** Funktionen fuer Fields *********************************/ +/*****************************************************************************/ + + +/************************ Funktion: field_load ******************************** + + l"adt alle Informationen f"ur eine Feld einer Methode aus dem ClassFile, + und f"ullt mit diesen Infos eine schon existierende 'fieldinfo'-Struktur. + Bei 'static'-Fields wird auch noch ein Platz auf dem Datensegment + reserviert. + +******************************************************************************/ + +static void field_load (fieldinfo *f, classinfo *c) +{ + u4 attrnum,i; + u4 jtype; + + f -> flags = suck_u2 (); + f -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + f -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + f -> type = jtype = desc_to_type (f->descriptor); + f -> offset = 0; + + switch (f->type) { + case TYPE_INT: f->value.i = 0; break; + case TYPE_FLOAT: f->value.f = 0.0; break; + case TYPE_DOUBLE: f->value.d = 0.0; break; + case TYPE_ADDRESS: f->value.a = NULL; + heap_addreference (&(f->value.a)); + break; + case TYPE_LONG: +#if U8_AVAILABLE + f->value.l = 0; break; +#else + f->value.l.low = 0; f->value.l.high = 0; break; +#endif + } + + attrnum = suck_u2(); + for (i=0; ivalue.i = ci -> value; + } + break; + + case TYPE_LONG: { + constant_long *cl = + class_getconstant(c, pindex, CONSTANT_Long); + + f->value.l = cl -> value; + } + break; + + case TYPE_FLOAT: { + constant_float *cf = + class_getconstant(c, pindex, CONSTANT_Float); + + f->value.f = cf->value; + } + break; + + case TYPE_DOUBLE: { + constant_double *cd = + class_getconstant(c, pindex, CONSTANT_Double); + + f->value.d = cd->value; + } + break; + + case TYPE_ADDRESS: { + unicode *u = + class_getconstant(c, pindex, CONSTANT_String); + f->value.a = literalstring_new(u); + } + break; + + default: + log_text ("Invalid Constant - Type"); + + } + + } + } + +} + + +/********************** Funktion: field_free *********************************/ + +static void field_free (fieldinfo *f) +{ +} + + +/************** Funktion: field_display (nur zu Debug-Zwecken) ***************/ + +static void field_display (fieldinfo *f) +{ + printf (" "); + printflags (f -> flags); + printf (" "); + unicode_display (f -> name); + printf (" "); + unicode_display (f -> descriptor); + printf (" offset: %ld\n", (long int) (f -> offset) ); +} + + + + +/*****************************************************************************/ +/************************* Funktionen f"ur Methods ***************************/ +/*****************************************************************************/ + + +/*********************** Funktion: method_load ******************************** + + l"adt die Infos f"ur eine Methode aus dem ClassFile und f"ullt damit + eine schon existierende 'methodinfo'-Struktur aus. + Bei allen native-Methoden wird au"serdem gleich der richtige + Funktionszeiger eingetragen, bei JavaVM-Methoden einstweilen ein + Zeiger auf den Compiler + +******************************************************************************/ + +static void method_load (methodinfo *m, classinfo *c) +{ + u4 attrnum,i,e; + +#ifdef STATISTICS + count_all_methods++; +#endif + + m -> class = c; + + m -> flags = suck_u2 (); + m -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + m -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + + m -> jcode = NULL; + m -> exceptiontable = NULL; + m -> entrypoint = NULL; + m -> mcode = NULL; + m -> stubroutine = NULL; + + if (! (m->flags & ACC_NATIVE) ) { + m -> stubroutine = createcompilerstub (m); + } + else { + functionptr f = native_findfunction + (c->name, m->name, m->descriptor, (m->flags & ACC_STATIC) != 0); + if (f) { + if (newcompiler) + m -> stubroutine = ncreatenativestub (f, m); + else + m -> stubroutine = createnativestub (f, m); + } + } + + + attrnum = suck_u2(); + for (i=0; i jcode) panic ("Two code-attributes for one method!"); + + suck_u4(); + m -> maxstack = suck_u2(); + m -> maxlocals = suck_u2(); + m -> jcodelength = suck_u4(); + m -> jcode = MNEW (u1, m->jcodelength); + suck_nbytes (m->jcode, m->jcodelength); + m -> exceptiontablelength = suck_u2 (); + m -> exceptiontable = + MNEW (exceptiontable, m->exceptiontablelength); + +#ifdef STATISTICS + count_vmcode_len += m->jcodelength + 18; + count_extable_len += 8 * m->exceptiontablelength; +#endif + + for (e=0; e < m->exceptiontablelength; e++) { + u4 idx; + m -> exceptiontable[e].startpc = suck_u2(); + m -> exceptiontable[e].endpc = suck_u2(); + m -> exceptiontable[e].handlerpc = suck_u2(); + + idx = suck_u2(); + if (!idx) m -> exceptiontable[e].catchtype = NULL; + else { + m -> exceptiontable[e].catchtype = + class_getconstant (c, idx, CONSTANT_Class); + } + } + + skipattributes ( suck_u2() ); + } + + } + + +} + + +/********************* Funktion: method_free ********************************** + + gibt allen Speicher, der extra f"ur eine Methode angefordert wurde, + wieder frei + +******************************************************************************/ + +static void method_free (methodinfo *m) +{ + if (m->jcode) MFREE (m->jcode, u1, m->jcodelength); + if (m->exceptiontable) + MFREE (m->exceptiontable, exceptiontable, m->exceptiontablelength); + if (m->mcode) CFREE (m->mcode, m->mcodelength); + if (m->stubroutine) { + if (m->flags & ACC_NATIVE) removenativestub (m->stubroutine); + else removecompilerstub (m->stubroutine); + } +} + + +/************** Funktion: method_display (nur zu Debug-Zwecken) *************/ + +void method_display (methodinfo *m) +{ + printf (" "); + printflags (m -> flags); + printf (" "); + unicode_display (m -> name); + printf (" "); + unicode_display (m -> descriptor); + printf ("\n"); +} + + +/******************** Funktion: method_canoverwrite *************************** + + "uberpr"ft, ob eine Methode mit einer anderen typ- und namensidentisch + ist (also mit einer Methodendefinition eine andere "uberschrieben + werden kann). + +******************************************************************************/ + +static bool method_canoverwrite (methodinfo *m, methodinfo *old) +{ + if (m->name != old->name) return false; + if (m->descriptor != old->descriptor) return false; + if (m->flags & ACC_STATIC) return false; + return true; +} + + + + +/*****************************************************************************/ +/************************ Funktionen fuer Class ******************************/ +/*****************************************************************************/ + + +/******************** Funktion: class_get ************************************* + + Sucht im System die Klasse mit dem gew"unschten Namen, oder erzeugt + eine neue 'classinfo'-Struktur (und h"angt sie in die Liste der zu + ladenen Klassen ein). + +******************************************************************************/ + +classinfo *class_get (unicode *u) +{ + classinfo *c; + + if (u->class) return u->class; + +#ifdef STATISTICS + count_class_infos += sizeof(classinfo); +#endif + + c = NEW (classinfo); + c -> flags = 0; + c -> name = u; + c -> cpcount = 0; + c -> cptags = NULL; + c -> cpinfos = NULL; + c -> super = NULL; + c -> interfacescount = 0; + c -> interfaces = NULL; + c -> fieldscount = 0; + c -> fields = NULL; + c -> methodscount = 0; + c -> methods = NULL; + c -> linked = false; + c -> index = 0; + c -> instancesize = 0; + c -> vftbl = NULL; + c -> initialized = false; + + unicode_setclasslink (u,c); + list_addlast (&unloadedclasses, c); + + return c; +} + + + +/******************** Funktion: class_getconstant ***************************** + + holt aus dem ConstantPool einer Klasse den Wert an der Stelle 'pos'. + Der Wert mu"s vom Typ 'ctype' sein, sonst wird das System angehalten. + +******************************************************************************/ + +voidptr class_getconstant (classinfo *c, u4 pos, u4 ctype) +{ + if (pos >= c->cpcount) + panic ("Attempt to access constant outside range"); + if (c->cptags[pos] != ctype) { + sprintf (logtext, "Type mismatch on constant: %d requested, %d here", + (int) ctype, (int) c->cptags[pos] ); + error(); + } + + return c->cpinfos[pos]; +} + + +/********************* Funktion: class_constanttype *************************** + + Findet heraus, welchen Typ ein Eintrag in den ConstantPool einer + Klasse hat. + +******************************************************************************/ + +u4 class_constanttype (classinfo *c, u4 pos) +{ + if (pos >= c->cpcount) + panic ("Attempt to access constant outside range"); + return c->cptags[pos]; +} + + +/******************** Funktion: class_loadcpool ******************************* + + l"adt den gesammten ConstantPool einer Klasse. + + Dabei werden die einzelnen Eintr"age in ein wesentlich einfachers + Format gebracht (Klassenreferenzen werden aufgel"ost, ...) + F"ur eine genaue "Ubersicht "uber das kompakte Format siehe: 'global.h' + +******************************************************************************/ + +static void class_loadcpool (classinfo *c) +{ + + typedef struct forward_class { /* Diese Strukturen dienen dazu, */ + struct forward_class *next; /* die Infos, die beim ersten */ + u2 thisindex; /* Durchgang durch den ConstantPool */ + u2 name_index; /* gelesen werden, aufzunehmen. */ + } forward_class; /* Erst nachdem der ganze Pool */ + /* gelesen wurde, k"onnen alle */ + typedef struct forward_string { /* Felder kompletiert werden */ + struct forward_string *next; /* (und das auch nur in der richtigen */ + u2 thisindex; /* Reihenfolge) */ + u2 string_index; + } forward_string; + + typedef struct forward_nameandtype { + struct forward_nameandtype *next; + u2 thisindex; + u2 name_index; + u2 sig_index; + } forward_nameandtype; + + typedef struct forward_fieldmethint { + struct forward_fieldmethint *next; + u2 thisindex; + u1 tag; + u2 class_index; + u2 nameandtype_index; + } forward_fieldmethint; + + + + u4 idx; + long int dumpsize = dump_size (); + + forward_class *forward_classes = NULL; + forward_string *forward_strings = NULL; + forward_nameandtype *forward_nameandtypes = NULL; + forward_fieldmethint *forward_fieldmethints = NULL; + + u4 cpcount = c -> cpcount = suck_u2(); + u1 *cptags = c -> cptags = MNEW (u1, cpcount); + voidptr *cpinfos = c -> cpinfos = MNEW (voidptr, cpcount); + +#ifdef STATISTICS + count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; +#endif + + + for (idx=0; idx next = forward_classes; + forward_classes = nfc; + + nfc -> thisindex = idx; + nfc -> name_index = suck_u2 (); + + idx++; + break; + } + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + forward_fieldmethint *nff = DNEW (forward_fieldmethint); + + nff -> next = forward_fieldmethints; + forward_fieldmethints = nff; + + nff -> thisindex = idx; + nff -> tag = t; + nff -> class_index = suck_u2 (); + nff -> nameandtype_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_String: { + forward_string *nfs = DNEW (forward_string); + + nfs -> next = forward_strings; + forward_strings = nfs; + + nfs -> thisindex = idx; + nfs -> string_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_NameAndType: { + forward_nameandtype *nfn = DNEW (forward_nameandtype); + + nfn -> next = forward_nameandtypes; + forward_nameandtypes = nfn; + + nfn -> thisindex = idx; + nfn -> name_index = suck_u2 (); + nfn -> sig_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_Integer: { + constant_integer *ci = NEW (constant_integer); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_integer); +#endif + + ci -> value = suck_s4 (); + cptags [idx] = CONSTANT_Integer; + cpinfos [idx] = ci; + idx ++; + + break; + } + + case CONSTANT_Float: { + constant_float *cf = NEW (constant_float); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_float); +#endif + + cf -> value = suck_float (); + cptags [idx] = CONSTANT_Float; + cpinfos[idx] = cf; + idx ++; + break; + } + + case CONSTANT_Long: { + constant_long *cl = NEW(constant_long); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_long); +#endif + + cl -> value = suck_s8 (); + cptags [idx] = CONSTANT_Long; + cpinfos [idx] = cl; + idx += 2; + break; + } + + case CONSTANT_Double: { + constant_double *cd = NEW(constant_double); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_double); +#endif + + cd -> value = suck_double (); + cptags [idx] = CONSTANT_Double; + cpinfos [idx] = cd; + idx += 2; + break; + } + + case CONSTANT_Utf8: { + unicode *u; + + u = loadUtf8 (); + + cptags [idx] = CONSTANT_Utf8; + cpinfos [idx] = u; + idx++; + break; + } + + default: + sprintf (logtext, "Unkown constant type: %d",(int) t); + error (); + + } /* end switch */ + + } /* end while */ + + + + /* Aufl"osen der noch unfertigen Eintr"age */ + + while (forward_classes) { + unicode *name = + class_getconstant (c, forward_classes -> name_index, CONSTANT_Utf8); + + if ( (name->length>0) && (name->text[0]=='[') ) { + checkfielddescriptor (name); + + cptags [forward_classes -> thisindex] = CONSTANT_Arraydescriptor; + cpinfos [forward_classes -> thisindex] = + buildarraydescriptor(name->text, name->length); + + } + else { + cptags [forward_classes -> thisindex] = CONSTANT_Class; + cpinfos [forward_classes -> thisindex] = class_get (name); + } + forward_classes = forward_classes -> next; + + } + + while (forward_strings) { + unicode *text = + class_getconstant (c, forward_strings -> string_index, CONSTANT_Utf8); + + cptags [forward_strings -> thisindex] = CONSTANT_String; + cpinfos [forward_strings -> thisindex] = text; + + forward_strings = forward_strings -> next; + } + + while (forward_nameandtypes) { + constant_nameandtype *cn = NEW (constant_nameandtype); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_nameandtype); +#endif + + cn -> name = class_getconstant + (c, forward_nameandtypes -> name_index, CONSTANT_Utf8); + cn -> descriptor = class_getconstant + (c, forward_nameandtypes -> sig_index, CONSTANT_Utf8); + + cptags [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType; + cpinfos [forward_nameandtypes -> thisindex] = cn; + + forward_nameandtypes = forward_nameandtypes -> next; + } + + + while (forward_fieldmethints) { + constant_nameandtype *nat; + constant_FMIref *fmi = NEW (constant_FMIref); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_FMIref); +#endif + + nat = class_getconstant + (c, forward_fieldmethints -> nameandtype_index, CONSTANT_NameAndType); + + fmi -> class = class_getconstant + (c, forward_fieldmethints -> class_index, CONSTANT_Class); + fmi -> name = nat -> name; + fmi -> descriptor = nat -> descriptor; + + cptags [forward_fieldmethints -> thisindex] = forward_fieldmethints -> tag; + cpinfos [forward_fieldmethints -> thisindex] = fmi; + + switch (forward_fieldmethints -> tag) { + case CONSTANT_Fieldref: checkfielddescriptor (fmi->descriptor); + break; + case CONSTANT_InterfaceMethodref: + case CONSTANT_Methodref: checkmethoddescriptor (fmi->descriptor); + break; + } + + forward_fieldmethints = forward_fieldmethints -> next; + + } + + + dump_release (dumpsize); +} + + +/********************** Funktion: class_load ********************************** + + l"adt alle Infos f"ur eine ganze Klasse aus einem ClassFile. Die + 'classinfo'-Struktur mu"s bereits angelegt worden sein. + + Die Superklasse und die Interfaces, die diese Klasse implementiert, + m"ussen zu diesem Zeitpunkt noch nicht geladen sein, die + Verbindung dazu wird sp"ater in der Funktion 'class_link' hergestellt. + + Die gelesene Klasse wird dann aus der Liste 'unloadedclasses' ausgetragen + und in die Liste 'unlinkedclasses' eingh"angt. + +******************************************************************************/ + +static void class_load (classinfo *c) +{ + u4 i; + u4 mi,ma; + + + if (loadverbose) { + sprintf (logtext, "Loading class: "); + unicode_sprint (logtext+strlen(logtext), c->name ); + dolog(); + } + + + suck_start (c->name); + + if (suck_u4() != MAGIC) panic("Can not find class-file signature"); + mi = suck_u2(); + ma = suck_u2(); + if (ma != MAJOR_VERSION) { + sprintf (logtext, "Can only support major version %d, but not %d", + MAJOR_VERSION, (int) ma); + error(); + } + if (mi > MINOR_VERSION) { + sprintf (logtext, "Minor version %d is not yet supported.", (int) mi); + error(); + } + + + class_loadcpool (c); + + c -> flags = suck_u2 (); + suck_u2 (); /* this */ + + if ( (i = suck_u2 () ) ) { + c -> super = class_getconstant (c, i, CONSTANT_Class); + } + else { + c -> super = NULL; + } + + c -> interfacescount = suck_u2 (); + c -> interfaces = MNEW (classinfo*, c -> interfacescount); + for (i=0; i < c -> interfacescount; i++) { + c -> interfaces [i] = + class_getconstant (c, suck_u2(), CONSTANT_Class); + } + + c -> fieldscount = suck_u2 (); + c -> fields = MNEW (fieldinfo, c -> fieldscount); + for (i=0; i < c -> fieldscount; i++) { + field_load (&(c->fields[i]), c); + } + + c -> methodscount = suck_u2 (); + c -> methods = MNEW (methodinfo, c -> methodscount); + for (i=0; i < c -> methodscount; i++) { + method_load (&(c -> methods [i]), c); + } + +#ifdef STATISTICS + count_class_infos += sizeof(classinfo*) * c -> interfacescount; + count_class_infos += sizeof(fieldinfo) * c -> fieldscount; + count_class_infos += sizeof(methodinfo) * c -> methodscount; +#endif + + + skipattributes ( suck_u2() ); + + + suck_stop (); + + list_remove (&unloadedclasses, c); + list_addlast (&unlinkedclasses, c); +} + + + +/************** interne Funktion: class_highestinterface ********************** + + wird von der Funktion class_link ben"otigt, um festzustellen, wie gro"s + die Interfacetable einer Klasse sein mu"s. + +******************************************************************************/ + +static s4 class_highestinterface (classinfo *c) +{ + s4 h; + s4 i; + + if ( ! (c->flags & ACC_INTERFACE) ) { + sprintf (logtext, "Interface-methods count requested for non-interface: "); + unicode_sprint (logtext+strlen(logtext), c->name); + error(); + } + + h = c->index; + for (i=0; iinterfacescount; i++) { + s4 h2 = class_highestinterface (c->interfaces[i]); + if (h2>h) h=h2; + } + return h; +} + + +/**************** Funktion: class_addinterface ******************************** + + wird von der Funktion class_link ben"otigt, um eine Virtual Function + Table f"ur ein Interface (und alle weiteren von diesem Interface + implementierten Interfaces) in eine Klasse einzutragen. + +******************************************************************************/ + +static void class_addinterface (classinfo *c, classinfo *ic) +{ + u4 i = ic->index; + u4 j,m; + vftbl *vftbl = c->vftbl; + + if (i>=vftbl->interfacetablelength) panic ("Interfacetable-Overflow"); + if (vftbl->interfacevftbl[i]) return; + + if (ic->methodscount==0) { /* wenn interface keine Methoden hat, dann + trotzdem eine Tabelle mit L"ange 1 anlegen, + wegen Subclass-Tests */ + vftbl -> interfacevftbllength[i] = 1; + vftbl -> interfacevftbl[i] = MNEW(methodptr, 1); + vftbl -> interfacevftbl[i][0] = NULL; + } + else { + vftbl -> interfacevftbllength[i] = ic -> methodscount; + vftbl -> interfacevftbl[i] = MNEW(methodptr, ic -> methodscount); + +#ifdef STATISTICS + count_vftbl_len += sizeof(methodptr) * ic -> methodscount; +#endif + + for (j=0; jmethodscount; j++) { + classinfo *sc = c; + while (sc) { + for (m=0; mmethodscount; m++) { + methodinfo *mi = &(sc->methods[m]); + if (method_canoverwrite (mi, &(ic->methods[j])) ) { + vftbl->interfacevftbl[i][j] = + vftbl->table[mi->vftblindex]; + goto foundmethod; + } + } + sc = sc->super; + } + foundmethod: ; + } + } + + for (j=0; jinterfacescount; j++) + class_addinterface(c, ic->interfaces[j]); +} + + +/********************** Funktion: class_link ********************************** + + versucht, eine Klasse in das System voll zu integrieren (linken). Dazu + m"ussen sowol die Superklasse, als auch alle implementierten + Interfaces schon gelinkt sein. + Diese Funktion berechnet sowohl die L"ange (in Bytes) einer Instanz + dieser Klasse, als auch die Virtual Function Tables f"ur normale + Methoden als auch Interface-Methoden. + + Wenn die Klasse erfolgreich gelinkt werden kann, dann wird sie aus + der Liste 'unlinkedclasses' ausgeh"angt, und in die Klasse 'linkedclasses' + eingetragen. + Wenn nicht, dann wird sie ans Ende der Liste 'unlinkedclasses' gestellt. + + Achtung: Bei zyklischen Klassendefinitionen ger"at das Programm hier in + eine Endlosschleife!! (Da muss ich mir noch was einfallen lassen) + +******************************************************************************/ + +static void class_link (classinfo *c) +{ + u4 supervftbllength; /* L"ange der VFTBL der Superklasse */ + u4 vftbllength; /* L"ange der VFTBL dieser Klasse */ + classinfo *super = c->super; + classinfo *ic,*c2; /* Hilfsvariablen */ + vftbl *v; + u4 i; + + + /* schauen, ob alle "ubergeordneten Klassen schon fertig sind, + und richtiges Initialisieren der lokalen Variablen */ + + for ( i=0; iinterfacescount; i++) { + ic = c->interfaces[i]; + if ( !ic -> linked) { + list_remove (&unlinkedclasses,c ); + list_addlast (&unlinkedclasses,c ); + return; + } + } + + if (! super) { + c -> index = 0; + c -> instancesize = sizeof (java_objectheader); + + vftbllength = supervftbllength = 0; + + c -> finalizer = NULL; + } + else { + if ( !super -> linked ) { + list_remove (&unlinkedclasses,c ); + list_addlast (&unlinkedclasses,c ); + return; + } + + if ( c->flags & ACC_INTERFACE) c -> index = interfaceindex++; + else c -> index = super -> index + 1; + + c -> instancesize = super -> instancesize; + + vftbllength = supervftbllength = super -> vftbl -> vftbllength; + + c -> finalizer = super -> finalizer; + } + + + if (linkverbose) { + sprintf (logtext, "Linking Class: "); + unicode_sprint (logtext+strlen(logtext), c->name ); + dolog (); + } + + /* Erstellen der Virtual Function Table */ + + for (i=0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (! (m->flags & ACC_STATIC) ) { + classinfo *sc = super; + while (sc) { + int j; + for (j=0; j < sc->methodscount; j++) { + if ( method_canoverwrite (m, &(sc->methods[j])) ) { + m -> vftblindex = sc->methods[j].vftblindex; + goto foundvftblindex; + } + } + sc = sc->super; + } + m -> vftblindex = (vftbllength++); + foundvftblindex: ; + } + } + +#ifdef STATISTICS + count_vftbl_len += sizeof(vftbl) + sizeof(methodptr)*(vftbllength-1); +#endif + + c -> vftbl = v = (vftbl*) + mem_alloc (sizeof(vftbl) + sizeof(methodptr)*(vftbllength-1)); + v -> class = c; + v -> vftbllength = vftbllength; + v -> interfacetablelength = 0; + + for (i=0; i < supervftbllength; i++) + v -> table[i] = super -> vftbl -> table[i]; + + for (i=0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + if ( ! (m->flags & ACC_STATIC) ) { + v -> table[m->vftblindex] = m -> stubroutine; + } + } + + + /* Berechnen der Instanzengr"o"se und der Offsets der einzelnen + Felder */ + + for (i=0; i < c->fieldscount; i++) { + u4 dsize; + fieldinfo *f = &(c -> fields[i]); + + if ( ! (f->flags & ACC_STATIC) ) { + dsize = desc_typesize (f->descriptor); + c -> instancesize = ALIGN ( c->instancesize, dsize); + f -> offset = c -> instancesize; + c -> instancesize += dsize; + } + + } + + + /* Berechnen der Virtual Function Tables f"ur alle Interfaces */ + + c2 = c; + while (c2) { + for (i=0; iinterfacescount; i++) { + s4 h = class_highestinterface (c2->interfaces[i]) + 1; + if ( h > v->interfacetablelength) v->interfacetablelength = h; + } + c2 = c2->super; + } + v -> interfacevftbllength = MNEW (u4, v->interfacetablelength); + v -> interfacevftbl = MNEW (methodptr *, v->interfacetablelength); + +#ifdef STATISTICS + count_vftbl_len += (4 + sizeof(methodptr*)) * v->interfacetablelength; +#endif + + for (i=0; i < v->interfacetablelength; i++) { + v -> interfacevftbllength[i] = 0; + v -> interfacevftbl[i] = NULL; + } + + c2 = c; + while (c2) { + for (i=0; iinterfacescount; i++) { + class_addinterface (c, c2->interfaces[i]); + } + c2 = c2->super; + } + + + + /* Die finalizer-Methode suchen und eintragen (wenn vorhanden), + aber nur bei Objekten ausser java.lang.Object */ + + if (super) { + methodinfo *fi; + static unicode *finame=NULL,*fidesc=NULL; + + if (!finame) finame = unicode_new_char ("finalize"); + if (!fidesc) fidesc = unicode_new_char ("()V"); + + fi = class_findmethod (c, finame, fidesc); + if (fi) { + if (! (fi->flags & ACC_STATIC) ) { + c -> finalizer = fi; + } + } + } + + + /* Abschlie"sende Aktionen */ + + c -> linked = true; + + list_remove (&unlinkedclasses, c); + list_addlast (&linkedclasses, c); +} + + +/******************* Funktion: class_freepool ********************************* + + Gibt alle Resourcen, die der ConstantPool einer Klasse ben"otigt, + wieder frei. + +******************************************************************************/ + +static void class_freecpool (classinfo *c) +{ + u4 idx; + u4 tag; + voidptr info; + + for (idx=0; idx < c->cpcount; idx++) { + tag = c->cptags[idx]; + info = c->cpinfos[idx]; + + if (info != NULL) { + switch (tag) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + FREE (info, constant_FMIref); + break; + case CONSTANT_Integer: + FREE (info, constant_integer); + break; + case CONSTANT_Float: + FREE (info, constant_float); + break; + case CONSTANT_Long: + FREE (info, constant_long); + break; + case CONSTANT_Double: + FREE (info, constant_double); + break; + case CONSTANT_NameAndType: + FREE (info, constant_nameandtype); + break; + case CONSTANT_Arraydescriptor: + freearraydescriptor (info); + break; + } + } + } + + MFREE (c -> cptags, u1, c -> cpcount); + MFREE (c -> cpinfos, voidptr, c -> cpcount); +} + + +/*********************** Funktion: class_free ********************************* + + Gibt alle Resourcen, die eine ganze Klasse ben"otigt, frei + +******************************************************************************/ + +static void class_free (classinfo *c) +{ + u4 i; + vftbl *v; + + unicode_unlinkclass (c->name); + + class_freecpool (c); + + MFREE (c->interfaces, classinfo*, c->interfacescount); + + for (i=0; i < c->fieldscount; i++) field_free ( &(c->fields[i]) ); + MFREE (c->fields, fieldinfo, c->fieldscount); + + for (i=0; i < c->methodscount; i++) method_free ( &(c->methods[i]) ); + MFREE (c->methods, methodinfo, c->methodscount); + + if ( (v = c->vftbl) ) { + for (i=0; iinterfacetablelength; i++) { + MFREE (v->interfacevftbl[i], methodptr, v->interfacevftbllength[i]); + } + MFREE (v->interfacevftbllength, u4, v->interfacetablelength); + MFREE (v->interfacevftbl, methodptr*, v->interfacetablelength); + + mem_free (v, sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1)); + } + + FREE (c, classinfo); +} + + +/************************* Funktion: class_findfield ************************* + + sucht in einer 'classinfo'-Struktur nach einem Feld mit gew"unschtem + Namen und Typ. + +*****************************************************************************/ + +fieldinfo *class_findfield (classinfo *c, unicode *name, unicode *desc) +{ + u4 i; + for (i=0; i < c->fieldscount; i++) { + if ( (c->fields[i].name == name) && (c->fields[i].descriptor == desc) ) + return &(c->fields[i]); + } + panic ("Can not find field given in CONSTANT_Fieldref"); + return NULL; +} + + +/************************* Funktion: class_findmethod ************************* + + sucht in einer 'classinfo'-Struktur nach einer Methode mit gew"unschtem + Namen und Typ. + Wenn als Typ NULL angegeben wird, dann ist der Typ egal. + +*****************************************************************************/ + +methodinfo *class_findmethod (classinfo *c, unicode *name, unicode *desc) +{ + u4 i; + for (i=0; i < c->methodscount; i++) { + if ( (c->methods[i].name == name) + && ( (desc == NULL) + || (c->methods[i].descriptor == desc) + ) + ) + return &(c->methods[i]); + } + return NULL; +} + + +/************************* Funktion: class_resolvemethod ************************* + + sucht eine Klasse und alle Superklassen ab, um eine Methode zu finden. + +*****************************************************************************/ + + +methodinfo *class_resolvemethod (classinfo *c, unicode *name, unicode *desc) +{ + while (c) { + methodinfo *m = class_findmethod (c, name, desc); + if (m) return m; + c = c->super; + } + return NULL; +} + + + +/************************* Funktion: class_issubclass ************************ + + "uberpr"uft, ob eine Klasse von einer anderen Klasse abgeleitet ist. + +*****************************************************************************/ + +bool class_issubclass (classinfo *sub, classinfo *super) +{ + for (;;) { + if (!sub) return false; + if (sub==super) return true; + sub = sub -> super; + } +} + + + +/****************** Initialisierungsfunktion f"ur eine Klasse **************** + + In Java kann jede Klasse ein statische Initialisierungsfunktion haben. + Diese Funktion mu"s aufgerufen werden, BEVOR irgendwelche Methoden der + Klasse aufgerufen werden, oder auf statische Variablen zugegriffen + wird. + +******************************************************************************/ + +#ifdef USE_THREADS +extern int blockInts; +#endif + +void class_init (classinfo *c) +{ + methodinfo *m; + java_objectheader *exceptionptr; + s4 i; + int b; + + if (!makeinitializations) return; + if (c->initialized) return; + c -> initialized = true; + + if (c->super) class_init (c->super); + for (i=0; i < c->interfacescount; i++) class_init(c->interfaces[i]); + + m = class_findmethod (c, + unicode_new_char (""), + unicode_new_char ("()V")); + if (!m) { + if (initverbose) { + sprintf (logtext, "Class "); + unicode_sprint (logtext+strlen(logtext), c->name); + sprintf (logtext+strlen(logtext), " has no initializer"); + dolog (); + } + return; + } + + if (! (m->flags & ACC_STATIC)) panic ("Class initializer is not static!"); + + if (initverbose) { + sprintf (logtext, "Starting initializer for class: "); + unicode_sprint (logtext+strlen(logtext), c->name); + dolog (); + } + +#ifdef USE_THREADS + b = blockInts; + blockInts = 0; +#endif + + exceptionptr = asm_calljavamethod (m, NULL,NULL,NULL,NULL); + +#ifdef USE_THREADS + assert(blockInts == 0); + blockInts = b; +#endif + + if (exceptionptr) { + printf ("#### Initializer has thrown: "); + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + fflush (stdout); + } + + if (initverbose) { + sprintf (logtext, "Finished initializer for class: "); + unicode_sprint (logtext+strlen(logtext), c->name); + dolog (); + } + +} + + + + +/********* Funktion: class_showconstantpool (nur f"ur Debug-Zwecke) ********/ + +void class_showconstantpool (classinfo *c) +{ + u4 i; + voidptr e; + + printf ("---- dump of constant pool ----\n"); + + for (i=0; icpcount; i++) { + printf ("#%d: ", (int) i); + + e = c -> cpinfos [i]; + if (e) { + + switch (c -> cptags [i]) { + case CONSTANT_Class: + printf ("Classreference -> "); + unicode_display ( ((classinfo*)e) -> name ); + break; + + case CONSTANT_Fieldref: + printf ("Fieldref -> "); goto displayFMI; + case CONSTANT_Methodref: + printf ("Methodref -> "); goto displayFMI; + case CONSTANT_InterfaceMethodref: + printf ("InterfaceMethod -> "); goto displayFMI; + displayFMI: + { + constant_FMIref *fmi = e; + unicode_display ( fmi->class->name ); + printf ("."); + unicode_display ( fmi->name); + printf (" "); + unicode_display ( fmi->descriptor ); + } + break; + + case CONSTANT_String: + printf ("String -> "); + unicode_display (e); + break; + case CONSTANT_Integer: + printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); + break; + case CONSTANT_Float: + printf ("Float -> %f", ((constant_float*)e) -> value); + break; + case CONSTANT_Double: + printf ("Double -> %f", ((constant_double*)e) -> value); + break; + case CONSTANT_Long: + { + u8 v = ((constant_long*)e) -> value; +#if U8_AVAILABLE + printf ("Long -> %ld", (long int) v); +#else + printf ("Long -> HI: %ld, LO: %ld\n", + (long int) v.high, (long int) v.low); +#endif + } + break; + case CONSTANT_NameAndType: + { constant_nameandtype *cnt = e; + printf ("NameAndType: "); + unicode_display (cnt->name); + printf (" "); + unicode_display (cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf ("Utf8 -> "); + unicode_display (e); + break; + case CONSTANT_Arraydescriptor: { + printf ("Arraydescriptor: "); + displayarraydescriptor (e); + } + break; + default: + panic ("Invalid type of ConstantPool-Entry"); + } + + } + + printf ("\n"); + } + +} + + + +/********** Funktion: class_showmethods (nur f"ur Debug-Zwecke) ************/ + +void class_showmethods (classinfo *c) +{ + u4 i; + + printf ("--------- Fields and Methods ----------------\n"); + printf ("Flags: "); printflags (c->flags); printf ("\n"); + + printf ("This: "); unicode_display (c->name); printf ("\n"); + if (c->super) { + printf ("Super: "); unicode_display (c->super->name); printf ("\n"); + } + printf ("Index: %d\n", c->index); + + printf ("interfaces:\n"); + for (i=0; i < c-> interfacescount; i++) { + printf (" "); + unicode_display (c -> interfaces[i] -> name); + printf (" (%d)\n", c->interfaces[i] -> index); + } + + printf ("fields:\n"); + for (i=0; i < c -> fieldscount; i++) { + field_display (&(c -> fields[i])); + } + + printf ("methods:\n"); + for (i=0; i < c -> methodscount; i++) { + methodinfo *m = &(c->methods[i]); + if ( !(m->flags & ACC_STATIC)) + printf ("vftblindex: %d ", m->vftblindex); + + method_display ( m ); + + } + + printf ("Virtual function table:\n"); + for (i=0; ivftbl->vftbllength; i++) { + printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]) ); + } + +} + + + +/*****************************************************************************/ +/******************* Funktionen fuer den Class-loader generell ***************/ +/*****************************************************************************/ + + +/********************* Funktion: loader_load ********************************** + + l"adt und linkt die ge"unschte Klasse und alle davon + referenzierten Klassen und Interfaces + Return: Einen Zeiger auf diese Klasse + +******************************************************************************/ + +classinfo *loader_load (unicode *topname) +{ + classinfo *top; + classinfo *c; + long int starttime=0,stoptime=0; + + intsDisable(); /* schani */ + + if (getloadingtime) starttime = getcputime(); + + + top = class_get (topname); + + while ( (c = list_first(&unloadedclasses)) ) { + class_load (c); + } + + while ( (c = list_first(&unlinkedclasses)) ) { + class_link (c); + } + + + synchronize_caches (); + + + + if (getloadingtime) { + stoptime = getcputime(); + loadingtime += (stoptime-starttime); + } + + intsRestore(); /* schani */ + + return top; +} + + +/******************* interne Funktion: loader_createarrayclass **************** + + Erzeugt (und linkt) eine Klasse f"ur die Arrays. + +******************************************************************************/ + +static classinfo *loader_createarrayclass () +{ + classinfo *c; + c = class_get ( unicode_new_char ("The_Array_Class") ); + + list_remove (&unloadedclasses, c); + list_addlast (&unlinkedclasses, c); + c -> super = class_java_lang_Object; + + class_link (c); + return c; +} + + + +/********************** Funktion: loader_init ********************************* + + Initialisiert alle Listen und l"adt alle Klassen, die vom System + und vom Compiler direkt ben"otigt werden. + +******************************************************************************/ + +void loader_init () +{ + interfaceindex = 0; + + list_init (&unloadedclasses, OFFSET(classinfo, listnode) ); + list_init (&unlinkedclasses, OFFSET(classinfo, listnode) ); + list_init (&linkedclasses, OFFSET(classinfo, listnode) ); + + + class_java_lang_Object = + loader_load ( unicode_new_char ("java/lang/Object") ); + class_java_lang_String = + loader_load ( unicode_new_char ("java/lang/String") ); + class_java_lang_ClassCastException = + loader_load ( unicode_new_char ("java/lang/ClassCastException") ); + class_java_lang_NullPointerException = + loader_load ( unicode_new_char ("java/lang/NullPointerException") ); + class_java_lang_ArrayIndexOutOfBoundsException = loader_load ( + unicode_new_char ("java/lang/ArrayIndexOutOfBoundsException") ); + class_java_lang_NegativeArraySizeException = loader_load ( + unicode_new_char ("java/lang/NegativeArraySizeException") ); + class_java_lang_OutOfMemoryError = loader_load ( + unicode_new_char ("java/lang/OutOfMemoryError") ); + class_java_lang_ArrayStoreException = + loader_load ( unicode_new_char ("java/lang/ArrayStoreException") ); + class_java_lang_ArithmeticException = + loader_load ( unicode_new_char ("java/lang/ArithmeticException") ); + class_java_lang_ThreadDeath = /* schani */ + loader_load ( unicode_new_char ("java/lang/ThreadDeath") ); + + class_array = loader_createarrayclass (); + + + proto_java_lang_ClassCastException = + builtin_new(class_java_lang_ClassCastException); + heap_addreference ( (void**) &proto_java_lang_ClassCastException); + + proto_java_lang_NullPointerException = + builtin_new(class_java_lang_NullPointerException); + heap_addreference ( (void**) &proto_java_lang_NullPointerException); + + proto_java_lang_ArrayIndexOutOfBoundsException = + builtin_new(class_java_lang_ArrayIndexOutOfBoundsException); + heap_addreference ( (void**) &proto_java_lang_ArrayIndexOutOfBoundsException); + + proto_java_lang_NegativeArraySizeException = + builtin_new(class_java_lang_NegativeArraySizeException); + heap_addreference ( (void**) &proto_java_lang_NegativeArraySizeException); + + proto_java_lang_OutOfMemoryError = + builtin_new(class_java_lang_OutOfMemoryError); + heap_addreference ( (void**) &proto_java_lang_OutOfMemoryError); + + proto_java_lang_ArithmeticException = + builtin_new(class_java_lang_ArithmeticException); + heap_addreference ( (void**) &proto_java_lang_ArithmeticException); + + proto_java_lang_ArrayStoreException = + builtin_new(class_java_lang_ArrayStoreException); + heap_addreference ( (void**) &proto_java_lang_ArrayStoreException); + + proto_java_lang_ThreadDeath = /* schani */ + builtin_new(class_java_lang_ThreadDeath); + heap_addreference ( (void**) &proto_java_lang_ThreadDeath); +} + + + + +/********************* Funktion: loader_initclasses **************************** + + initialisiert alle geladenen aber noch nicht initialisierten Klassen + +******************************************************************************/ + +void loader_initclasses () +{ + classinfo *c; + + intsDisable(); /* schani */ + + if (makeinitializations) { + c = list_first (&linkedclasses); + while (c) { + class_init (c); + c = list_next (&linkedclasses, c); + } + } + + intsRestore(); /* schani */ +} + + + +/******************** Funktion: loader_close ********************************** + + gibt alle Resourcen wieder frei + +******************************************************************************/ + +void loader_close () +{ + classinfo *c; + + while ( (c=list_first(&unloadedclasses)) ) { + list_remove (&unloadedclasses,c); + class_free (c); + } + while ( (c=list_first(&unlinkedclasses)) ) { + list_remove (&unlinkedclasses,c); + class_free (c); + } + while ( (c=list_first(&linkedclasses)) ) { + list_remove (&linkedclasses,c); + class_free (c); + } +} + diff --git a/loader.h b/loader.h new file mode 100644 index 000000000..190a6458a --- /dev/null +++ b/loader.h @@ -0,0 +1,53 @@ +/******************************* loader.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the prototypes for the class loader. + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/14 + +*******************************************************************************/ + + +/************************* program switches ***********************************/ + +extern bool loadverbose; /* Debug-Meldungen beim Laden ausgeben */ +extern bool linkverbose; +extern bool initverbose; /* Meldungen ausgeben, wenn Klasse + initialisiert wird */ +extern bool makeinitializations; /* Klassen automatisch initialisieren */ + +extern bool getloadingtime; +extern long int loadingtime; /* CPU-Zeit f"urs Laden der Klassen */ + +extern list linkedclasses; /* Liste aller fertig gelinkten Klassen */ + + +/************************ prototypes ******************************************/ + +void loader_init (); +void loader_close (); + +classinfo *loader_load (unicode *topname); +void loader_initclasses (); + +classinfo *class_get (unicode *name); +voidptr class_getconstant (classinfo *class, u4 pos, u4 ctype); +u4 class_constanttype (classinfo *class, u4 pos); + +fieldinfo *class_findfield (classinfo *c, unicode *name, unicode *desc); +methodinfo *class_findmethod (classinfo *c, unicode *name, unicode *desc); + +methodinfo *class_resolvemethod (classinfo *c, unicode *name, unicode *dest); + +bool class_issubclass (classinfo *sub, classinfo *super); + +void class_init (classinfo *c); + +void class_showmethods (classinfo *c); +void class_showconstantpool (classinfo *c); + diff --git a/main.c b/main.c new file mode 100644 index 000000000..d91cfc830 --- /dev/null +++ b/main.c @@ -0,0 +1,750 @@ +/******************************* main.c **************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enthaelt die Funktion main() und die Variablen fuer die + globalen Optionen. + Dieser Modul erledigt folgende Aufgaben: + - Bearbeiten der command-line-options + - Aufrufen aller Initialisierungsroutinen + - Aufrufen des Classloaders + - Starten der main - Methode + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Andi Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/29 + +*******************************************************************************/ + +#include "global.h" + +#include "tables.h" +#include "compiler.h" +#include "ncomp/ncomp.h" +#include "loader.h" + +#include "asmpart.h" +#include "builtin.h" +#include "native.h" + +#include "threads/thread.h" /* schani */ + +bool compileall = false; +int newcompiler = true; +bool verbose = false; + +#ifndef USE_THREADS +void **stackbottom = 0; +#endif + + +/********************* interne Funktion: get_opt ***************************** + + liest die n"achste Option aus der Kommandozeile + +******************************************************************************/ + +#define OPT_DONE -1 +#define OPT_ERROR 0 +#define OPT_IGNORE 1 + +#define OPT_CLASSPATH 2 +#define OPT_D 3 +#define OPT_MS 4 +#define OPT_MX 5 +#define OPT_VERBOSE1 6 +#define OPT_VERBOSE 7 +#define OPT_VERBOSEGC 8 +#define OPT_VERBOSECALL 9 +#define OPT_IEEE 10 +#define OPT_SOFTNULL 11 +#define OPT_TIME 12 +#define OPT_STAT 13 +#define OPT_LOG 14 +#define OPT_CHECK 15 +#define OPT_LOAD 16 +#define OPT_METHOD 17 +#define OPT_SIGNATURE 18 +#define OPT_SHOW 19 +#define OPT_ALL 20 +#define OPT_OLD 21 + +struct { char *name; bool arg; int value; } opts[] = { + { "classpath", true, OPT_CLASSPATH }, + { "D", true, OPT_D }, + { "ms", true, OPT_MS }, + { "mx", true, OPT_MX }, + { "noasyncgc", false, OPT_IGNORE }, + { "noverify", false, OPT_IGNORE }, + { "oss", true, OPT_IGNORE }, + { "ss", true, OPT_IGNORE }, + { "v", false, OPT_VERBOSE1 }, + { "verbose", false, OPT_VERBOSE }, + { "verbosegc", false, OPT_VERBOSEGC }, + { "verbosecall", false, OPT_VERBOSECALL }, + { "ieee", false, OPT_IEEE }, + { "softnull", false, OPT_SOFTNULL }, + { "time", false, OPT_TIME }, + { "stat", false, OPT_STAT }, + { "log", true, OPT_LOG }, + { "c", true, OPT_CHECK }, + { "l", false, OPT_LOAD }, + { "m", true, OPT_METHOD }, + { "sig", true, OPT_SIGNATURE }, + { "s", true, OPT_SHOW }, + { "all", false, OPT_ALL }, + { "old", false, OPT_OLD }, + { NULL, false, 0 } +}; + +static int opt_ind = 1; +static char *opt_arg; + +static int get_opt (int argc, char **argv) +{ + char *a; + int i; + + if (opt_ind >= argc) return OPT_DONE; + + a = argv[opt_ind]; + if (a[0] != '-') return OPT_DONE; + + for (i=0; opts[i].name; i++) { + if (! opts[i].arg) { + if (strcmp(a+1, opts[i].name) == 0) { /* boolean option found */ + opt_ind++; + return opts[i].value; + } + } + else { + if (strcmp(a+1, opts[i].name) == 0) { /* parameter option found */ + opt_ind++; + if (opt_ind < argc) { + opt_arg = argv[opt_ind]; + opt_ind++; + return opts[i].value; + } + return OPT_ERROR; + } + else { + size_t l = strlen(opts[i].name); + if (strlen(a+1) > l) { + if (memcmp (a+1, opts[i].name, l)==0) { + opt_ind++; + opt_arg = a+1+l; + return opts[i].value; + } + } + } + } + } /* end for */ + + return OPT_ERROR; +} + + + + +/******************** interne Funktion: print_usage ************************ + +Gibt die richtige Aufrufsyntax des JavaVM-Compilers auf stdout aus. + +***************************************************************************/ + +static void print_usage() +{ + printf ("USAGE: cacao [options] classname [program arguments\n"); + printf ("Options:\n"); + printf (" -classpath path ...... specify a path to look for classes\n"); + printf (" -Dpropertyname=value . add an entry to the property list\n"); + printf (" -mx maxmem[k|m] ...... specify the size for the heap\n"); + printf (" -ms initmem[k|m] ..... specify the initial size for the heap\n"); + printf (" -v ................... write state-information\n"); + printf (" -verbose ............. write more information\n"); + printf (" -verbosegc ........... write message for each GC\n"); + printf (" -verbosecall ......... write message for each call\n"); + printf (" -ieee ................ use ieee compliant arithmetic\n"); + printf (" -softnull ............ use software nullpointer check\n"); + printf (" -time ................ measure the runtime\n"); + printf (" -stat ................ detailed compiler statistics\n"); + printf (" -log logfile ......... specify a name for the logfile\n"); + printf (" -c(heck) b(ounds...... don't check array bounds\n"); + printf (" s(ync) ...... don't check for synchronization\n"); + printf (" -l ................... don't start the class after loading\n"); + printf (" -all ................. compile all methods, no execution\n"); + printf (" -old ................. use old JIT compiler\n"); + printf (" -m ................... compile only a specific method\n"); + printf (" -sig ................. specify signature for a specific method\n"); + printf (" -s(how)m(ethods) ..... show all methods&fields of a class\n"); + printf (" c(onstants) ... show the constant pool\n"); + printf (" a(ssembler) ... show disassembled listing\n"); + printf (" s(tack) ....... show stack for every javaVM-command\n"); + printf (" i(ntermediate). show intermediate representation\n"); + printf (" u(nicode) ..... show the unicode - hash\n"); +} + + + +/***************************** Funktion: print_times ********************* + + gibt eine Aufstellung der verwendeten CPU-Zeit aus + +**************************************************************************/ + +static void print_times() +{ + long int totaltime = getcputime(); + long int runtime = totaltime - loadingtime - compilingtime; + + sprintf (logtext, "Time for loading classes: %ld secs, %ld millis", + loadingtime / 1000000, (loadingtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Time for compiling code: %ld secs, %ld millis", + compilingtime / 1000000, (compilingtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Time for running program: %ld secs, %ld millis", + runtime / 1000000, (runtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Total time: %ld secs, %ld millis", + totaltime / 1000000, (totaltime % 1000000) / 1000); + dolog(); +} + + + + + + +/***************************** Funktion: print_stats ********************* + + outputs detailed compiler statistics + +**************************************************************************/ + +static void print_stats() +{ + sprintf (logtext, "Number of JitCompiler Calls: %d", count_jit_calls); + dolog(); + sprintf (logtext, "Number of compiled Methods: %d", count_methods); + dolog(); + sprintf (logtext, "Number of max basic blocks per method: %d", count_max_basic_blocks); + dolog(); + sprintf (logtext, "Number of compiled basic blocks: %d", count_basic_blocks); + dolog(); + sprintf (logtext, "Number of max JavaVM-Instructions per method: %d", count_max_javainstr); + dolog(); + sprintf (logtext, "Number of compiled JavaVM-Instructions: %d", count_javainstr); + dolog(); + sprintf (logtext, "Size of compiled JavaVM-Instructions: %d(%d)", count_javacodesize, + count_javacodesize - count_methods * 18); + dolog(); + sprintf (logtext, "Size of compiled Exception Tables: %d", count_javaexcsize); + dolog(); + sprintf (logtext, "Value of extended instruction set var: %d", has_ext_instr_set); + dolog(); + sprintf (logtext, "Number of Alpha-Instructions: %d", count_code_len >> 2); + dolog(); + sprintf (logtext, "Number of Spills: %d", count_spills); + dolog(); + sprintf (logtext, "Number of Activ Pseudocommands: %5d", count_pcmd_activ); + dolog(); + sprintf (logtext, "Number of Drop Pseudocommands: %5d", count_pcmd_drop); + dolog(); + sprintf (logtext, "Number of Const Pseudocommands: %5d (zero:%5d)", count_pcmd_load, count_pcmd_zero); + dolog(); + sprintf (logtext, "Number of ConstAlu Pseudocommands: %5d (cmp: %5d, store:%5d)", count_pcmd_const_alu, count_pcmd_const_bra, count_pcmd_const_store); + dolog(); + sprintf (logtext, "Number of Move Pseudocommands: %5d", count_pcmd_move); + dolog(); + sprintf (logtext, "Number of Load Pseudocommands: %5d", count_load_instruction); + dolog(); + sprintf (logtext, "Number of Store Pseudocommands: %5d (combined: %5d)", count_pcmd_store, count_pcmd_store - count_pcmd_store_comb); + dolog(); + sprintf (logtext, "Number of OP Pseudocommands: %5d", count_pcmd_op); + dolog(); + sprintf (logtext, "Number of DUP Pseudocommands: %5d", count_dup_instruction); + dolog(); + sprintf (logtext, "Number of Mem Pseudocommands: %5d", count_pcmd_mem); + dolog(); + sprintf (logtext, "Number of Method Pseudocommands: %5d", count_pcmd_met); + dolog(); + sprintf (logtext, "Number of Branch Pseudocommands: %5d (rets:%5d, Xrets: %5d)", + count_pcmd_bra, count_pcmd_return, count_pcmd_returnx); + dolog(); + sprintf (logtext, "Number of Table Pseudocommands: %5d", count_pcmd_table); + dolog(); + sprintf (logtext, "Number of Useful Pseudocommands: %5d", count_pcmd_table + + count_pcmd_bra + count_pcmd_load + count_pcmd_mem + count_pcmd_op); + dolog(); + sprintf (logtext, "Number of Null Pointer Checks: %5d", count_check_null); + dolog(); + sprintf (logtext, "Number of Array Bound Checks: %5d", count_check_bound); + dolog(); + sprintf (logtext, "Number of Try-Blocks: %d", count_tryblocks); + dolog(); + sprintf (logtext, "Maximal count of stack elements: %d", count_max_new_stack); + dolog(); + sprintf (logtext, "Upper bound of max stack elements: %d", count_upper_bound_new_stack); + dolog(); + sprintf (logtext, "Distribution of stack sizes at block boundary"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_block_stack[0], + count_block_stack[1],count_block_stack[2],count_block_stack[3],count_block_stack[4], + count_block_stack[5],count_block_stack[6],count_block_stack[7],count_block_stack[8], + count_block_stack[9],count_block_stack[10]); + dolog(); + sprintf (logtext, "Distribution of store stack depth"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_depth[0], + count_store_depth[1],count_store_depth[2],count_store_depth[3],count_store_depth[4], + count_store_depth[5],count_store_depth[6],count_store_depth[7],count_store_depth[8], + count_store_depth[9],count_store_depth[10]); + dolog(); + sprintf (logtext, "Distribution of store creator chains first part"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 "); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_length[0], + count_store_length[1],count_store_length[2],count_store_length[3],count_store_length[4], + count_store_length[5],count_store_length[6],count_store_length[7],count_store_length[8], + count_store_length[9]); + dolog(); + sprintf (logtext, "Distribution of store creator chains second part"); + dolog(); + sprintf (logtext, " 10 11 12 13 14 15 16 17 18 19 >=20"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_length[10], + count_store_length[11],count_store_length[12],count_store_length[13],count_store_length[14], + count_store_length[15],count_store_length[16],count_store_length[17],count_store_length[18], + count_store_length[19],count_store_length[20]); + dolog(); + sprintf (logtext, "Distribution of analysis iterations"); + dolog(); + sprintf (logtext, " 1 2 3 4 >=5"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d", count_analyse_iterations[0],count_analyse_iterations[1], + count_analyse_iterations[2],count_analyse_iterations[3],count_analyse_iterations[4]); + dolog(); + sprintf (logtext, "Distribution of basic blocks per method"); + dolog(); + sprintf (logtext, " <= 5 <=10 <=15 <=20 <=30 <=40 <=50 <=75 >75"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_method_bb_distribution[0], + count_method_bb_distribution[1],count_method_bb_distribution[2],count_method_bb_distribution[3], + count_method_bb_distribution[4],count_method_bb_distribution[5],count_method_bb_distribution[6], + count_method_bb_distribution[7],count_method_bb_distribution[8]); + dolog(); + sprintf (logtext, "Distribution of basic block sizes"); + dolog(); + sprintf (logtext, + " 1 2 3 4 5 6 7 8 9 10 <13 <15 <17 <19 <21 <26 <31 >30"); + dolog(); + sprintf (logtext, "%3d%5d%5d%5d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d", + count_block_size_distribution[0], count_block_size_distribution[1], count_block_size_distribution[2], + count_block_size_distribution[3], count_block_size_distribution[4], count_block_size_distribution[5], + count_block_size_distribution[6], count_block_size_distribution[7], count_block_size_distribution[8], + count_block_size_distribution[9], count_block_size_distribution[10],count_block_size_distribution[11], + count_block_size_distribution[12],count_block_size_distribution[13],count_block_size_distribution[14], + count_block_size_distribution[15],count_block_size_distribution[16],count_block_size_distribution[17]); + dolog(); + sprintf (logtext, "Size of Code Area (Kb): %10.3f", (float) count_code_len / 1024); + dolog(); + sprintf (logtext, "Size of data Area (Kb): %10.3f", (float) count_data_len / 1024); + dolog(); + sprintf (logtext, "Size of Class Infos (Kb):%10.3f", (float) (count_class_infos) / 1024); + dolog(); + sprintf (logtext, "Size of Const Pool (Kb): %10.3f", (float) (count_const_pool_len + count_unicode_len) / 1024); + dolog(); + sprintf (logtext, "Size of Vftbl (Kb): %10.3f", (float) count_vftbl_len / 1024); + dolog(); + sprintf (logtext, "Size of comp stub (Kb): %10.3f", (float) count_cstub_len / 1024); + dolog(); + sprintf (logtext, "Size of native stub (Kb):%10.3f", (float) count_nstub_len / 1024); + dolog(); + sprintf (logtext, "Size of Unicode (Kb): %10.3f", (float) count_unicode_len / 1024); + dolog(); + sprintf (logtext, "Size of VMCode (Kb): %10.3f(%d)", (float) count_vmcode_len / 1024, + count_vmcode_len - 18 * count_all_methods); + dolog(); + sprintf (logtext, "Size of ExTable (Kb): %10.3f", (float) count_extable_len / 1024); + dolog(); + sprintf (logtext, "Number of loaded Methods: %d\n\n", count_all_methods); + dolog(); +} + + +/********** Funktion: class_compile_methods (nur f"ur Debug-Zwecke) ********/ + +void class_compile_methods () +{ + int i; + classinfo *c; + methodinfo *m; + + c = list_first (&linkedclasses); + while (c) { + for (i = 0; i < c -> methodscount; i++) { + m = &(c->methods[i]); + if (m->jcode) { + if (newcompiler) + (void) new_compile(m); + else + (void) compiler_compile(m); + } + } + c = list_next (&linkedclasses, c); + } +} + + +/************************** Funktion: main ******************************* + + Das Hauptprogramm. + Wird vom System zu Programstart aufgerufen (eh klar). + +**************************************************************************/ + + +int main(int argc, char **argv) +{ + s4 i,j; + char *cp; + classinfo *topclass; + java_objectheader *exceptionptr; + void *dummy; + + + /********** interne (nur fuer main relevante Optionen) **************/ + + char logfilename[200] = ""; + u4 heapsize = 16000000; + u4 heapstartsize = 200000; + char classpath[500] = ".:/usr/local/lib/java/classes"; + bool showmethods = false; + bool showconstantpool = false; + bool showunicode = false; + bool startit = true; + char *specificmethodname = NULL; + char *specificsignature = NULL; + +#ifndef USE_THREADS + stackbottom = &dummy; +#endif + + + /************ Infos aus der Environment lesen ************************/ + + cp = getenv ("CLASSPATH"); + if (cp) { + strcpy (classpath, cp); + } + + /***************** Interpretieren der Kommandozeile *****************/ + + checknull = false; + checkfloats = false; + + while ( (i = get_opt(argc,argv)) != OPT_DONE) { + + switch (i) { + case OPT_IGNORE: break; + + case OPT_CLASSPATH: + strcpy (classpath + strlen(classpath), ":"); + strcpy (classpath + strlen(classpath), opt_arg); + break; + + case OPT_D: + { + int n,l=strlen(opt_arg); + for (n=0; n= argc) { + print_usage (); + exit(10); + } + + + /**************************** Programmstart *****************************/ + + log_init (logfilename); + if (verbose) { + log_text ( + "CACAO started -------------------------------------------------------"); + } + + suck_init (classpath); + native_setclasspath (classpath); + + unicode_init(); + heap_init(heapsize, heapstartsize, &dummy); + loader_init(); + compiler_init(); + ncomp_init(); + + native_loadclasses (); + + + /*********************** JAVA-Klassen laden ***************************/ + + cp = argv[opt_ind++]; + for (i=strlen(cp)-1; i>=0; i--) { /* Punkte im Klassennamen */ + if (cp[i]=='.') cp[i]='/'; /* auf slashes umbauen */ + } + + topclass = loader_load ( unicode_new_char (cp) ); + + gc_init(); + +#ifdef USE_THREADS + initThreads((u1*)&dummy); /* schani */ +#endif + + /************************* Arbeitsroutinen starten ********************/ + + if (startit) { + methodinfo *mainmethod; + java_objectarray *a; + + mainmethod = class_findmethod ( + topclass, + unicode_new_char ("main"), + unicode_new_char ("([Ljava/lang/String;)V") + ); + if (!mainmethod) panic ("Can not find method 'void main(String[])'"); + if ((mainmethod->flags & ACC_STATIC) != ACC_STATIC) panic ("main is not static!"); + + a = builtin_anewarray (argc - opt_ind, class_java_lang_String); + for (i=opt_ind; idata[i-opt_ind] = javastring_new (unicode_new_char (argv[i]) ); + } + exceptionptr = asm_calljavamethod (mainmethod, a, NULL,NULL,NULL ); + + if (exceptionptr) { + printf ("#### Program has thrown: "); + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + } + +/* killThread(currentThread); */ + + } + + /************* Auf Wunsch alle Methode "ubersetzen ********************/ + + if (compileall) { + class_compile_methods(); + } + + + /******** Auf Wunsch eine spezielle Methode "ubersetzen ***************/ + + if (specificmethodname) { + methodinfo *m; + if (specificsignature) + m = class_findmethod(topclass, + unicode_new_char(specificmethodname), + unicode_new_char(specificsignature)); + else + m = class_findmethod(topclass, + unicode_new_char(specificmethodname), NULL); + if (!m) panic ("Specific method not found"); + if (newcompiler) + (void) new_compile(m); + else + (void) compiler_compile(m); + } + + /********************* Debug-Tabellen ausgeben ************************/ + + if (showmethods) class_showmethods (topclass); + if (showconstantpool) class_showconstantpool (topclass); + if (showunicode) unicode_show (); + + + + /************************ Freigeben aller Resourcen *******************/ + + compiler_close (); + loader_close (); + heap_close (); + unicode_close ( literalstring_free ); + + + /* Endemeldung ausgeben und mit entsprechendem exit-Status terminieren */ + + if (verbose || getcompilingtime || statistics) { + log_text ("CACAO terminated"); + if (statistics) + print_stats (); + if (getcompilingtime) + print_times (); + mem_usagelog(1); + } + + exit(0); + return 1; +} + + + +/************************************ SHUTDOWN-Funktion ********************************* + + Terminiert das System augenblicklich, ohne den Speicher + explizit freizugeben (eigentlich nur f"ur abnorme + Programmterminierung) + +*****************************************************************************************/ + +void cacao_shutdown(s4 status) +{ + if (verbose || getcompilingtime || statistics) { + log_text ("CACAO terminated by shutdown"); + if (statistics) + print_stats (); + if (getcompilingtime) + print_times (); + mem_usagelog(0); + sprintf (logtext, "Exit status: %d\n", (int) status); + dolog(); + } + + exit(status); +} diff --git a/nat/io.c b/nat/io.c new file mode 100644 index 000000000..c7abc6b0d --- /dev/null +++ b/nat/io.c @@ -0,0 +1,473 @@ +/****************************** nat/io.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the native functions for class java.io. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/22 + +*******************************************************************************/ + +#include +#include +#include +#ifdef _OSF_SOURCE +#include +#endif +#include + +#include "../threads/threadio.h" /* schani */ + +/* + * io is performed through the threaded... functions, since io operations may + * block and the corresponding thread must, in this case, be suspended. + * + * schani + */ + +/********************* java.io.FileDescriptor ********************************/ + +s4 java_io_FileDescriptor_valid (struct java_io_FileDescriptor* this) +{ + if (this->fd >= 0) return 1; + return 0; +} + +struct java_io_FileDescriptor* java_io_FileDescriptor_initSystemFD + (struct java_io_FileDescriptor* fd, s4 handle) +{ + switch (handle) { + case 0: fd -> fd = fileno(stdin); + break; + case 1: fd -> fd = fileno(stdout); + break; + case 2: fd -> fd = fileno(stderr); + break; + default: panic ("Invalid file descriptor number"); + } + + threadedFileDescriptor(fd->fd); + + return fd; +} + + +/************************* java.io.FileInputStream ***************************/ + + +void java_io_FileInputStream_open + (struct java_io_FileInputStream* this, struct java_lang_String* name) +{ + s4 fd; + char *fname = javastring_tochar ((java_objectheader*)name); + + if (!fname) goto fail; + + fd = open (fname, O_RDONLY, 0); + if (fd<0) goto fail; + + threadedFileDescriptor(fd); + + this->fd->fd = fd; + return; + + fail: + exceptionptr = native_new_and_init (class_java_io_IOException); + return; +} + +s4 java_io_FileInputStream_read (struct java_io_FileInputStream* this) +{ + s4 r; + u1 buffer[1]; + r = threadedRead (this->fd->fd, (char *) buffer, 1); + + if (r>0) return buffer[0]; + if (r==0) return -1; + + exceptionptr = native_new_and_init (class_java_io_IOException); + return 0; +} + + +s4 java_io_FileInputStream_readBytes (struct java_io_FileInputStream* this, + java_bytearray* buffer, s4 start, s4 len) +{ + s4 ret = threadedRead (this->fd->fd, (char *) buffer->data+start, len); + if (ret>0) return ret; + if (ret==0) return -1; + + exceptionptr = native_new_and_init (class_java_io_IOException); + return 0; +} + + +s8 java_io_FileInputStream_skip + (struct java_io_FileInputStream* this, s8 numbytes) +{ + s4 ret = lseek (this->fd->fd, builtin_l2i(numbytes), SEEK_CUR); + if (ret>0) return builtin_i2l(ret); + if (ret==0) return builtin_i2l(-1); + + exceptionptr = native_new_and_init (class_java_io_IOException); + return builtin_i2l(0); +} + +s4 java_io_FileInputStream_available (struct java_io_FileInputStream* this) +{ + struct stat buffer; + s4 r1,r2; + + r1 = fstat (this->fd->fd, &buffer); + r2 = lseek(this->fd->fd, 0, SEEK_CUR); + + if ( (r1 >= 0) && (r2 >= 0) ) + return buffer.st_size - r2; + + exceptionptr = native_new_and_init (class_java_io_IOException); + return 0; +} + +void java_io_FileInputStream_close (struct java_io_FileInputStream* this) +{ + if (this->fd->fd >= 0) { + s4 r = close (this->fd->fd); + this->fd->fd = -1; + if (r < 0) + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + + + + + +/*************************** java.io.FileOutputStream ************************/ + + +void java_io_FileOutputStream_open (struct java_io_FileOutputStream* this, + struct java_lang_String* name) +{ + s4 fd; + char *fname = javastring_tochar ((java_objectheader*)name); + if (!fname) goto fail; + + fd = creat (fname, 0666); + if (fd<0) goto fail; + + threadedFileDescriptor(fd); + + this->fd->fd = fd; + return; + + fail: + exceptionptr = native_new_and_init (class_java_io_IOException); + return; +} + + +void java_io_FileOutputStream_write + (struct java_io_FileOutputStream* this, s4 byte) +{ + u1 buffer[1]; + s4 l; + + buffer[0] = byte; + l = threadedWrite (this->fd->fd, (char *) buffer, 1); + + if (l<1) { + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + +void java_io_FileOutputStream_writeBytes (struct java_io_FileOutputStream* this, + java_bytearray* buffer, s4 start, s4 len) +{ + s4 o; + + if (len == 0) + return; + o = threadedWrite (this->fd->fd, (char *) buffer->data+start, len); + if (o!=len) + exceptionptr = native_new_and_init (class_java_io_IOException); +} + +void java_io_FileOutputStream_close (struct java_io_FileOutputStream* this) +{ + if (this->fd->fd >= 0) { + s4 r = close (this->fd->fd); + this->fd->fd = -1; + if (r<0) + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + + + +/************************** java.io.File **************************************/ + +s4 java_io_File_exists0 (struct java_io_File* this) +{ + struct stat buffer; + char *path; + int err; + + path = javastring_tochar( (java_objectheader*) (this->path)); + + err = stat (path, &buffer); + if (err==0) return 1; + return 0; +} + +s4 java_io_File_canWrite0 (struct java_io_File* this) +{ + int err; + err = access (javastring_tochar( (java_objectheader*) (this->path)), W_OK); + if (err==0) return 1; + return 0; +} + +s4 java_io_File_canRead0 (struct java_io_File* this) +{ + int err; + err = access (javastring_tochar( (java_objectheader*) (this->path)), R_OK); + if (err==0) return 1; + return 0; +} + +s4 java_io_File_isFile0 (struct java_io_File* this) +{ + struct stat buffer; + char *path; + int err; + + path = javastring_tochar( (java_objectheader*) (this->path)); + + err = stat (path, &buffer); + if (err!=0) return 0; + if (S_ISREG(buffer.st_mode)) return 1; + return 0; +} + +s4 java_io_File_isDirectory0 (struct java_io_File* this) +{ + struct stat buffer; + char *path; + int err; + + path = javastring_tochar( (java_objectheader*) (this->path)); + + err = stat (path, &buffer); + if (err!=0) return 0; + if (S_ISDIR(buffer.st_mode)) return 1; + return 0; +} + +s8 java_io_File_lastModified0 (struct java_io_File* this) +{ + struct stat buffer; + int err; + err = stat (javastring_tochar( (java_objectheader*) (this->path)), &buffer); + if (err!=0) return builtin_i2l(0); + return builtin_lmul (builtin_i2l(buffer.st_mtime), builtin_i2l(1000) ); +} + +s8 java_io_File_length0 (struct java_io_File* this) +{ + struct stat buffer; + int err; + err = stat (javastring_tochar( (java_objectheader*) (this->path)), &buffer); + if (err!=0) return builtin_i2l(0); + return builtin_i2l(buffer.st_size); +} + +s4 java_io_File_mkdir0 (struct java_io_File* this) +{ + char *name = javastring_tochar ( (java_objectheader*) (this->path) ); + int err = mkdir (name, 0777); + if (err==0) return 1; + return 0; +} + +s4 java_io_File_renameTo0 (struct java_io_File* this, struct java_io_File* new) +{ +#define MAXPATHLEN 200 + char newname[MAXPATHLEN]; + char *n = javastring_tochar ( (java_objectheader*) (new->path) ); + int err; + + if (strlen(n)>=MAXPATHLEN) return 0; + strcpy (newname, n); + n = javastring_tochar ( (java_objectheader*) (this->path) ); + err = rename (n, newname); + if (err==0) return 1; + return 0; +} + +s4 java_io_File_delete0 (struct java_io_File* this) +{ + int err; + err = remove (javastring_tochar ( (java_objectheader*) (this->path) ) ); + if (err==0) return 1; + return 0; +} + +java_objectarray* java_io_File_list0 (struct java_io_File* this) +{ + char *name; + DIR *d; + int i,len, namlen; + java_objectarray *a; + struct dirent *ent; + struct java_lang_String *n; + char entbuffer[257]; + + name = javastring_tochar ( (java_objectheader*) (this->path) ); + d = opendir(name); + if (!d) return NULL; + + len=0; + while (readdir(d) != NULL) len++; + rewinddir (d); + + a = builtin_anewarray (len, class_java_lang_String); + if (!a) { + closedir(d); + return NULL; + } + + for (i=0; id_name); + memcpy (entbuffer, ent->d_name, namlen); + entbuffer[namlen] = '\0'; + + n = (struct java_lang_String*) + javastring_new_char (entbuffer); + + a -> data[i] = (java_objectheader*) n; + } + } + + + closedir(d); + return a; +} + +s4 java_io_File_isAbsolute (struct java_io_File* this) +{ + char *name = javastring_tochar ( (java_objectheader*) (this->path) ); + if (name[0] == '/') return 1; + return 0; +} + + + + +/********************** java.io.RandomAccessFile *****************************/ + +void java_io_RandomAccessFile_open (struct java_io_RandomAccessFile* this, + struct java_lang_String* name, s4 writeable) +{ + s4 fd; + char *fname = javastring_tochar ((java_objectheader*)name); + + if (writeable) fd = open (fname, O_RDWR, 0); + else fd = open (fname, O_RDONLY, 0); + if (fd==-1) goto fail; + + threadedFileDescriptor(fd); + + this->fd->fd = fd; + return; + + fail: + exceptionptr = native_new_and_init (class_java_io_IOException); + return; +} + +s4 java_io_RandomAccessFile_read (struct java_io_RandomAccessFile* this) +{ + s4 r; + u1 buffer[1]; + r = threadedRead (this->fd->fd, (char *) buffer, 1); + if (r>0) return buffer[1]; + if (r==0) return -1; + exceptionptr = native_new_and_init (class_java_io_IOException); + return 0; +} + +s4 java_io_RandomAccessFile_readBytes (struct java_io_RandomAccessFile* this, + java_bytearray* buffer, s4 start, s4 len) +{ + s4 r = threadedRead (this->fd->fd, (char *) buffer->data+start, len); + if (r>0) return r; + if (r==0) return -1; + exceptionptr = native_new_and_init (class_java_io_IOException); + return 0; +} + +void java_io_RandomAccessFile_write + (struct java_io_RandomAccessFile* this, s4 byte) +{ + u1 buffer[1]; + int r; + buffer[1] = byte; + r = write (this->fd->fd, buffer, 1); + if (r<0) { + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + +void java_io_RandomAccessFile_writeBytes (struct java_io_RandomAccessFile* this, + java_bytearray* buffer, s4 start, s4 len) +{ + s4 o; + if (len == 0) + return; + o = threadedWrite (this->fd->fd, (char *) buffer->data+start, len); + if (o!=len) exceptionptr = native_new_and_init (class_java_io_IOException); +} + +s8 java_io_RandomAccessFile_getFilePointer + (struct java_io_RandomAccessFile* this) +{ + s4 p = lseek (this->fd->fd, 0, SEEK_CUR); + if (p>=0) return builtin_i2l(p); + exceptionptr = native_new_and_init (class_java_io_IOException); + return builtin_i2l(0); +} + +void java_io_RandomAccessFile_seek + (struct java_io_RandomAccessFile* this, s8 offset) +{ + s4 p = lseek (this->fd->fd, builtin_l2i(offset), SEEK_SET); + if (p<0) { + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + +s8 java_io_RandomAccessFile_length (struct java_io_RandomAccessFile* this) +{ + struct stat buffer; + s4 r = fstat(this->fd->fd, &buffer); + if (r>=0) return builtin_i2l(buffer.st_size); + exceptionptr = native_new_and_init (class_java_io_IOException); + return builtin_i2l(0); +} + +void java_io_RandomAccessFile_close (struct java_io_RandomAccessFile* this) +{ + if (this->fd->fd >= 0) { + s4 r = close (this->fd->fd); + this->fd->fd = -1; + if (r<0) + exceptionptr = native_new_and_init (class_java_io_IOException); + } +} + diff --git a/nat/lang.c b/nat/lang.c new file mode 100644 index 000000000..4561319f9 --- /dev/null +++ b/nat/lang.c @@ -0,0 +1,918 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** nat/lang.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the native functions for class java.lang. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/06/10 + +*******************************************************************************/ + +#include +#include +#include + +#include "../threads/thread.h" /* schani */ +#include "../threads/locks.h" + +static void use_class_as_object (classinfo *c) +{ + c->header.vftbl = class_java_lang_Class -> vftbl; +} + + +/************************************** java.lang.Object ***********************************/ + +struct java_lang_Class* java_lang_Object_getClass (struct java_lang_Object* this) +{ + classinfo *c = this->header.vftbl -> class; + use_class_as_object (c); + return (java_lang_Class*) c; +} + +s4 java_lang_Object_hashCode (struct java_lang_Object* this) +{ + return ((char*) this) - ((char*) 0); +} + + +struct java_lang_Object* java_lang_Object_clone (struct java_lang_Object* this) +{ + classinfo *c; + java_lang_Object *new; + + if (((java_objectheader*)this)->vftbl->class == class_array) + { + static u4 multiplicator[10]; + static int is_initialized = 0; + + java_arrayheader *array = (java_arrayheader*)this; + u4 size; + + if (!is_initialized) + { + multiplicator[ARRAYTYPE_INT] = sizeof(s4); + multiplicator[ARRAYTYPE_LONG] = sizeof(s8); + multiplicator[ARRAYTYPE_FLOAT] = sizeof(float); + multiplicator[ARRAYTYPE_DOUBLE] = sizeof(double); + multiplicator[ARRAYTYPE_BYTE] = sizeof(s1); + multiplicator[ARRAYTYPE_CHAR] = sizeof(u2); + multiplicator[ARRAYTYPE_SHORT] = sizeof(s2); + multiplicator[ARRAYTYPE_BOOLEAN] = sizeof(u1); + multiplicator[ARRAYTYPE_OBJECT] = sizeof(void*); + multiplicator[ARRAYTYPE_ARRAY] = sizeof(void*); + is_initialized = 1; + } + + size = sizeof(java_arrayheader) + + array->size * multiplicator[array->arraytype]; + + new = (java_lang_Object*)heap_allocate(size, false, NULL); + memcpy(new, this, size); + + return new; + } + else + { + if (! builtin_instanceof ((java_objectheader*) this, class_java_lang_Cloneable) ) { + exceptionptr = native_new_and_init (class_java_lang_CloneNotSupportedException); + return NULL; + } + + c = this -> header.vftbl -> class; + new = (java_lang_Object*) builtin_new (c); + if (!new) { + exceptionptr = proto_java_lang_OutOfMemoryError; + return NULL; + } + + memcpy (new, this, c->instancesize); + return new; + } +} + +void java_lang_Object_notify (struct java_lang_Object* this) +{ + if (runverbose) + log_text ("java_lang_Object_notify called"); + +#ifdef USE_THREADS + signal_cond_for_object(&this->header); +#endif +} + +void java_lang_Object_notifyAll (struct java_lang_Object* this) +{ + if (runverbose) + log_text ("java_lang_Object_notifyAll called"); + +#ifdef USE_THREADS + broadcast_cond_for_object(&this->header); +#endif +} + +void java_lang_Object_wait (struct java_lang_Object* this, s8 time) +{ + if (runverbose) + log_text ("java_lang_Object_wait called"); + +#ifdef USE_THREADS + wait_cond_for_object(&this->header, time); +#endif +} + + +/********************************** java.lang.Class **************************************/ + + +struct java_lang_Class* java_lang_Class_forName (struct java_lang_String* s) +{ + java_chararray *a,*b; + u4 i; + unicode *u; + classinfo *c; + + if (!s) return NULL; + if (!(a = s->value) ) return NULL; + b = builtin_newarray_char (s->count); + if (!b) return NULL; + for (i=0; icount; i++) { + if (a->data[s->offset+i]=='.') b->data[i] = '/'; + else b->data[i] = a->data[s->offset+i]; + } + u = unicode_new_u2 (b->data, b->header.size); + c = u->class; + if (!c) { + c = loader_load (u); + loader_initclasses (); + + if (!c) { + exceptionptr = + native_new_and_init (class_java_lang_ClassNotFoundException); + + return NULL; + } + + } + + use_class_as_object (c); + return (java_lang_Class*) c; +} + +struct java_lang_Object* java_lang_Class_newInstance (struct java_lang_Class* this) +{ + java_objectheader *o = native_new_and_init ((classinfo*) this); + if (!o) { + exceptionptr = + native_new_and_init (class_java_lang_InstantiationException); + } + return (java_lang_Object*) o; +} + +struct java_lang_String* java_lang_Class_getName (struct java_lang_Class* this) +{ + u4 i; + classinfo *c = (classinfo*) this; + java_lang_String *s = (java_lang_String*) javastring_new(c->name); + + if (!s) return NULL; + + for (i=0; ivalue->header.size; i++) { + if (s->value->data[i] == '/') s->value->data[i] = '.'; + } + + return s; +} + +struct java_lang_Class* java_lang_Class_getSuperclass (struct java_lang_Class* this) +{ + classinfo *c = ((classinfo*) this) -> super; + if (!c) return NULL; + + use_class_as_object (c); + return (java_lang_Class*) c; +} + +java_objectarray* java_lang_Class_getInterfaces (struct java_lang_Class* this) +{ + classinfo *c = (classinfo*) this; + u4 i; + java_objectarray *a = builtin_anewarray (c->interfacescount, class_java_lang_Class); + if (!a) return NULL; + for (i=0; iinterfacescount; i++) { + use_class_as_object (c->interfaces[i]); + + a->data[i] = (java_objectheader*) c->interfaces[i]; + } + return a; +} + +struct java_lang_ClassLoader* java_lang_Class_getClassLoader (struct java_lang_Class* this) +{ + log_text ("java_lang_Class_getClassLoader called"); + return NULL; +} + +s4 java_lang_Class_isInterface (struct java_lang_Class* this) +{ + classinfo *c = (classinfo*) this; + if (c->flags & ACC_INTERFACE) return 1; + return 0; +} + +/************************************ java.lang.ClassLoader *******************************/ + + +struct java_lang_Class* java_lang_ClassLoader_defineClass (struct java_lang_ClassLoader* this, java_bytearray* par1, s4 par2, s4 par3) +{ + log_text ("java_lang_ClassLoader_defineClass called"); + return NULL; +} +void java_lang_ClassLoader_resolveClass (struct java_lang_ClassLoader* this, struct java_lang_Class* par1) +{ + log_text ("java_lang_ClassLoader_resolveClass called"); +} +struct java_lang_Class* java_lang_ClassLoader_findSystemClass (struct java_lang_ClassLoader* this, struct java_lang_String* par1) +{ + log_text ("java_lang_ClassLoader_findSystemClass called"); + return NULL; +} +void java_lang_ClassLoader_init (struct java_lang_ClassLoader* this) +{ + log_text ("java_lang_ClassLoader_init called"); +} +struct java_lang_Class* java_lang_ClassLoader_findSystemClass0 (struct java_lang_ClassLoader* this, struct java_lang_String* par1) +{ + log_text ("java_lang_ClassLoader_findSystemClass0 called"); + return NULL; +} + +struct java_lang_Class* java_lang_ClassLoader_defineClass0 (struct java_lang_ClassLoader* this, java_bytearray* par1, s4 par2, s4 par3) +{ + log_text ("java_lang_ClassLoader_defineClass0 called"); + return NULL; +} +void java_lang_ClassLoader_resolveClass0 (struct java_lang_ClassLoader* this, struct java_lang_Class* par1) +{ + log_text ("java_lang_ClassLoader_resolveClass0 called"); + return; +} + +/************************************** java.lang.Compiler *******************************/ + +void java_lang_Compiler_initialize () +{ + log_text ("java_lang_Compiler_initialize called"); +} +s4 java_lang_Compiler_compileClass (struct java_lang_Class* par1) +{ + log_text ("java_lang_Compiler_compileClass called"); + return 0; +} +s4 java_lang_Compiler_compileClasses (struct java_lang_String* par1) +{ + log_text ("java_lang_Compiler_compileClasses called"); + return 0; +} +struct java_lang_Object* java_lang_Compiler_command (struct java_lang_Object* par1) +{ + log_text ("java_lang_Compiler_command called"); + return NULL; +} +void java_lang_Compiler_enable () +{ + log_text ("java_lang_Compiler_enable called"); +} +void java_lang_Compiler_disable () +{ + log_text ("java_lang_Compiler_disable called"); +} + + +/******************************** java.lang.Double **************************************/ + +struct java_lang_String* java_lang_Double_toString (double par1) +{ + char b[400]; + sprintf (b, "%-.6g", par1); + return (java_lang_String*) javastring_new_char (b); +} +struct java_lang_Double* java_lang_Double_valueOf (struct java_lang_String* par1) +{ + float val; + java_lang_Double *d = (java_lang_Double*) builtin_new (class_java_lang_Double); + if (d) { + sscanf (javastring_tochar((java_objectheader*) par1), "%f", &val); + d->value = val; + return d; + } + return NULL; +} +s8 java_lang_Double_doubleToLongBits (double par1) +{ + s8 l; + double d = par1; + memcpy ((u1*) &l, (u1*) &d, 8); + return l; +} +double java_lang_Double_longBitsToDouble (s8 par1) +{ + s8 l = par1; + double d; + memcpy ((u1*) &d, (u1*) &l, 8); + return d; +} + +/******************************** java.lang.Float ***************************************/ + +struct java_lang_String* java_lang_Float_toString (float par1) +{ + char b[50]; + sprintf (b, "%-.6g", (double) par1); + return (java_lang_String*) javastring_new_char (b); +} +struct java_lang_Float* java_lang_Float_valueOf (struct java_lang_String* par1) +{ + float val; + java_lang_Float *d = (java_lang_Float*) builtin_new (class_java_lang_Float); + if (d) { + sscanf (javastring_tochar((java_objectheader*) par1), "%f", &val); + d->value = val; + return d; + } + return NULL; +} +s4 java_lang_Float_floatToIntBits (float par1) +{ + s4 i; + float f = par1; + memcpy ((u1*) &i, (u1*) &f, 4); + return i; +} +float java_lang_Float_intBitsToFloat (s4 par1) +{ + s4 i = par1; + float f; + memcpy ((u1*) &f, (u1*) &i, 4); + return f; +} + + +/******************************** java.lang.Math ****************************************/ + +double java_lang_Math_sin (double par1) +{ + return sin(par1); +} + +double java_lang_Math_cos (double par1) +{ + return cos(par1); +} + +double java_lang_Math_tan (double par1) +{ + return tan(par1); +} + +double java_lang_Math_asin (double par1) +{ + return asin(par1); +} + +double java_lang_Math_acos (double par1) +{ + return acos(par1); +} + +double java_lang_Math_atan (double par1) +{ + return atan(par1); +} + +double java_lang_Math_exp (double par1) +{ + return exp(par1); +} + +double java_lang_Math_log (double par1) +{ + if (par1<0.0) { + exceptionptr = proto_java_lang_ArithmeticException; + return 0.0; + } + return log(par1); +} + +double java_lang_Math_sqrt (double par1) +{ + if (par1<0.0) { + exceptionptr = proto_java_lang_ArithmeticException; + return 0.0; + } + return sqrt(par1); +} + +static u8 dbl_nan = 0xffffffffffffffffL ; + +#define DBL_NAN (*((double*) (&dbl_nan))) + +double java_lang_Math_IEEEremainder (double a, double b) +{ + double d; + if (finite(a) && finite(b)) { + d = a / b; + if (finite(d)) + return a - floor(d) * b; + return DBL_NAN; + } + if (isnan(b)) + return DBL_NAN; + if (finite(a)) + return a; + return DBL_NAN; +} + +double java_lang_Math_ceil (double par1) +{ + return ceil(par1); +} + +double java_lang_Math_floor (double par1) +{ + return floor(par1); +} + +double java_lang_Math_rint (double par1) +{ + panic ("native Methode java_lang_rint not implemented yet"); + return 0.0; +} + +double java_lang_Math_atan2 (double par1, double par2) +{ + return atan2(par1,par2); +} + +double java_lang_Math_pow (double par1, double par2) +{ + return pow(par1,par2); +} + + +/******************************* java.lang.Runtime **************************************/ + +void java_lang_Runtime_exitInternal (struct java_lang_Runtime* this, s4 par1) +{ + cacao_shutdown (par1); +} +struct java_lang_Process* java_lang_Runtime_execInternal (struct java_lang_Runtime* this, java_objectarray* par1, java_objectarray* par2) +{ + log_text ("java_lang_Runtime_execInternal called"); + return NULL; +} +s8 java_lang_Runtime_freeMemory (struct java_lang_Runtime* this) +{ + log_text ("java_lang_Runtime_freeMemory called"); + return builtin_i2l (0); +} +s8 java_lang_Runtime_totalMemory (struct java_lang_Runtime* this) +{ + log_text ("java_lang_Runtime_totalMemory called"); + return builtin_i2l (0); +} +void java_lang_Runtime_gc (struct java_lang_Runtime* this) +{ + gc_call(); +} +void java_lang_Runtime_runFinalization (struct java_lang_Runtime* this) +{ + log_text ("java_lang_Runtime_runFinalization called"); +} +void java_lang_Runtime_traceInstructions (struct java_lang_Runtime* this, s4 par1) +{ + log_text ("java_lang_Runtime_traceInstructions called"); +} +void java_lang_Runtime_traceMethodCalls (struct java_lang_Runtime* this, s4 par1) +{ + log_text ("java_lang_Runtime_traceMethodCalls called"); +} +struct java_lang_String* java_lang_Runtime_initializeLinkerInternal (struct java_lang_Runtime* this) +{ + log_text ("java_lang_Runtime_initializeLinkerInternal called"); + return (java_lang_String*)javastring_new_char("."); +} +struct java_lang_String* java_lang_Runtime_buildLibName (struct java_lang_Runtime* this, struct java_lang_String* par1, struct java_lang_String* par2) +{ + log_text ("java_lang_Runtime_buildLibName called"); + return NULL; +} +s4 java_lang_Runtime_loadFileInternal (struct java_lang_Runtime* this, struct java_lang_String* par1) +{ + log_text ("java_lang_Runtime_loadFileInternal called"); + return 1; +} + + +/**************************************** java.lang.SecurityManager ***********************/ + +java_objectarray* java_lang_SecurityManager_getClassContext (struct java_lang_SecurityManager* this) +{ + log_text ("called: java_lang_SecurityManager_getClassContext"); + return NULL; +} +struct java_lang_ClassLoader* java_lang_SecurityManager_currentClassLoader (struct java_lang_SecurityManager* this) +{ + log_text ("called: java_lang_SecurityManager_currentClassLoader"); + return NULL; +} +s4 java_lang_SecurityManager_classDepth (struct java_lang_SecurityManager* this, struct java_lang_String* par1) +{ + log_text ("called: java_lang_SecurityManager_classDepth"); + return 0; +} +s4 java_lang_SecurityManager_classLoaderDepth (struct java_lang_SecurityManager* this) +{ + log_text ("called: java_lang_SecurityManager_classLoaderDepth"); + return 0; +} + + + +/*********************************** java.lang.System ************************************/ + +s8 java_lang_System_currentTimeMillis () +{ + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + return ((s8) tv.tv_sec) * 1000 + tv.tv_usec / 1000; +} + + +void java_lang_System_arraycopy (struct java_lang_Object* source, s4 sp, + struct java_lang_Object* dest, s4 dp, s4 len) +{ + s4 i; + java_arrayheader *s = (java_arrayheader*) source; + java_arrayheader *d = (java_arrayheader*) dest; + + if ( (!s) || (!d) ) { + exceptionptr = proto_java_lang_NullPointerException; + return; + } + if ( (s->objheader.vftbl->class != class_array) || (d->objheader.vftbl->class != class_array) ) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + + if (s->arraytype != d->arraytype) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + + if ((sp<0) || (sp+len > s->size) || (dp<0) || (dp+len > d->size)) { + exceptionptr = proto_java_lang_ArrayIndexOutOfBoundsException; + return; + } + + switch (s->arraytype) { + case ARRAYTYPE_BYTE: + { + java_bytearray *bas = (java_bytearray*) s; + java_bytearray *bad = (java_bytearray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = bas->data[sp+i]; + else + for (i=len-1; i>=0; i--) bad->data[dp+i] = bas->data[sp+i]; + } + break; + case ARRAYTYPE_BOOLEAN: + { + java_booleanarray *bas = (java_booleanarray*) s; + java_booleanarray *bad = (java_booleanarray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = bas->data[sp+i]; + else + for (i=len-1; i>=0; i--) bad->data[dp+i] = bas->data[sp+i]; + } + break; + case ARRAYTYPE_CHAR: + { + java_chararray *cas = (java_chararray*) s; + java_chararray *cad = (java_chararray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = cas->data[sp+i]; + else + for (i=len-1; i>=0; i--) cad->data[dp+i] = cas->data[sp+i]; + } + break; + case ARRAYTYPE_SHORT: + { + java_shortarray *sas = (java_shortarray*) s; + java_shortarray *sad = (java_shortarray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = sas->data[sp+i]; + else + for (i=len-1; i>=0; i--) sad->data[dp+i] = sas->data[sp+i]; + } + break; + case ARRAYTYPE_INT: + { + java_intarray *ias = (java_intarray*) s; + java_intarray *iad = (java_intarray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = ias->data[sp+i]; + else + for (i=len-1; i>=0; i--) iad->data[dp+i] = ias->data[sp+i]; + } + break; + case ARRAYTYPE_LONG: + { + java_longarray *las = (java_longarray*) s; + java_longarray *lad = (java_longarray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = las->data[sp+i]; + else + for (i=len-1; i>=0; i--) lad->data[dp+i] = las->data[sp+i]; + } + break; + case ARRAYTYPE_FLOAT: + { + java_floatarray *fas = (java_floatarray*) s; + java_floatarray *fad = (java_floatarray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = fas->data[sp+i]; + else + for (i=len-1; i>=0; i--) fad->data[dp+i] = fas->data[sp+i]; + } + break; + case ARRAYTYPE_DOUBLE: + { + java_doublearray *das = (java_doublearray*) s; + java_doublearray *dad = (java_doublearray*) d; + if (dp<=sp) + for (i=0; idata[dp+i] = das->data[sp+i]; + else + for (i=len-1; i>=0; i--) dad->data[dp+i] = das->data[sp+i]; + } + break; + case ARRAYTYPE_OBJECT: + { + java_objectarray *oas = (java_objectarray*) s; + java_objectarray *oad = (java_objectarray*) d; + if (dp<=sp) + for (i=0; idata[sp+i]; + if (!builtin_canstore(oad, o)) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + oad->data[dp+i] = o; + } + else + for (i=len-1; i>=0; i--) { + java_objectheader *o = oas->data[sp+i]; + if (!builtin_canstore(oad, o)) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + oad->data[dp+i] = o; + } + + } + break; + case ARRAYTYPE_ARRAY: + { + java_arrayarray *aas = (java_arrayarray*) s; + java_arrayarray *aad = (java_arrayarray*) d; + if (dp<=sp) + for (i=0; idata[sp+i]; + if (!builtin_canstore( (java_objectarray*)aad, + (java_objectheader*)o )) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + aad->data[dp+i] = o; + } + else + for (i=len-1; i>=0; i--) { + java_arrayheader *o = aas->data[sp+i]; + if (!builtin_canstore( (java_objectarray*)aad, + (java_objectheader*)o )) { + exceptionptr = proto_java_lang_ArrayStoreException; + return; + } + aad->data[dp+i] = o; + } + + } + break; + + default: + panic ("Unknown data type for arraycopy"); + } + +} + + +#define MAXPROPS 100 +static int activeprops = 15; + +static char *proplist[MAXPROPS][2] = { + { "java.class.path", NULL }, + { "java.home", NULL }, + { "user.home", NULL }, + { "user.name", NULL }, + { "user.dir", NULL }, + + { "java.class.version", "45.3" }, + { "java.version", "cacao:0.2" }, + { "java.vendor", "CACAO Team" }, + { "java.vendor.url", "http://www.complang.tuwien.ac.at/java/cacao/" }, + { "os.arch", "Alpha" }, + { "os.name", "Linux/Digital Unix" }, + { "os.version", "4.0/3.2C/V4.0" }, + { "path.separator", ":" }, + { "file.separator", "/" }, + { "line.separator", "\n" } +}; + +void attach_property (char *name, char *value) +{ + if (activeprops >= MAXPROPS) panic ("Too many properties defined"); + proplist[activeprops][0] = name; + proplist[activeprops][1] = value; + activeprops++; +} + + +struct java_util_Properties* java_lang_System_initProperties (struct java_util_Properties* p) +{ + u4 i; + methodinfo *m; +#define BUFFERSIZE 200 + char buffer[BUFFERSIZE]; + + proplist[0][1] = classpath; + proplist[1][1] = getenv("JAVAHOME"); + proplist[2][1] = getenv("HOME"); + proplist[3][1] = getenv("USER"); + proplist[4][1] = getcwd(buffer,BUFFERSIZE); + + if (!p) panic ("initProperties called with NULL-Argument"); + + m = class_resolvemethod ( + p->header.vftbl->class, + unicode_new_char ("put"), + unicode_new_char ("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") + ); + if (!m) panic ("Can not find method 'put' for class Properties"); + + for (i=0; i detailMessage = + (java_lang_String*) (javastring_new_char ("no backtrace info!") ); + return this; +} + diff --git a/nat/util.c b/nat/util.c new file mode 100644 index 000000000..968496c61 --- /dev/null +++ b/nat/util.c @@ -0,0 +1,121 @@ +/***************************** nat/util.c ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the native functions for class java.util. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + +#include + +/**************************** java.util.Date **********************************/ + + +struct java_lang_String* java_util_Date_toString + (struct java_util_Date* this) +{ + time_t tt; + char *buffer; + int l; + + if (!this->valueValid) java_util_Date_computeValue(this); + tt = builtin_l2i ( builtin_ldiv(this->value, builtin_i2l(1000) ) ); + + buffer = ctime (&tt); + l = strlen(buffer); + while (l>1 && buffer[l-1]=='\n') l--; + buffer[l] = '\0'; + + return (java_lang_String*) javastring_new_char( buffer ); +} + + +struct java_lang_String* java_util_Date_toLocaleString + (struct java_util_Date* this) +{ + time_t tt; + char *buffer; + int l; + + if (!this->valueValid) java_util_Date_computeValue(this); + tt = builtin_l2i ( builtin_ldiv(this->value, builtin_i2l(1000) ) ); + + buffer = asctime (localtime(&tt)); + l = strlen(buffer); + while (l>1 && buffer[l-1]=='\n') l--; + buffer[l] = '\0'; + + return (java_lang_String*) javastring_new_char ( buffer ); +} + +struct java_lang_String* java_util_Date_toGMTString + (struct java_util_Date* this) +{ + time_t tt; + char *buffer; + int l; + + if (!this->valueValid) java_util_Date_computeValue(this); + tt = builtin_l2i ( builtin_ldiv(this->value, builtin_i2l(1000) ) ); + + buffer = asctime (gmtime(&tt)); + l = strlen(buffer); + while (l>1 && buffer[l-1]=='\n') l--; + buffer[l] = '\0'; + + + return (java_lang_String*) javastring_new_char ( buffer ); +} + + + +void java_util_Date_expand (struct java_util_Date* this) +{ + struct tm *t; + time_t tt; + + if (this->expanded) return; + + tt = builtin_l2i ( builtin_ldiv(this->value, builtin_i2l(1000) ) ); + t = gmtime (&tt); + this->tm_millis = + builtin_l2i( builtin_lrem (this->value, builtin_i2l(1000) ) ); + this->tm_sec = t->tm_sec; + this->tm_min = t->tm_min; + this->tm_hour = t->tm_hour; + this->tm_mday = t->tm_mday; + this->tm_mon = t->tm_mon; + this->tm_wday = t->tm_wday; + this->tm_yday = t->tm_yday; + this->tm_year = t->tm_year; + this->tm_isdst = t->tm_isdst; + this->expanded = 1; +} + +void java_util_Date_computeValue (struct java_util_Date* this) +{ + struct tm t; + + if (this->valueValid) return; + t.tm_sec = this->tm_sec; + t.tm_min = this->tm_min; + t.tm_hour = this->tm_hour; + t.tm_mday = this->tm_mday; + t.tm_mon = this->tm_mon; + t.tm_wday = this->tm_wday; + t.tm_yday = this->tm_yday; + t.tm_year = this->tm_year; + t.tm_isdst = this->tm_isdst; + this->value = + builtin_ladd( + builtin_lmul( builtin_i2l(mktime(&t)), builtin_i2l(1000)), + builtin_i2l(this->tm_millis) + ); + this->valueValid = 1; +} diff --git a/native.c b/native.c new file mode 100644 index 000000000..771ec5406 --- /dev/null +++ b/native.c @@ -0,0 +1,340 @@ +/****************************** native.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt die Tabellen f"ur die native-methods. + Die vom Headerfile-Generator erzeugten -.hh - Dateien werden hier + eingebunden, und ebenso alle C-Funktionen, mit denen diese + Methoden implementiert werden. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + +#include +#include + + +#include "global.h" +#include "native.h" + +#include "builtin.h" +#include "nativetypes.hh" +#include "asmpart.h" +#include "tables.h" +#include "loader.h" + + +java_objectheader* exceptionptr = NULL; + + + +static char *classpath; + + +/******************** die f"r die native-Methoden n"otigen Systemklassen *****/ + +static classinfo *class_java_lang_Class; +static classinfo *class_java_lang_Cloneable; +static classinfo *class_java_lang_CloneNotSupportedException; +static classinfo *class_java_lang_Double; +static classinfo *class_java_lang_Float; +static classinfo *class_java_io_IOException; +static classinfo *class_java_lang_ClassNotFoundException; +static classinfo *class_java_lang_InstantiationException; + + + +/************************** alle Funktionen einbinden ************************/ + +#include "nat/lang.c" +#include "nat/io.c" +#include "nat/util.c" + + +/********************** Tabellen f"ur die Methoden ***************************/ + +static struct nativeref { + char *classname; + char *methodname; + char *descriptor; + bool isstatic; + functionptr func; +} nativetable [] = { + +#include "nativetable.hh" + +}; + + +#define NATIVETABLESIZE (sizeof(nativetable)/sizeof(struct nativeref)) + +static struct nativecompref { + unicode *classname; + unicode *methodname; + unicode *descriptor; + bool isstatic; + functionptr func; + } nativecomptable [NATIVETABLESIZE]; + +static bool nativecompdone = false; + + +/*********************** Funktion: native_loadclasses ************************** + + L"adt alle Klassen, die die native Methoden zus"atzlich ben"otigen + +*******************************************************************************/ + +void native_loadclasses() +{ + class_java_lang_Cloneable = + loader_load ( unicode_new_char ("java/lang/Cloneable") ); + class_java_lang_CloneNotSupportedException = + loader_load ( unicode_new_char ("java/lang/CloneNotSupportedException") ); + class_java_lang_Class = + loader_load ( unicode_new_char ("java/lang/Class") ); + class_java_lang_Double = + loader_load ( unicode_new_char ("java/lang/Double") ); + class_java_lang_Float = + loader_load ( unicode_new_char ("java/lang/Float") ); + class_java_io_IOException = + loader_load ( unicode_new_char ("java/io/IOException") ); + class_java_lang_ClassNotFoundException = + loader_load ( unicode_new_char ("java/lang/ClassNotFoundException") ); + class_java_lang_InstantiationException= + loader_load ( unicode_new_char ("java/lang/InstantiationException") ); + +} + +/********************* Funktion: native_setclasspath ***************************/ + +void native_setclasspath (char *path) +{ + classpath = path; +} + + +/*********************** Funktion: native_findfunction ************************ + + Sucht in der Tabelle die passende Methode (muss mit Klassennamen, + Methodennamen, Descriptor und 'static'-Status "ubereinstimmen), + und gibt den Funktionszeiger darauf zur"uck. + Return: Funktionszeiger oder NULL (wenn es keine solche Methode gibt) + + Anmerkung: Zu Beschleunigung des Suchens werden die als C-Strings + vorliegenden Namen/Descriptors in entsprechende unicode-Symbole + umgewandelt (beim ersten Aufruf dieser Funktion). + +*******************************************************************************/ + +functionptr native_findfunction (unicode *cname, unicode *mname, + unicode *desc, bool isstatic) +{ + u4 i; + struct nativecompref *n; + + isstatic = isstatic ? true : false; + + if (!nativecompdone) { + for (i=0; iclassname && mname==n->methodname && + desc==n->descriptor && isstatic==n->isstatic) return n->func; + } + + return NULL; +} + + +/********************** Funktion: javastring_new ***************************** + + Legt ein neues Objekt vom Typ java/lang/String an, und tr"agt als Text + das "ubergebene unicode-Symbol ein. + Return: Zeiger auf den String, oder NULL (wenn Speicher aus) + +*****************************************************************************/ + +java_objectheader *javastring_new (unicode *text) +{ + u4 i; + java_lang_String *s; + java_chararray *a; + + s = (java_lang_String*) builtin_new (class_java_lang_String); + a = builtin_newarray_char (text->length); + + if ( (!a) || (!s) ) return NULL; + + for (i=0; ilength; i++) a->data[i] = text->text[i]; + s -> value = a; + s -> offset = 0; + s -> count = text->length; + + return (java_objectheader*) s; +} + + +/********************** Funktion: javastring_new_char ************************ + + Legt ein neues Objekt vom Typ java/lang/String an, und tr"agt als Text + den "ubergebenen C-String ein. + Return: Zeiger auf den String, oder NULL (wenn Speicher aus) + +*****************************************************************************/ + +java_objectheader *javastring_new_char (char *text) +{ + u4 i; + u4 len = strlen(text); + java_lang_String *s; + java_chararray *a; + + s = (java_lang_String*) builtin_new (class_java_lang_String); + a = builtin_newarray_char (len); + + if ( (!a) || (!s) ) return NULL; + + for (i=0; idata[i] = text[i]; + s -> value = a; + s -> offset = 0; + s -> count = len; + + return (java_objectheader*) s; +} + + +/************************* Funktion: javastring_tochar ***************************** + + Macht aus einem java-string einen C-String, und liefert den Zeiger + darauf zur"uck. + Achtung: Beim n"achsten Aufruf der Funktion wird der vorige String + "uberschrieben + +***********************************************************************************/ + +#define MAXSTRINGSIZE 1000 +char stringbuffer[MAXSTRINGSIZE]; + +char *javastring_tochar (java_objectheader *so) +{ + java_lang_String *s = (java_lang_String*) so; + java_chararray *a; + u4 i; + + if (!s) return ""; + a = s->value; + if (!a) return ""; + if (s->count > MAXSTRINGSIZE) return ""; + for (i=0; icount; i++) stringbuffer[i] = a->data[s->offset+i]; + stringbuffer[i] = '\0'; + return stringbuffer; +} + + +/******************** Funktion: native_new_and_init ************************* + + Legt ein neues Objekt einer Klasse am Heap an, und ruft automatisch + die Initialisierungsmethode auf. + Return: Der Zeiger auf das Objekt, oder NULL, wenn kein Speicher + mehr frei ist. + +*****************************************************************************/ + +java_objectheader *native_new_and_init (classinfo *c) +{ + methodinfo *m; + java_objectheader *o = builtin_new (c); + + if (!o) return NULL; + + m = class_findmethod (c, + unicode_new_char (""), + unicode_new_char ("()V")); + if (!m) { + log_text ("warning: class has no instance-initializer:"); + unicode_sprint (logtext, c->name); + dolog(); + return o; + } + + asm_calljavamethod (m, o,NULL,NULL,NULL); + return o; +} + + +/********************* Funktion: literalstring_new **************************** + + erzeugt einen Java-String mit dem angegebenen Text, allerdings nicht + auf dem HEAP, sondern in einem anderen Speicherbereich (der String + muss dann sp"ater explizit wieder freigegeben werden). + Alle Strings, die auf diese Art erzeugt werden, werden in einer + gemeinsamen Struktur gespeichert (n"amlich auch "uber die + Unicode-Hashtabelle), sodass identische Strings auch wirklich den + gleichen Zeiger liefern. + +******************************************************************************/ + +java_objectheader *literalstring_new (unicode *text) +{ + u4 i; + java_lang_String *s; + java_chararray *a; + + if (text->string) return text->string; + + a = lit_mem_alloc (sizeof(java_chararray) + sizeof(u2)*(text->length-1) ); + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = text->length; + a -> header.arraytype = ARRAYTYPE_CHAR; + for (i=0; ilength; i++) a->data[i] = text->text[i]; + + s = LNEW (java_lang_String); + s -> header.vftbl = class_java_lang_String -> vftbl; + s -> value = a; + s -> offset = 0; + s -> count = text->length; + + unicode_setstringlink (text, (java_objectheader*) s); + return (java_objectheader*) s; +} + + +/********************** Funktion: literalstring_free ************************** + + L"oscht einen Java-String wieder aus dem Speicher (wird zu Systemende + vom Hashtabellen-Verwalter aufgerufen) + +******************************************************************************/ + +void literalstring_free (java_objectheader* sobj) +{ + java_lang_String *s = (java_lang_String*) sobj; + java_chararray *a = s->value; + + LFREE (s, java_lang_String); + LFREE (a, sizeof(java_chararray) + sizeof(u2)*(a->header.size-1)); +} + + + diff --git a/native.h b/native.h new file mode 100644 index 000000000..c484642b4 --- /dev/null +++ b/native.h @@ -0,0 +1,35 @@ +/****************************** native.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the codegenerator for an Alpha processor. + This module generates Alpha machine code for a sequence of + pseudo commands (PCMDs). + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/03/12 + +*******************************************************************************/ + + +extern java_objectheader* exceptionptr; + +void native_loadclasses (); +void native_setclasspath (char *path); + +functionptr native_findfunction (unicode *cname, unicode *mname, + unicode *desc, bool isstatic); + +java_objectheader *javastring_new (unicode *text); +java_objectheader *javastring_new_char (char *text); +char *javastring_tochar (java_objectheader *s); + +java_objectheader *native_new_and_init (classinfo *c); + +java_objectheader *literalstring_new (unicode *text); +void literalstring_free (java_objectheader*); + +void attach_property(char *name, char *value); diff --git a/ncomp/mcode.c b/ncomp/mcode.c new file mode 100644 index 000000000..11fc9a6b6 --- /dev/null +++ b/ncomp/mcode.c @@ -0,0 +1,331 @@ +/***************************** comp/mcode.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + This file is an include file for "compiler.c" . It contains (mostly) + architecture independent functions for writing instructions into the + code area and constants into the data area. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Changes: Micheal Gschwind EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/08/10 + + + All functions assume the following code area / data area layout: + + +-----------+ + | | + | code area | code area grows to higher addresses + | | + +-----------+ <-- start of procedure + | | + | data area | data area grows to lower addresses + | | + +-----------+ + + The functions first write into a temporary code/data area allocated by + "mcode_init". "mcode_finish" copies the code and data area into permanent + memory. All functions writing values into the data area return the offset + relative the begin of the code area (start of procedure). + +*******************************************************************************/ + +#define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */ +#define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */ + +static u1* mcodebase = NULL; /* base pointer of code area */ +static s4* mcodeend = NULL; /* pointer to end of code area */ +static int mcodesize; /* complete size of code area (bytes) */ + +static u1* dsegtop = NULL; /* pointer to top (end) of data area */ +static int dsegsize; /* complete size of data area (bytes) */ +static int dseglen; /* used size of data area (bytes) */ + /* data area grows from top to bottom */ + +static jumpref *jumpreferences; /* list of jumptable target addresses */ +static branchref *xboundrefs; /* list of bound check branches */ +static branchref *xcheckarefs; /* list of array size check branches */ +static branchref *xnullrefs; /* list of null check branches */ + +static void mcode_init(); /* allocates code and data area */ +static void mcode_close(); /* releases temporary storage */ +static void mcode_finish(); /* makes code and data area permanent and */ + /* updates branch references to code/data */ + +static s4 dseg_adds4(s4 value); /* adds an int to data area */ +static s4 dseg_adds8(s8 value); /* adds an long to data area */ +static s4 dseg_addfloat (float value); /* adds an float to data area */ +static s4 dseg_adddouble(double value); /* adds an double to data area */ + +#if POINTERSIZE==8 +#define dseg_addaddress(value) dseg_adds8((s8)(value)) +#else +#define dseg_addaddress(value) dseg_adds4((s4)(value)) +#endif + +static void dseg_addtarget(basicblock *target); +static void mcode_addreference(basicblock *target, void *branchptr); +static void mcode_addxboundrefs(void *branchptr); +static void mcode_addxnullrefs(void *branchptr); + +static void dseg_display(s4 *s4ptr); + +/* mcode_init allocates and initialises code area, data area and references */ + +static void mcode_init() +{ + if (!mcodebase) { + mcodebase = MNEW (u1, MCODEINITSIZE); + mcodesize = MCODEINITSIZE; + } + + if (!dsegtop) { + dsegtop = MNEW (u1, DSEGINITSIZE); + dsegsize = DSEGINITSIZE; + dsegtop += dsegsize; + } + + dseglen = 0; + + jumpreferences = NULL; + xboundrefs = NULL; + xnullrefs = NULL; +} + + +/* mcode_close releases temporary code and data area */ + +static void mcode_close() +{ + if (mcodebase) { + MFREE (mcodebase, u1, mcodesize); + mcodebase = NULL; + } + if (dsegtop) { + MFREE (dsegtop - dsegsize, u1, dsegsize); + dsegtop = NULL; + } +} + + +/* mcode_increase doubles code area */ + +static s4 *mcode_increase(u1 *codeptr) +{ + long len; + + len = codeptr - mcodebase; + mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2); + mcodesize *= 2; + mcodeend = (s4*) (mcodebase + mcodesize); + return (s4*) (mcodebase + len); +} + + +/* desg_increase doubles data area */ + +static void dseg_increase() { + u1 *newstorage = MNEW (u1, dsegsize * 2); + memcpy ( newstorage + dsegsize, dsegtop - dsegsize, dsegsize); + MFREE (dsegtop - dsegsize, u1, dsegsize); + dsegtop = newstorage; + dsegsize *= 2; + dsegtop += dsegsize; +} + + +static s4 dseg_adds4_increase(s4 value) +{ + dseg_increase(); + *((s4 *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adds4(s4 value) +{ + s4 *dataptr; + + dseglen += 4; + dataptr = (s4 *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adds4_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_adds8_increase(s8 value) +{ + dseg_increase(); + *((s8 *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adds8(s8 value) +{ + s8 *dataptr; + + dseglen = ALIGN (dseglen + 8, 8); + dataptr = (s8 *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adds8_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_addfloat_increase(float value) +{ + dseg_increase(); + *((float *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_addfloat(float value) +{ + float *dataptr; + + dseglen += 4; + dataptr = (float *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_addfloat_increase(value); + *dataptr = value; + return -dseglen; +} + + +static s4 dseg_adddouble_increase(double value) +{ + dseg_increase(); + *((double *) (dsegtop - dseglen)) = value; + return -dseglen; +} + + +static s4 dseg_adddouble(double value) +{ + double *dataptr; + + dseglen = ALIGN (dseglen + 8, 8); + dataptr = (double *) (dsegtop - dseglen); + if (dseglen > dsegsize) + return dseg_adddouble_increase(value); + *dataptr = value; + return -dseglen; +} + + +static void dseg_addtarget(basicblock *target) +{ + jumpref *jr = DNEW(jumpref); + + jr->tablepos = dseg_addaddress(NULL); + jr->target = target; + jr->next = jumpreferences; + jumpreferences = jr; +} + + +static void mcode_addreference(basicblock *target, void *branchptr) +{ + s4 branchpos = (u1*) branchptr - mcodebase; + + if (target->mpc >= 0) { + gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc); + } + else { + branchref *br = DNEW(branchref); + + br->branchpos = branchpos; + br->next = target->branchrefs; + target->branchrefs= br; + } +} + + +static void mcode_addxboundrefs(void *branchptr) +{ + s4 branchpos = (u1*) branchptr - mcodebase; + + branchref *br = DNEW(branchref); + + br->branchpos = branchpos; + br->next = xboundrefs; + xboundrefs = br; +} + + +static void mcode_addxcheckarefs(void *branchptr) +{ + s4 branchpos = (u1*) branchptr - mcodebase; + + branchref *br = DNEW(branchref); + + br->branchpos = branchpos; + br->next = xcheckarefs; + xcheckarefs = br; +} + + +static void mcode_addxnullrefs(void *branchptr) +{ + s4 branchpos = (u1*) branchptr - mcodebase; + + branchref *br = DNEW(branchref); + + br->branchpos = branchpos; + br->next = xnullrefs; + xnullrefs = br; +} + + +static void mcode_finish(int mcodelen) +{ + jumpref *jr; + u1 *epoint; + + count_code_len += mcodelen; + count_data_len += dseglen; + + dseglen = ALIGN(dseglen, MAX_ALIGN); + + method -> mcodelength = mcodelen + dseglen; + method -> mcode = CNEW(u1, mcodelen + dseglen); + + memcpy ( method->mcode, dsegtop - dseglen, dseglen); + memcpy ( method->mcode + dseglen, mcodebase, mcodelen); + + method -> entrypoint = epoint = (u1*) (method->mcode + dseglen); + + /* jump table resolving */ + + jr = jumpreferences; + while (jr != NULL) { + *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc; + jr = jr->next; + } + +#ifdef CACHE_FLUSH_BLOCK + synchronize_caches(method->mcode, (mcodelen>>2)); +#endif + +} + + +static void dseg_display(s4 *s4ptr) +{ + int i; + + printf(" --- dump of datasegment\n"); + for (i = dseglen; i > 0 ; i -= 4) { + printf("-%6x: %8x\n", i, (int)(*s4ptr++)); + } + printf(" --- begin of data segment: %p\n", s4ptr); +} diff --git a/ncomp/nblock.c b/ncomp/nblock.c new file mode 100644 index 000000000..cae3347fe --- /dev/null +++ b/ncomp/nblock.c @@ -0,0 +1,87 @@ +/***************************** ncomp/nblock.c ********************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Basic block handling functions. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/05 + +*******************************************************************************/ + + +/******************** function determine_basic_blocks ************************** + + Scans the JavaVM code of a method and marks each instruction which is the + start of a basic block. + +*******************************************************************************/ + +static void allocate_literals() +{ + int p, nextp; + int opcode, i; + + p = 0; + while (p < jcodelength) { + + opcode = jcode[p]; + nextp = p + jcommandsize[opcode]; + + switch (opcode) { + case JAVA_WIDE: + switch (code_get_u1(p + 1)) { + case JAVA_RET: nextp = p + 4; + break; + case JAVA_IINC: nextp = p + 6; + break; + default: nextp = p + 4; + break; + } + break; + + case JAVA_LOOKUPSWITCH: + { + s4 num; + + nextp = ALIGN((p + 1), 4); + num = code_get_u4(nextp + 4); + nextp = nextp + 8 + 8 * num; + break; + } + + case JAVA_TABLESWITCH: + { + s4 num; + + nextp = ALIGN ((p + 1),4); + num = code_get_s4(nextp + 4); + num = code_get_s4(nextp + 8) - num; + nextp = nextp + 16 + 4 * num; + break; + } + + case JAVA_LDC1: + i = code_get_u1(p+1); + goto pushconstantitem; + case JAVA_LDC2: + case JAVA_LDC2W: + i = code_get_u2(p + 1); + pushconstantitem: + if (class_constanttype(class, i) == CONSTANT_String) { + unicode *s; + s = class_getconstant(class, i, CONSTANT_String); + (void) literalstring_new(s); + } + break; + } /* end switch */ + + p = nextp; + + } /* end while */ + +} diff --git a/ncomp/ncomp.h b/ncomp/ncomp.h new file mode 100644 index 000000000..e8fe1cd9c --- /dev/null +++ b/ncomp/ncomp.h @@ -0,0 +1,93 @@ +/****************************** ncomp.h **************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + new compiler header file for inclusion in other moduls. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/05 + +*******************************************************************************/ + +/************** compiler switches (are set by main function) ******************/ + +extern bool runverbose; /* Das Programm soll w"arend des Laufs alle + Methodenaufrufe mitprotokollieren */ +extern bool compileverbose; /* Der Compiler soll sagen, was er macht */ +extern bool showstack; /* Alle Stackzust"ande ausgeben */ +extern bool showdisassemble; /* Disassemblerlisting ausgeben */ +extern bool showintermediate; /* Zwischencode ausgeben */ +extern int optimizelevel; /* Optimierungsstufe (0=keine) */ + +extern bool checkbounds; /* Arraygrenzen "uberpr"ufen */ +extern bool checknull; /* auf Null-Pointer "uberpr"ufen */ +extern bool checkfloats; /* Fehler bei Fliesskommas abfangen */ +extern bool checksync; /* Thread-Synchronisation wirklich machen */ + +extern bool getcompilingtime; +extern long compilingtime; /* CPU-Zeit f"urs "Ubersetzen */ + +extern int has_ext_instr_set; /* has instruction set extensions */ + + +extern int count_jit_calls; +extern int count_methods; +extern int count_spills; +extern int count_pcmd_activ; +extern int count_pcmd_drop; +extern int count_pcmd_zero; +extern int count_pcmd_const_store; +extern int count_pcmd_const_alu; +extern int count_pcmd_const_bra; +extern int count_pcmd_load; +extern int count_pcmd_move; +extern int count_load_instruction; +extern int count_pcmd_store; +extern int count_pcmd_store_comb; +extern int count_dup_instruction; +extern int count_pcmd_op; +extern int count_pcmd_mem; +extern int count_pcmd_met; +extern int count_pcmd_bra; +extern int count_pcmd_table; +extern int count_pcmd_return; +extern int count_pcmd_returnx; +extern int count_max_basic_blocks; +extern int count_basic_blocks; +extern int count_max_javainstr; +extern int count_javainstr; +extern int count_javacodesize; +extern int count_javaexcsize; +extern int count_calls; +extern int count_tryblocks; +extern int count_code_len; +extern int count_data_len; +extern int count_cstub_len; +extern int count_nstub_len; +extern int count_max_new_stack; +extern int count_upper_bound_new_stack; +extern int *count_block_stack; +extern int *count_analyse_iterations; +extern int *count_method_bb_distribution; +extern int *count_block_size_distribution; +extern int *count_store_length; +extern int *count_store_depth; + +/******************************* prototypes ***********************************/ + +methodptr new_compile (methodinfo *m); /* compile a method with new compiler */ + +void ncomp_init(); /* compiler initialisation */ +void ncomp_close(); /* compiler finalisation */ + +/* +u1 *createcompilerstub (methodinfo *m); +u1 *createnativestub (functionptr f, methodinfo *m); + +void removecompilerstub (u1 *stub); +void removenativestub (u1 *stub); +*/ diff --git a/ncomp/ncompdef.h b/ncomp/ncompdef.h new file mode 100644 index 000000000..c44953f4d --- /dev/null +++ b/ncomp/ncompdef.h @@ -0,0 +1,1103 @@ +/******************************* ncomp/compdef.h ******************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + defines all the constants and data structures of the compiler + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Michael Gschwind EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/05 + +*******************************************************************************/ + +#include "../sysdep/types.h" + +/**************************** resolve typedef-cycles **************************/ + +typedef struct stackelement stackelement; +typedef stackelement *stackptr; +typedef struct basicblock basicblock; +typedef struct instruction instruction; +typedef struct subroutineinfo subroutineinfo; +typedef struct varinfo varinfo; +typedef struct branchref branchref; +typedef struct jumpref jumpref; +typedef varinfo *varinfoptr; + + +/************************** stack element structure ***************************/ + +/* slot types */ + +#define TYPE_INT 0 /* the stack slot types must numbered in the */ +#define TYPE_LNG 1 /* same order as the ICMD_Ixxx to ICMD_Axxx */ +#define TYPE_FLT 2 /* instructions (LOAD and STORE) */ +#define TYPE_DBL 3 /* integer, long, float, double, address */ +#define TYPE_ADR 4 + +#define IS_INT_LNG_TYPE(a) (!((a)&TYPE_FLT)) +#define IS_FLT_DBL_TYPE(a) ((a)&TYPE_FLT) +#define IS_2_WORD_TYPE(a) ((a)&TYPE_LNG) + + +/* flags */ + +#define SAVEDVAR 1 /* variable has to survive method invocations */ +#define INMEMORY 2 /* variable stored in memory */ + +/* variable types */ + +#define UNDEFVAR 0 /* stack slot will become temp during regalloc*/ +#define TEMPVAR 1 /* stack slot is temp register */ +#define STACKVAR 2 /* stack slot is numbered stack slot */ +#define LOCALVAR 3 /* stack slot is local variable */ +#define ARGVAR 4 /* stack slot is argument variable */ + +struct stackelement { + stackptr prev; /* pointer to next element towards bottom */ + int type; /* data type of stack element */ + int flags; /* flags (SAVED, INMEMORY) */ + int varkind; /* kind of variable or register */ + int varnum; /* number of variable */ + int regoff; /* register number or memory offset */ + }; + + +/**************************** instruction structure ***************************/ + +struct instruction { + stackptr dst; /* stack index of destination operand stack */ + u2 opc; /* opcode of intermediate code command */ + s4 op1; /* first operand, usually variable number */ + + union { + s4 i; /* integer operand */ + s8 l; /* long operand */ + float f; /* float operand */ + double d; /* double operand */ + void *a; /* address operand */ + } val; /* immediate constant */ + }; + + +/**************************** basic block structure ***************************/ + +/* flags */ + +#define BBUNDEF -1 +#define BBREACHED 0 +#define BBFINISHED 1 + +#define BBTYPE_STD 0 /* standard basic block type */ +#define BBTYPE_EXH 1 /* exception handler basic block type */ +#define BBTYPE_SBR 2 /* subroutine basic block type */ + +struct basicblock { + int flags; /* used during stack analysis, init with -1 */ + int type; /* basic block type (std, xhandler, subroutine*/ + int ipc; /* intermediate code pc at start of block */ + int mpc; /* machine code pc at start of block */ + stackptr instack; /* stack at begin of basic block */ + stackptr outstack; /* stack at end of basic block */ + int indepth; /* stack depth at begin of basic block */ + int outdepth; /* stack depth end of basic block */ + branchref *branchrefs; /* list of branches to be patched */ + }; + + +/************************* pseudo variable structure **************************/ + +struct varinfo { + int type; /* basic type of variable */ + int flags; /* flags (SAVED, INMEMORY) */ + int regoff; /* register number or memory offset */ + }; + +typedef varinfo varinfo5[5]; + + +/***************** forward references in branch instructions ******************/ + +struct branchref { + s4 branchpos; /* patching position in code segment */ + branchref *next; /* next element in branchref list */ + }; + + +/******************** forward references in tables ***************************/ + +struct jumpref { + s4 tablepos; /* patching position in data segment */ + basicblock *target; /* target basic block */ + jumpref *next; /* next element in jumpref list */ + }; + + +/********** JavaVM operation codes (sorted) and instruction lengths ***********/ + +static int stackreq[256]; + +static int jcommandsize[256] = { + +#define JAVA_NOP 0 +#define ICMD_NOP 0 + 1, +#define JAVA_ACONST_NULL 1 +#define ICMD_ACONST 1 /* op1 = 0, val.a = constant */ + 1, +#define JAVA_ICONST_M1 2 +#define ICMD_NULLCHECKPOP 2 + 1, +#define JAVA_ICONST_0 3 +#define ICMD_ICONST 3 /* op1 = 0, val.i = constant */ + 1, +#define JAVA_ICONST_1 4 + 1, +#define JAVA_ICONST_2 5 + 1, +#define JAVA_ICONST_3 6 + 1, +#define JAVA_ICONST_4 7 + 1, +#define JAVA_ICONST_5 8 + 1, +#define JAVA_LCONST_0 9 +#define ICMD_LCONST 9 /* op1 = 0, val.l = constant */ + 1, +#define JAVA_LCONST_1 10 +#define ICMD_LCMPCONST 10 /* op1 = 0, val.l = constant */ + 1, +#define JAVA_FCONST_0 11 +#define ICMD_FCONST 11 /* op1 = 0, val.f = constant */ + 1, +#define JAVA_FCONST_1 12 + 1, +#define JAVA_FCONST_2 13 + 1, +#define JAVA_DCONST_0 14 +#define ICMD_DCONST 14 /* op1 = 0, val.a = constant */ + 1, +#define JAVA_DCONST_1 15 + 1, +#define JAVA_BIPUSH 16 + 2, +#define JAVA_SIPUSH 17 + 3, +#define JAVA_LDC1 18 + 2, +#define JAVA_LDC2 19 + 3, +#define JAVA_LDC2W 20 + 3, + /* order of LOAD instructions must be */ + /* equal to order of TYPE_XXX defines */ +#define JAVA_ILOAD 21 +#define ICMD_ILOAD 21 /* op1 = local variable */ + 2, +#define JAVA_LLOAD 22 +#define ICMD_LLOAD 22 /* op1 = local variable */ + 2, +#define JAVA_FLOAD 23 +#define ICMD_FLOAD 23 /* op1 = local variable */ + 2, +#define JAVA_DLOAD 24 +#define ICMD_DLOAD 24 /* op1 = local variable */ + 2, +#define JAVA_ALOAD 25 +#define ICMD_ALOAD 25 /* op1 = local variable */ + 2, +#define JAVA_ILOAD_0 26 +#define ICMD_IADDCONST 26 + 1, +#define JAVA_ILOAD_1 27 +#define ICMD_ISUBCONST 27 + 1, +#define JAVA_ILOAD_2 28 +#define ICMD_IMULCONST 28 + 1, +#define JAVA_ILOAD_3 29 +#define ICMD_IANDCONST 29 + 1, +#define JAVA_LLOAD_0 30 +#define ICMD_IORCONST 30 + 1, +#define JAVA_LLOAD_1 31 +#define ICMD_IXORCONST 31 + 1, +#define JAVA_LLOAD_2 32 +#define ICMD_ISHLCONST 32 + 1, +#define JAVA_LLOAD_3 33 +#define ICMD_ISHRCONST 33 + 1, +#define JAVA_FLOAD_0 34 +#define ICMD_IUSHRCONST 34 + 1, +#define JAVA_FLOAD_1 35 + 1, +#define JAVA_FLOAD_2 36 +#define ICMD_LADDCONST 36 + 1, +#define JAVA_FLOAD_3 37 +#define ICMD_LSUBCONST 37 + 1, +#define JAVA_DLOAD_0 38 +#define ICMD_LMULCONST 38 + 1, +#define JAVA_DLOAD_1 39 +#define ICMD_LANDCONST 39 + 1, +#define JAVA_DLOAD_2 40 +#define ICMD_LORCONST 40 + 1, +#define JAVA_DLOAD_3 41 +#define ICMD_LXORCONST 41 + 1, +#define JAVA_ALOAD_0 42 +#define ICMD_LSHLCONST 42 + 1, +#define JAVA_ALOAD_1 43 +#define ICMD_LSHRCONST 43 + 1, +#define JAVA_ALOAD_2 44 +#define ICMD_LUSHRCONST 44 + 1, +#define JAVA_ALOAD_3 45 + 1, +#define JAVA_IALOAD 46 +#define ICMD_IALOAD 46 + 1, +#define JAVA_LALOAD 47 +#define ICMD_LALOAD 47 + 1, +#define JAVA_FALOAD 48 +#define ICMD_FALOAD 48 + 1, +#define JAVA_DALOAD 49 +#define ICMD_DALOAD 49 + 1, +#define JAVA_AALOAD 50 +#define ICMD_AALOAD 50 + 1, +#define JAVA_BALOAD 51 +#define ICMD_BALOAD 51 + 1, +#define JAVA_CALOAD 52 +#define ICMD_CALOAD 52 + 1, +#define JAVA_SALOAD 53 +#define ICMD_SALOAD 53 + 1, + /* order of STORE instructions must be*/ + /* equal to order of TYPE_XXX defines */ +#define JAVA_ISTORE 54 +#define ICMD_ISTORE 54 /* op1 = local variable */ + 2, +#define JAVA_LSTORE 55 +#define ICMD_LSTORE 55 /* op1 = local variable */ + 2, +#define JAVA_FSTORE 56 +#define ICMD_FSTORE 56 /* op1 = local variable */ + 2, +#define JAVA_DSTORE 57 +#define ICMD_DSTORE 57 /* op1 = local variable */ + 2, +#define JAVA_ASTORE 58 +#define ICMD_ASTORE 58 /* op1 = local variable */ + 2, +#define JAVA_ISTORE_0 59 +#define ICMD_IF_LEQ 59 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_ISTORE_1 60 +#define ICMD_IF_LNE 60 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_ISTORE_2 61 +#define ICMD_IF_LLT 61 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_ISTORE_3 62 +#define ICMD_IF_LGE 62 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_LSTORE_0 63 +#define ICMD_IF_LGT 63 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_LSTORE_1 64 +#define ICMD_IF_LLE 64 /* op1 = target JavaVM pc, val.l */ + 1, +#define JAVA_LSTORE_2 65 +#define ICMD_IF_LCMPEQ 65 /* op1 = target JavaVM pc */ + 1, +#define JAVA_LSTORE_3 66 +#define ICMD_IF_LCMPNE 66 /* op1 = target JavaVM pc */ + 1, +#define JAVA_FSTORE_0 67 +#define ICMD_IF_LCMPLT 67 /* op1 = target JavaVM pc */ + 1, +#define JAVA_FSTORE_1 68 +#define ICMD_IF_LCMPGE 68 /* op1 = target JavaVM pc */ + 1, +#define JAVA_FSTORE_2 69 +#define ICMD_IF_LCMPGT 69 /* op1 = target JavaVM pc */ + 1, +#define JAVA_FSTORE_3 70 +#define ICMD_IF_LCMPLE 70 /* op1 = target JavaVM pc */ + 1, +#define JAVA_DSTORE_0 71 + 1, +#define JAVA_DSTORE_1 72 + 1, +#define JAVA_DSTORE_2 73 + 1, +#define JAVA_DSTORE_3 74 + 1, +#define JAVA_ASTORE_0 75 + 1, +#define JAVA_ASTORE_1 76 + 1, +#define JAVA_ASTORE_2 77 + 1, +#define JAVA_ASTORE_3 78 + 1, +#define JAVA_IASTORE 79 +#define ICMD_IASTORE 79 + 1, +#define JAVA_LASTORE 80 +#define ICMD_LASTORE 80 + 1, +#define JAVA_FASTORE 81 +#define ICMD_FASTORE 81 + 1, +#define JAVA_DASTORE 82 +#define ICMD_DASTORE 82 + 1, +#define JAVA_AASTORE 83 +#define ICMD_AASTORE 83 + 1, +#define JAVA_BASTORE 84 +#define ICMD_BASTORE 84 + 1, +#define JAVA_CASTORE 85 +#define ICMD_CASTORE 85 + 1, +#define JAVA_SASTORE 86 +#define ICMD_SASTORE 86 + 1, +#define JAVA_POP 87 +#define ICMD_POP 87 + 1, +#define JAVA_POP2 88 +#define ICMD_POP2 88 + 1, +#define JAVA_DUP 89 +#define ICMD_DUP 89 + 1, +#define JAVA_DUP_X1 90 +#define ICMD_DUP_X1 90 + 1, +#define JAVA_DUP_X2 91 +#define ICMD_DUP_X2 91 + 1, +#define JAVA_DUP2 92 +#define ICMD_DUP2 92 + 1, +#define JAVA_DUP2_X1 93 +#define ICMD_DUP2_X1 93 + 1, +#define JAVA_DUP2_X2 94 +#define ICMD_DUP2_X2 94 + 1, +#define JAVA_SWAP 95 +#define ICMD_SWAP 95 + 1, +#define JAVA_IADD 96 +#define ICMD_IADD 96 + 1, +#define JAVA_LADD 97 +#define ICMD_LADD 97 + 1, +#define JAVA_FADD 98 +#define ICMD_FADD 98 + 1, +#define JAVA_DADD 99 +#define ICMD_DADD 99 + 1, +#define JAVA_ISUB 100 +#define ICMD_ISUB 100 + 1, +#define JAVA_LSUB 101 +#define ICMD_LSUB 101 + 1, +#define JAVA_FSUB 102 +#define ICMD_FSUB 102 + 1, +#define JAVA_DSUB 103 +#define ICMD_DSUB 103 + 1, +#define JAVA_IMUL 104 +#define ICMD_IMUL 104 + 1, +#define JAVA_LMUL 105 +#define ICMD_LMUL 105 + 1, +#define JAVA_FMUL 106 +#define ICMD_FMUL 106 + 1, +#define JAVA_DMUL 107 +#define ICMD_DMUL 107 + 1, +#define JAVA_IDIV 108 +#define ICMD_IDIV 108 + 1, +#define JAVA_LDIV 109 +#define ICMD_LDIV 109 + 1, +#define JAVA_FDIV 110 +#define ICMD_FDIV 110 + 1, +#define JAVA_DDIV 111 +#define ICMD_DDIV 111 + 1, +#define JAVA_IREM 112 +#define ICMD_IREM 112 + 1, +#define JAVA_LREM 113 +#define ICMD_LREM 113 + 1, +#define JAVA_FREM 114 +#define ICMD_FREM 114 + 1, +#define JAVA_DREM 115 +#define ICMD_DREM 115 + 1, +#define JAVA_INEG 116 +#define ICMD_INEG 116 + 1, +#define JAVA_LNEG 117 +#define ICMD_LNEG 117 + 1, +#define JAVA_FNEG 118 +#define ICMD_FNEG 118 + 1, +#define JAVA_DNEG 119 +#define ICMD_DNEG 119 + 1, +#define JAVA_ISHL 120 +#define ICMD_ISHL 120 + 1, +#define JAVA_LSHL 121 +#define ICMD_LSHL 121 + 1, +#define JAVA_ISHR 122 +#define ICMD_ISHR 122 + 1, +#define JAVA_LSHR 123 +#define ICMD_LSHR 123 + 1, +#define JAVA_IUSHR 124 +#define ICMD_IUSHR 124 + 1, +#define JAVA_LUSHR 125 +#define ICMD_LUSHR 125 + 1, +#define JAVA_IAND 126 +#define ICMD_IAND 126 + 1, +#define JAVA_LAND 127 +#define ICMD_LAND 127 + 1, +#define JAVA_IOR 128 +#define ICMD_IOR 128 + 1, +#define JAVA_LOR 129 +#define ICMD_LOR 129 + 1, +#define JAVA_IXOR 130 +#define ICMD_IXOR 130 + 1, +#define JAVA_LXOR 131 +#define ICMD_LXOR 131 + 1, +#define JAVA_IINC 132 +#define ICMD_IINC 132 /* op1 = local variable, val.i = constant */ + 3, +#define JAVA_I2L 133 +#define ICMD_I2L 133 + 1, +#define JAVA_I2F 134 +#define ICMD_I2F 134 + 1, +#define JAVA_I2D 135 +#define ICMD_I2D 135 + 1, +#define JAVA_L2I 136 +#define ICMD_L2I 136 + 1, +#define JAVA_L2F 137 +#define ICMD_L2F 137 + 1, +#define JAVA_L2D 138 +#define ICMD_L2D 138 + 1, +#define JAVA_F2I 139 +#define ICMD_F2I 139 + 1, +#define JAVA_F2L 140 +#define ICMD_F2L 140 + 1, +#define JAVA_F2D 141 +#define ICMD_F2D 141 + 1, +#define JAVA_D2I 142 +#define ICMD_D2I 142 + 1, +#define JAVA_D2L 143 +#define ICMD_D2L 143 + 1, +#define JAVA_D2F 144 +#define ICMD_D2F 144 + 1, +#define JAVA_INT2BYTE 145 +#define ICMD_INT2BYTE 145 + 1, +#define JAVA_INT2CHAR 146 +#define ICMD_INT2CHAR 146 + 1, +#define JAVA_INT2SHORT 147 +#define ICMD_INT2SHORT 147 + 1, +#define JAVA_LCMP 148 +#define ICMD_LCMP 148 + 1, +#define JAVA_FCMPL 149 +#define ICMD_FCMPL 149 + 1, +#define JAVA_FCMPG 150 +#define ICMD_FCMPG 150 + 1, +#define JAVA_DCMPL 151 +#define ICMD_DCMPL 151 + 1, +#define JAVA_DCMPG 152 +#define ICMD_DCMPG 152 + 1, +#define JAVA_IFEQ 153 +#define ICMD_IFEQ 153 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IFNE 154 +#define ICMD_IFNE 154 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IFLT 155 +#define ICMD_IFLT 155 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IFGE 156 +#define ICMD_IFGE 156 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IFGT 157 +#define ICMD_IFGT 157 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IFLE 158 +#define ICMD_IFLE 158 /* op1 = target JavaVM pc, val.i */ + 3, +#define JAVA_IF_ICMPEQ 159 +#define ICMD_IF_ICMPEQ 159 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ICMPNE 160 +#define ICMD_IF_ICMPNE 160 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ICMPLT 161 +#define ICMD_IF_ICMPLT 161 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ICMPGE 162 +#define ICMD_IF_ICMPGE 162 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ICMPGT 163 +#define ICMD_IF_ICMPGT 163 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ICMPLE 164 +#define ICMD_IF_ICMPLE 164 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ACMPEQ 165 +#define ICMD_IF_ACMPEQ 165 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IF_ACMPNE 166 +#define ICMD_IF_ACMPNE 166 /* op1 = target JavaVM pc */ + 3, +#define JAVA_GOTO 167 +#define ICMD_GOTO 167 /* op1 = target JavaVM pc */ + 3, +#define JAVA_JSR 168 +#define ICMD_JSR 168 /* op1 = target JavaVM pc */ + 3, +#define JAVA_RET 169 +#define ICMD_RET 169 /* op1 = local variable */ + 2, +#define JAVA_TABLESWITCH 170 +#define ICMD_TABLESWITCH 170 /* val.a = pointer to s4 table */ + 0, /* length must be computed */ +#define JAVA_LOOKUPSWITCH 171 +#define ICMD_LOOKUPSWITCH 171 /* val.a = pointer to s4 table */ + 0, /* length must be computed */ +#define JAVA_IRETURN 172 +#define ICMD_IRETURN 172 + 1, +#define JAVA_LRETURN 173 +#define ICMD_LRETURN 173 + 1, +#define JAVA_FRETURN 174 +#define ICMD_FRETURN 174 + 1, +#define JAVA_DRETURN 175 +#define ICMD_DRETURN 175 + 1, +#define JAVA_ARETURN 176 +#define ICMD_ARETURN 176 + 1, +#define JAVA_RETURN 177 +#define ICMD_RETURN 177 + 1, +#define JAVA_GETSTATIC 178 +#define ICMD_GETSTATIC 178 /* op1 = type, val.a = field adress */ + 3, +#define JAVA_PUTSTATIC 179 +#define ICMD_PUTSTATIC 179 /* op1 = type, val.a = field adress */ + 3, +#define JAVA_GETFIELD 180 +#define ICMD_GETFIELD 180 /* op1 = type, val.i = field offset */ + 3, +#define JAVA_PUTFIELD 181 +#define ICMD_PUTFIELD 181 /* op1 = type, val.i = field offset */ + 3, +#define JAVA_INVOKEVIRTUAL 182 +#define ICMD_INVOKEVIRTUAL 182 /* val.a = method info pointer */ + 3, +#define JAVA_INVOKESPECIAL 183 +#define ICMD_INVOKESPECIAL 183 /* val.a = method info pointer */ + 3, +#define JAVA_INVOKESTATIC 184 +#define ICMD_INVOKESTATIC 184 /* val.a = method info pointer */ + 3, +#define JAVA_INVOKEINTERFACE 185 +#define ICMD_INVOKEINTERFACE 185 /* val.a = method info pointer */ + 5, +#define ICMD_CHECKASIZE 186 /* */ + 1, /* unused */ +#define JAVA_NEW 187 +#define ICMD_NEW 187 /* op1 = 1, val.a = class pointer */ + 3, +#define JAVA_NEWARRAY 188 +#define ICMD_NEWARRAY 188 /* op1 = basic type */ + 2, +#define JAVA_ANEWARRAY 189 +#define ICMD_ANEWARRAY 189 /* op1 = 0, val.a = array pointer */ + 3, /* op1 = 1, val.a = class pointer */ +#define JAVA_ARRAYLENGTH 190 +#define ICMD_ARRAYLENGTH 190 + 1, +#define JAVA_ATHROW 191 +#define ICMD_ATHROW 191 + 1, +#define JAVA_CHECKCAST 192 +#define ICMD_CHECKCAST 192 /* op1 = 0, val.a = array pointer */ + 3, /* op1 = 1, val.a = class pointer */ +#define JAVA_INSTANCEOF 193 +#define ICMD_INSTANCEOF 193 /* op1 = 0, val.a = array pointer */ + 3, /* op1 = 1, val.a = class pointer */ +#define JAVA_MONITORENTER 194 +#define ICMD_MONITORENTER 194 + 1, +#define JAVA_MONITOREXIT 195 +#define ICMD_MONITOREXIT 195 + 1, +#define JAVA_WIDE 196 + 0, /* length must be computed */ +#define JAVA_MULTIANEWARRAY 197 +#define ICMD_MULTIANEWARRAY 197 /* op1 = dimension, val.a = array */ + 4, /* pointer */ +#define JAVA_IFNULL 198 +#define ICMD_IFNULL 198 /* op1 = target JavaVM pc */ + 3, +#define JAVA_IFNONNULL 199 +#define ICMD_IFNONNULL 199 /* op1 = target JavaVM pc */ + 3, +#define JAVA_GOTO_W 200 + 5, +#define JAVA_JSR_W 201 + 5, +#define JAVA_BREAKPOINT 202 + 1, + + 1,1,1,1,1,1,1,1, /* unused */ + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1 + }; + +#define ICMD_BUILTIN3 253 /* internal opcode */ +#define ICMD_BUILTIN2 254 /* internal opcode */ +#define ICMD_BUILTIN1 255 /* internal opcode */ + + +/******************* description of JavaVM instructions ***********************/ + +typedef struct { + u1 opcode; + u1 type_s1; + u1 type_s2; + u1 type_d; + functionptr builtin; + bool supported; + bool isfloat; +} stdopdescriptor; + +static stdopdescriptor *stdopdescriptors[256]; + +static stdopdescriptor stdopdescriptortable[] = { + { JAVA_IADD, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_ISUB, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_IMUL, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_ISHL, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_ISHR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_IUSHR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_IAND, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_IOR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_IXOR, TYPE_INT, TYPE_INT, TYPE_INT, NULL, true, false }, + { JAVA_INEG, TYPE_INT, TYPE_VOID,TYPE_INT, NULL, true, false }, + + { JAVA_LADD, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_ladd , SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { JAVA_LSUB, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lsub , SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { JAVA_LMUL, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lmul , SUPPORT_LONG && SUPPORT_LONG_MULDIV, false }, + { JAVA_LSHL, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lshl , SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { JAVA_LSHR, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lshr, SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { JAVA_LUSHR, TYPE_LONG, TYPE_INT, TYPE_LONG, + (functionptr) builtin_lushr, SUPPORT_LONG && SUPPORT_LONG_SHIFT, false }, + { JAVA_LAND, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_land, SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { JAVA_LOR, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lor , SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { JAVA_LXOR, TYPE_LONG, TYPE_LONG, TYPE_LONG, + (functionptr) builtin_lxor, SUPPORT_LONG && SUPPORT_LONG_LOG, false }, + { JAVA_LNEG, TYPE_LONG, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_lneg, SUPPORT_LONG && SUPPORT_LONG_ADD, false }, + { JAVA_LCMP, TYPE_LONG, TYPE_LONG, TYPE_INT, + (functionptr) builtin_lcmp, SUPPORT_LONG && SUPPORT_LONG_CMP, false }, + + { JAVA_FADD, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fadd, SUPPORT_FLOAT, true }, + { JAVA_FSUB, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fsub, SUPPORT_FLOAT, true }, + { JAVA_FMUL, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fmul, SUPPORT_FLOAT, true }, + { JAVA_FDIV, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_fdiv, SUPPORT_FLOAT, true }, + { JAVA_FREM, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, + (functionptr) builtin_frem, SUPPORT_FLOAT, true }, + { JAVA_FNEG, TYPE_FLOAT, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_fneg, SUPPORT_FLOAT, true }, + { JAVA_FCMPL, TYPE_FLOAT, TYPE_FLOAT, TYPE_INT, + (functionptr) builtin_fcmpl, SUPPORT_FLOAT, true }, + { JAVA_FCMPG, TYPE_FLOAT, TYPE_FLOAT, TYPE_INT, + (functionptr) builtin_fcmpg, SUPPORT_FLOAT, true }, + + { JAVA_DADD, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dadd, SUPPORT_DOUBLE, true }, + { JAVA_DSUB, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dsub, SUPPORT_DOUBLE, true }, + { JAVA_DMUL, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_dmul, SUPPORT_DOUBLE, true }, + { JAVA_DDIV, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_ddiv, SUPPORT_DOUBLE, true }, + { JAVA_DREM, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, + (functionptr) builtin_drem, SUPPORT_DOUBLE, true }, + { JAVA_DNEG, TYPE_DOUBLE, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_dneg, SUPPORT_DOUBLE, true }, + { JAVA_DCMPL, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_INT, + (functionptr) builtin_dcmpl, SUPPORT_DOUBLE, true }, + { JAVA_DCMPG, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_INT, + (functionptr) builtin_dcmpg, SUPPORT_DOUBLE, true }, + + { JAVA_INT2BYTE, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { JAVA_INT2CHAR, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { JAVA_INT2SHORT, TYPE_INT, TYPE_VOID, TYPE_INT, NULL, true,false }, + { JAVA_I2L, TYPE_INT, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_i2l, SUPPORT_LONG && SUPPORT_LONG_ICVT, false }, + { JAVA_I2F, TYPE_INT, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_i2f, SUPPORT_FLOAT, true }, + { JAVA_I2D, TYPE_INT, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_i2d, SUPPORT_DOUBLE, true }, + { JAVA_L2I, TYPE_LONG, TYPE_VOID, TYPE_INT, + (functionptr) builtin_l2i, SUPPORT_LONG && SUPPORT_LONG_ICVT, false }, + { JAVA_L2F, TYPE_LONG, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_l2f, SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_LONG_FCVT, true }, + { JAVA_L2D, TYPE_LONG, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_l2d, SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_LONG_FCVT, true }, + { JAVA_F2I, TYPE_FLOAT, TYPE_VOID, TYPE_INT, + (functionptr) builtin_f2i, SUPPORT_FLOAT, true }, + { JAVA_F2L, TYPE_FLOAT, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_f2l, SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_LONG_FCVT, true }, + { JAVA_F2D, TYPE_FLOAT, TYPE_VOID, TYPE_DOUBLE, + (functionptr) builtin_f2d, SUPPORT_FLOAT && SUPPORT_DOUBLE, true }, + { JAVA_D2I, TYPE_DOUBLE, TYPE_VOID, TYPE_INT, + (functionptr) builtin_d2i, SUPPORT_DOUBLE, true }, + { JAVA_D2L, TYPE_DOUBLE, TYPE_VOID, TYPE_LONG, + (functionptr) builtin_d2l, SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_LONG_FCVT, true }, + { JAVA_D2F, TYPE_DOUBLE, TYPE_VOID, TYPE_FLOAT, + (functionptr) builtin_d2f, SUPPORT_DOUBLE && SUPPORT_FLOAT, true }, + +}; + +static char *icmd_names[256] = { + "NOP ", /* 0 */ + "ACONST ", /* 1 */ + "NULLCHECKPOP ", /* ICONST_M1 2 */ + "ICONST ", /* 3 */ + "UNDEF__4 ", /* ICONST_1 4 */ + "UNDEF__5 ", /* ICONST_2 5 */ + "UNDEF__6 ", /* ICONST_3 6 */ + "UNDEF__7 ", /* ICONST_4 7 */ + "UNDEF__8 ", /* ICONST_5 8 */ + "LCONST ", /* 9 */ + "LCMPCONST ", /* LCONST_1 10 */ + "FCONST ", /* 11 */ + "UNDEF_12 ", /* FCONST_1 12 */ + "UNDEF_13 ", /* FCONST_2 13 */ + "DCONST ", /* 14 */ + "UNDEF_15 ", /* DCONST_1 15 */ + "UNDEF_16 ", /* BIPUSH 16 */ + "UNDEF_17 ", /* SIPUSH 17 */ + "UNDEF_18 ", /* LDC1 18 */ + "UNDEF_19 ", /* LDC2 19 */ + "UNDEF_20 ", /* LDC2W 20 */ + "ILOAD ", /* 21 */ + "LLOAD ", /* 22 */ + "FLOAD ", /* 23 */ + "DLOAD ", /* 24 */ + "ALOAD ", /* 25 */ + "IADDCONST ", /* ILOAD_0 26 */ + "ISUBCONST ", /* ILOAD_1 27 */ + "IMULCONST ", /* ILOAD_2 28 */ + "IANDCONST ", /* ILOAD_3 29 */ + "IORCONST ", /* LLOAD_0 30 */ + "IXORCONST ", /* LLOAD_1 31 */ + "ISHLCONST ", /* LLOAD_2 32 */ + "ISHRCONST ", /* LLOAD_3 33 */ + "IUSHRCONST ", /* FLOAD_0 34 */ + "UNDEF_35 ", /* FLOAD_1 35 */ + "LADDCONST ", /* FLOAD_2 36 */ + "LSUBCONST ", /* FLOAD_3 37 */ + "LMULCONST ", /* DLOAD_0 38 */ + "LANDCONST ", /* DLOAD_1 39 */ + "LORCONST ", /* DLOAD_2 40 */ + "LXORCONST ", /* DLOAD_3 41 */ + "LSHLCONST ", /* ALOAD_0 42 */ + "LSHRCONST ", /* ALOAD_1 43 */ + "LUSHRCONST ", /* ALOAD_2 44 */ + "UNDEF_45 ", /* ALOAD_3 45 */ + "IALOAD ", /* 46 */ + "LALOAD ", /* 47 */ + "FALOAD ", /* 48 */ + "DALOAD ", /* 49 */ + "AALOAD ", /* 50 */ + "BALOAD ", /* 51 */ + "CALOAD ", /* 52 */ + "SALOAD ", /* 53 */ + "ISTORE ", /* 54 */ + "LSTORE ", /* 55 */ + "FSTORE ", /* 56 */ + "DSTORE ", /* 57 */ + "ASTORE ", /* 58 */ + "IF_LEQ ", /* ISTORE_0 59 */ + "IF_LNE ", /* ISTORE_1 60 */ + "IF_LLT ", /* ISTORE_2 61 */ + "IF_LGE ", /* ISTORE_3 62 */ + "IF_LGT ", /* LSTORE_0 63 */ + "IF_LLE ", /* LSTORE_1 64 */ + "IF_LCMPEQ ", /* LSTORE_2 65 */ + "IF_LCMPNE ", /* LSTORE_3 66 */ + "IF_LCMPLT ", /* FSTORE_0 67 */ + "IF_LCMPGE ", /* FSTORE_1 68 */ + "IF_LCMPGT ", /* FSTORE_2 69 */ + "IF_LCMPLE ", /* FSTORE_3 70 */ + "UNDEF_71 ", /* DSTORE_0 71 */ + "UNDEF_72 ", /* DSTORE_1 72 */ + "UNDEF_73 ", /* DSTORE_2 73 */ + "UNDEF_74 ", /* DSTORE_3 74 */ + "UNDEF_75 ", /* ASTORE_0 75 */ + "UNDEF_76 ", /* ASTORE_1 76 */ + "UNDEF_77 ", /* ASTORE_2 77 */ + "UNDEF_78 ", /* ASTORE_3 78 */ + "IASTORE ", /* 79 */ + "LASTORE ", /* 80 */ + "FASTORE ", /* 81 */ + "DASTORE ", /* 82 */ + "AASTORE ", /* 83 */ + "BASTORE ", /* 84 */ + "CASTORE ", /* 85 */ + "SASTORE ", /* 86 */ + "POP ", /* 87 */ + "POP2 ", /* 88 */ + "DUP ", /* 89 */ + "DUP_X1 ", /* 90 */ + "DUP_X2 ", /* 91 */ + "DUP2 ", /* 92 */ + "DUP2_X1 ", /* 93 */ + "DUP2_X2 ", /* 94 */ + "SWAP ", /* 95 */ + "IADD ", /* 96 */ + "LADD ", /* 97 */ + "FADD ", /* 98 */ + "DADD ", /* 99 */ + "ISUB ", /* 100 */ + "LSUB ", /* 101 */ + "FSUB ", /* 102 */ + "DSUB ", /* 103 */ + "IMUL ", /* 104 */ + "LMUL ", /* 105 */ + "FMUL ", /* 106 */ + "DMUL ", /* 107 */ + "IDIV ", /* 108 */ + "LDIV ", /* 109 */ + "FDIV ", /* 110 */ + "DDIV ", /* 111 */ + "IREM ", /* 112 */ + "LREM ", /* 113 */ + "FREM ", /* 114 */ + "DREM ", /* 115 */ + "INEG ", /* 116 */ + "LNEG ", /* 117 */ + "FNEG ", /* 118 */ + "DNEG ", /* 119 */ + "ISHL ", /* 120 */ + "LSHL ", /* 121 */ + "ISHR ", /* 122 */ + "LSHR ", /* 123 */ + "IUSHR ", /* 124 */ + "LUSHR ", /* 125 */ + "IAND ", /* 126 */ + "LAND ", /* 127 */ + "IOR ", /* 128 */ + "LOR ", /* 129 */ + "IXOR ", /* 130 */ + "LXOR ", /* 131 */ + "IINC ", /* 132 */ + "I2L ", /* 133 */ + "I2F ", /* 134 */ + "I2D ", /* 135 */ + "L2I ", /* 136 */ + "L2F ", /* 137 */ + "L2D ", /* 138 */ + "F2I ", /* 139 */ + "F2L ", /* 140 */ + "F2D ", /* 141 */ + "D2I ", /* 142 */ + "D2L ", /* 143 */ + "D2F ", /* 144 */ + "INT2BYTE ", /* 145 */ + "INT2CHAR ", /* 146 */ + "INT2SHORT ", /* 147 */ + "LCMP ", /* 148 */ + "FCMPL ", /* 149 */ + "FCMPG ", /* 150 */ + "DCMPL ", /* 151 */ + "DCMPG ", /* 152 */ + "IFEQ ", /* 153 */ + "IFNE ", /* 154 */ + "IFLT ", /* 155 */ + "IFGE ", /* 156 */ + "IFGT ", /* 157 */ + "IFLE ", /* 158 */ + "IF_ICMPEQ ", /* 159 */ + "IF_ICMPNE ", /* 160 */ + "IF_ICMPLT ", /* 161 */ + "IF_ICMPGE ", /* 162 */ + "IF_ICMPGT ", /* 163 */ + "IF_ICMPLE ", /* 164 */ + "IF_ACMPEQ ", /* 165 */ + "IF_ACMPNE ", /* 166 */ + "GOTO ", /* 167 */ + "JSR ", /* 168 */ + "RET ", /* 169 */ + "TABLESWITCH ", /* 170 */ + "LOOKUPSWITCH ", /* 171 */ + "IRETURN ", /* 172 */ + "LRETURN ", /* 173 */ + "FRETURN ", /* 174 */ + "DRETURN ", /* 175 */ + "ARETURN ", /* 176 */ + "RETURN ", /* 177 */ + "GETSTATIC ", /* 178 */ + "PUTSTATIC ", /* 179 */ + "GETFIELD ", /* 180 */ + "PUTFIELD ", /* 181 */ + "INVOKEVIRTUAL", /* 182 */ + "INVOKESPECIAL", /* 183 */ + "INVOKESTATIC ", /* 184 */ + "INVOKEINTERFACE",/* 185 */ + "CHECKASIZE ", /* UNDEF186 186 */ + "NEW ", /* 187 */ + "NEWARRAY ", /* 188 */ + "ANEWARRAY ", /* 189 */ + "ARRAYLENGTH ", /* 190 */ + "ATHROW ", /* 191 */ + "CHECKCAST ", /* 192 */ + "INSTANCEOF ", /* 193 */ + "MONITORENTER ", /* 194 */ + "MONITOREXIT ", /* 195 */ + "UNDEF196 ", /* WIDE 196 */ + "MULTIANEWARRAY",/* 197 */ + "IFNULL ", /* 198 */ + "IFNONNULL ", /* 199 */ + "UNDEF200 ", /* GOTO_W 200 */ + "UNDEF201 ", /* JSR_W 201 */ + "UNDEF202 ", /* BREAKPOINT 202 */ + + "UNDEF203","UNDEF204","UNDEF205", + "UNDEF206","UNDEF207","UNDEF208","UNDEF209","UNDEF210", + "UNDEF","UNDEF","UNDEF","UNDEF","UNDEF", + "UNDEF216","UNDEF217","UNDEF218","UNDEF219","UNDEF220", + "UNDEF","UNDEF","UNDEF","UNDEF","UNDEF", + "UNDEF226","UNDEF227","UNDEF228","UNDEF229","UNDEF230", + "UNDEF","UNDEF","UNDEF","UNDEF","UNDEF", + "UNDEF236","UNDEF237","UNDEF238","UNDEF239","UNDEF240", + "UNDEF","UNDEF","UNDEF","UNDEF","UNDEF", + "UNDEF246","UNDEF247","UNDEF248","UNDEF249","UNDEF250", + "UNDEF251","UNDEF252", + "BUILTIN3 ", /* 253 */ + "BUILTIN2 ", /* 254 */ + "BUILTIN1 " /* 255 */ + }; + + + +/***************************** register types *********************************/ + +#define REG_RES 0 /* reserved register for OS or code generator */ +#define REG_RET 1 /* return value register */ +#define REG_EXC 2 /* exception value register */ +#define REG_SAV 3 /* (callee) saved register */ +#define REG_TMP 4 /* scratch temporary register (caller saved) */ +#define REG_ARG 5 /* argument register (caller saved) */ + +#define REG_END -1 /* last entry in tables */ + +#define PARAMMODE_NUMBERED 0 +#define PARAMMODE_STUFFED 1 + +/***************************** register info block ****************************/ + +extern int nregdescint[]; /* description of integer registers */ +extern int nregdescfloat[]; /* description of floating point registers */ + +extern int nreg_parammode; + +void asm_handle_exception(); +void asm_handle_nat_exception(); diff --git a/ncomp/nparse.c b/ncomp/nparse.c new file mode 100644 index 000000000..993e305f0 --- /dev/null +++ b/ncomp/nparse.c @@ -0,0 +1,979 @@ +/****************************** ncomp/nparse.c ********************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Parser for JavaVM to intermediate code translation + + Author: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/05/07 + +*******************************************************************************/ + +#include "math.h" + +/*********************** function allocate_literals **************************** + + Scans the JavaVM code of a method and allocates string literals. Needed + to generate the same addresses as the old JIT compiler. + +*******************************************************************************/ + +static void allocate_literals() +{ + int p, nextp; + int opcode, i; + s4 num; + unicode *s; + + for (p = 0; p < jcodelength; p = nextp) { + + opcode = jcode[p]; + nextp = p + jcommandsize[opcode]; + + switch (opcode) { + case JAVA_WIDE: + if (code_get_u1(p + 1) == JAVA_IINC) + nextp = p + 6; + else + nextp = p + 4; + break; + + case JAVA_LOOKUPSWITCH: + nextp = ALIGN((p + 1), 4); + num = code_get_u4(nextp + 4); + nextp = nextp + 8 + 8 * num; + break; + + case JAVA_TABLESWITCH: + nextp = ALIGN ((p + 1),4); + num = code_get_s4(nextp + 4); + num = code_get_s4(nextp + 8) - num; + nextp = nextp + 16 + 4 * num; + break; + + case JAVA_LDC1: + i = code_get_u1(p+1); + goto pushconstantitem; + case JAVA_LDC2: + case JAVA_LDC2W: + i = code_get_u2(p + 1); + pushconstantitem: + if (class_constanttype(class, i) == CONSTANT_String) { + s = class_getconstant(class, i, CONSTANT_String); + (void) literalstring_new(s); + } + break; + } /* end switch */ + } /* end while */ +} + + + +/******************************************************************************* + + function 'parse' scans the JavaVM code and generates intermediate code + + During parsing the block index table is used to store at bit pos 0 + a flag which marks basic block starts and at position 1 to 31 the + intermediate instruction index. After parsing the block index table + is scanned, for marked positions a block is generated and the block + number is stored in the block index table. + +*******************************************************************************/ + +/* intermediate code generating macros */ + +#define PINC iptr++;ipc++ +#define LOADCONST_I(v) iptr->opc=ICMD_ICONST;iptr->op1=0;iptr->val.i=(v);PINC +#define LOADCONST_L(v) iptr->opc=ICMD_LCONST;iptr->op1=0;iptr->val.l=(v);PINC +#define LOADCONST_F(v) iptr->opc=ICMD_FCONST;iptr->op1=0;iptr->val.f=(v);PINC +#define LOADCONST_D(v) iptr->opc=ICMD_DCONST;iptr->op1=0;iptr->val.d=(v);PINC +#define LOADCONST_A(v) iptr->opc=ICMD_ACONST;iptr->op1=0;iptr->val.a=(v);PINC +#define OP(o) iptr->opc=(o);iptr->op1=0;iptr->val.l=0;PINC +#define OP1(o,o1) iptr->opc=(o);iptr->op1=(o1);iptr->val.l=(0);PINC +#define OP2I(o,o1,v) iptr->opc=(o);iptr->op1=(o1);iptr->val.i=(v);PINC +#define OP2A(o,o1,v) iptr->opc=(o);iptr->op1=(o1);iptr->val.a=(v);PINC +#define BUILTIN1(v,t) isleafmethod=false;iptr->opc=ICMD_BUILTIN1;iptr->op1=t;\ + iptr->val.a=(v);PINC +#define BUILTIN2(v,t) isleafmethod=false;iptr->opc=ICMD_BUILTIN2;iptr->op1=t;\ + iptr->val.a=(v);PINC +#define BUILTIN3(v,t) isleafmethod=false;iptr->opc=ICMD_BUILTIN3;iptr->op1=t;\ + iptr->val.a=(v);PINC + + +/* block generating and checking macros */ + +#define block_insert(i) {if(!(block_index[i]&1))\ + {b_count++;block_index[i] |= 1;}} +#define bound_check(i) {if((i< 0) || (i>=jcodelength)) \ + panic("branch target out of code-boundary");} +#define bound_check1(i) {if((i< 0) || (i>jcodelength)) \ + panic("branch target out of code-boundary");} + + +static void parse() +{ + int p; /* java instruction counter */ + int nextp; /* start of next java instruction */ + int opcode; /* java opcode */ + int i; /* temporary for different uses (counters) */ + int ipc = 0; /* intermediate instruction counter */ + int b_count = 0; /* basic block counter */ + int s_count = 0; /* stack element counter */ + bool blockend = false; /* true if basic block end has reached */ + bool iswide = false; /* true if last instruction was a wide */ + instruction *iptr; /* current pointer into instruction array */ + + + /* allocate instruction array and block index table */ + + /* 1 additional for end ipc and 3 for loop unrolling */ + + block_index = DMNEW(int, jcodelength + 3); + + /* 1 additional for TRACEBUILTIN and 4 for MONITORENTER/EXIT */ + /* additional MONITOREXITS are reached by branches which are 3 bytes */ + + iptr = instr = DMNEW(instruction, jcodelength + 5); + + /* initialize block_index table (unrolled four times) */ + + { + int *ip; + + for (i = 0, ip = block_index; i <= jcodelength; i += 4, ip += 4) { + ip[0] = 0; + ip[1] = 0; + ip[2] = 0; + ip[3] = 0; + } + } + + /* compute branch targets of exception table */ + + for (i = 0; i < exceptiontablelength; i++) { + p = extable[i].startpc; + bound_check(p); + block_insert(p); + p = extable[i].endpc; + bound_check1(p); + if (p < jcodelength) + block_insert(p); + p = extable[i].handlerpc; + bound_check(p); + block_insert(p); + } + + s_count = 1 + exceptiontablelength; /* initialize stack element counter */ + + if (runverbose) { +/* isleafmethod=false; */ + } + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + isleafmethod=false; + } +#endif + + /* scan all java instructions */ + + for (p = 0; p < jcodelength; p = nextp) { + + opcode = code_get_u1 (p); /* fetch op code */ + + block_index[p] |= (ipc << 1); /* store intermediate count */ + + if (blockend) { + block_insert(p); /* start new block */ + blockend = false; + } + + nextp = p + jcommandsize[opcode]; /* compute next instruction start */ + s_count += stackreq[opcode]; /* compute stack element count */ + + switch (opcode) { + + case JAVA_NOP: + break; + + /* pushing constants onto the stack p */ + + case JAVA_BIPUSH: + LOADCONST_I(code_get_s1(p+1)); + break; + + case JAVA_SIPUSH: + LOADCONST_I(code_get_s2(p+1)); + break; + + case JAVA_LDC1: + i = code_get_u1(p+1); + goto pushconstantitem; + case JAVA_LDC2: + case JAVA_LDC2W: + i = code_get_u2(p + 1); + + pushconstantitem: + + if (i >= class->cpcount) + panic ("Attempt to access constant outside range"); + + switch (class->cptags[i]) { + case CONSTANT_Integer: + LOADCONST_I(((constant_integer*) + (class->cpinfos[i]))->value); + break; + case CONSTANT_Long: + LOADCONST_L(((constant_long*) + (class->cpinfos[i]))->value); + break; + case CONSTANT_Float: + LOADCONST_F(((constant_float*) + (class->cpinfos[i]))->value); + break; + case CONSTANT_Double: + LOADCONST_D(((constant_double*) + (class->cpinfos[i]))->value); + break; + case CONSTANT_String: + LOADCONST_A(literalstring_new((unicode*) + (class->cpinfos[i]))); + break; + default: panic("Invalid constant type to push"); + } + break; + + case JAVA_ACONST_NULL: + LOADCONST_A(NULL); + break; + + case JAVA_ICONST_M1: + case JAVA_ICONST_0: + case JAVA_ICONST_1: + case JAVA_ICONST_2: + case JAVA_ICONST_3: + case JAVA_ICONST_4: + case JAVA_ICONST_5: + LOADCONST_I(opcode - JAVA_ICONST_0); + break; + + case JAVA_LCONST_0: + case JAVA_LCONST_1: + LOADCONST_L(opcode - JAVA_LCONST_0); + break; + + case JAVA_FCONST_0: + case JAVA_FCONST_1: + case JAVA_FCONST_2: + LOADCONST_F(opcode - JAVA_FCONST_0); + break; + + case JAVA_DCONST_0: + case JAVA_DCONST_1: + LOADCONST_D(opcode - JAVA_DCONST_0); + break; + + /* loading variables onto the stack */ + + case JAVA_ILOAD: + case JAVA_LLOAD: + case JAVA_FLOAD: + case JAVA_DLOAD: + case JAVA_ALOAD: + if (!iswide) + i = code_get_u1(p+1); + else { + i = code_get_u2(p+1); + nextp = p+3; + iswide = false; + } + OP1(opcode, i); + break; + + case JAVA_ILOAD_0: + case JAVA_ILOAD_1: + case JAVA_ILOAD_2: + case JAVA_ILOAD_3: + OP1(ICMD_ILOAD, opcode - JAVA_ILOAD_0); + break; + + case JAVA_LLOAD_0: + case JAVA_LLOAD_1: + case JAVA_LLOAD_2: + case JAVA_LLOAD_3: + OP1(ICMD_LLOAD, opcode - JAVA_LLOAD_0); + break; + + case JAVA_FLOAD_0: + case JAVA_FLOAD_1: + case JAVA_FLOAD_2: + case JAVA_FLOAD_3: + OP1(ICMD_FLOAD, opcode - JAVA_FLOAD_0); + break; + + case JAVA_DLOAD_0: + case JAVA_DLOAD_1: + case JAVA_DLOAD_2: + case JAVA_DLOAD_3: + OP1(ICMD_DLOAD, opcode - JAVA_DLOAD_0); + break; + + case JAVA_ALOAD_0: + case JAVA_ALOAD_1: + case JAVA_ALOAD_2: + case JAVA_ALOAD_3: + OP1(ICMD_ALOAD, opcode - JAVA_ALOAD_0); + break; + + /* storing stack values into local variables */ + + case JAVA_ISTORE: + case JAVA_LSTORE: + case JAVA_FSTORE: + case JAVA_DSTORE: + case JAVA_ASTORE: + if (!iswide) + i = code_get_u1(p+1); + else { + i = code_get_u2(p+1); + iswide=false; + nextp = p+3; + } + OP1(opcode, i); + break; + + case JAVA_ISTORE_0: + case JAVA_ISTORE_1: + case JAVA_ISTORE_2: + case JAVA_ISTORE_3: + OP1(ICMD_ISTORE, opcode - JAVA_ISTORE_0); + break; + + case JAVA_LSTORE_0: + case JAVA_LSTORE_1: + case JAVA_LSTORE_2: + case JAVA_LSTORE_3: + OP1(ICMD_LSTORE, opcode - JAVA_LSTORE_0); + break; + + case JAVA_FSTORE_0: + case JAVA_FSTORE_1: + case JAVA_FSTORE_2: + case JAVA_FSTORE_3: + OP1(ICMD_FSTORE, opcode - JAVA_FSTORE_0); + break; + + case JAVA_DSTORE_0: + case JAVA_DSTORE_1: + case JAVA_DSTORE_2: + case JAVA_DSTORE_3: + OP1(ICMD_DSTORE, opcode - JAVA_DSTORE_0); + break; + + case JAVA_ASTORE_0: + case JAVA_ASTORE_1: + case JAVA_ASTORE_2: + case JAVA_ASTORE_3: + OP1(ICMD_ASTORE, opcode - JAVA_ASTORE_0); + break; + + case JAVA_IINC: + { + int v; + + if (!iswide) { + i = code_get_u1(p + 1); + v = code_get_s1(p + 2); + } + else { + i = code_get_u2(p + 1); + v = code_get_s2(p + 3); + iswide = false; + nextp = p+5; + } + OP2I(opcode, i, v); + } + break; + + /* wider index for loading, storing and incrementing */ + + case JAVA_WIDE: + iswide = true; + nextp = p + 1; + break; + + /*********************** managing arrays **************************/ + + case JAVA_NEWARRAY: + OP2I(ICMD_CHECKASIZE, 0, 0); + switch (code_get_s1(p+1)) { + case 4: + BUILTIN1((functionptr)builtin_newarray_boolean, TYPE_ADR); + break; + case 5: + BUILTIN1((functionptr)builtin_newarray_char, TYPE_ADR); + break; + case 6: + BUILTIN1((functionptr)builtin_newarray_float, TYPE_ADR); + break; + case 7: + BUILTIN1((functionptr)builtin_newarray_double, TYPE_ADR); + break; + case 8: + BUILTIN1((functionptr)builtin_newarray_byte, TYPE_ADR); + break; + case 9: + BUILTIN1((functionptr)builtin_newarray_short, TYPE_ADR); + break; + case 10: + BUILTIN1((functionptr)builtin_newarray_int, TYPE_ADR); + break; + case 11: + BUILTIN1((functionptr)builtin_newarray_long, TYPE_ADR); + break; + default: panic("Invalid array-type to create"); + } + break; + + case JAVA_ANEWARRAY: + OP2I(ICMD_CHECKASIZE, 0, 0); + i = code_get_u2(p+1); + /* array or class type ? */ + if (class_constanttype (class, i) == CONSTANT_Arraydescriptor) { + LOADCONST_A(class_getconstant(class, i, + CONSTANT_Arraydescriptor)); + BUILTIN2((functionptr)builtin_newarray_array, TYPE_ADR); + } + else { + LOADCONST_A(class_getconstant(class, i, CONSTANT_Class)); + BUILTIN2((functionptr)builtin_anewarray, TYPE_ADR); + } + break; + + case JAVA_MULTIANEWARRAY: + isleafmethod=false; + i = code_get_u2(p+1); + { + int v = code_get_u1(p+3); + constant_arraydescriptor *desc = + class_getconstant (class, i, CONSTANT_Arraydescriptor); + OP2A(opcode, v, desc); + } + break; + + case JAVA_IFEQ: + case JAVA_IFLT: + case JAVA_IFLE: + case JAVA_IFNE: + case JAVA_IFGT: + case JAVA_IFGE: + case JAVA_IFNULL: + case JAVA_IFNONNULL: + case JAVA_IF_ICMPEQ: + case JAVA_IF_ICMPNE: + case JAVA_IF_ICMPLT: + case JAVA_IF_ICMPGT: + case JAVA_IF_ICMPLE: + case JAVA_IF_ICMPGE: + case JAVA_IF_ACMPEQ: + case JAVA_IF_ACMPNE: + case JAVA_GOTO: + case JAVA_JSR: + i = p + code_get_s2(p+1); + bound_check(i); + block_insert(i); + blockend = true; + OP1(opcode, i); + break; + case JAVA_GOTO_W: + case JAVA_JSR_W: + i = p + code_get_s4(p+1); + bound_check(i); + block_insert(i); + blockend = true; + OP1(opcode, i); + break; + + case JAVA_RET: + if (!iswide) + i = code_get_u1(p+1); + else { + i = code_get_u2(p+1); + nextp = p+3; + iswide = false; + } + blockend = true; + OP1(opcode, i); + break; + + case JAVA_IRETURN: + case JAVA_LRETURN: + case JAVA_FRETURN: + case JAVA_DRETURN: + case JAVA_ARETURN: + case JAVA_RETURN: + blockend = true; + OP(opcode); + break; + + case JAVA_ATHROW: + blockend = true; + OP(opcode); + break; + + + /**************** table jumps *****************/ + + case JAVA_LOOKUPSWITCH: + { + s4 num, j; + + blockend = true; + nextp = ALIGN((p + 1), 4); + OP2A(opcode, 0, jcode + nextp); + + /* default target */ + + j = p + code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + bound_check(j); + block_insert(j); + + /* number of pairs */ + + num = code_get_u4(nextp); + *((s4*)(jcode + nextp)) = num; + nextp += 4; + + for (i = 0; i < num; i++) { + + /* value */ + + j = code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + + /* target */ + + j = p + code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + bound_check(j); + block_insert(j); + } + + break; + } + + + case JAVA_TABLESWITCH: + { + s4 num, j; + + blockend = true; + nextp = ALIGN((p + 1), 4); + OP2A(opcode, 0, jcode + nextp); + + /* default target */ + + j = p + code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + bound_check(j); + block_insert(j); + + /* lower bound */ + + j = code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + + /* upper bound */ + + num = code_get_s4(nextp); + *((s4*)(jcode + nextp)) = num; /* restore for little endian */ + nextp += 4; + + num -= j; + + for (i = 0; i <= num; i++) { + j = p + code_get_s4(nextp); + *((s4*)(jcode + nextp)) = j; /* restore for little endian */ + nextp += 4; + bound_check(j); + block_insert(j); + } + + break; + } + + + /************ load and store of object fields ********/ + + case JAVA_AASTORE: + BUILTIN3((functionptr) new_builtin_aastore, TYPE_VOID); + break; + + case JAVA_PUTSTATIC: + case JAVA_GETSTATIC: + i = code_get_u2(p + 1); + { + constant_FMIref *fr; + fieldinfo *fi; + fr = class_getconstant (class, i, CONSTANT_Fieldref); + fi = class_findfield (fr->class, fr->name, fr->descriptor); + compiler_addinitclass (fr->class); + OP2A(opcode, fi->type, &(fi->value)); + } + break; + case JAVA_PUTFIELD: + case JAVA_GETFIELD: + i = code_get_u2(p + 1); + { + constant_FMIref *fr; + fieldinfo *fi; + fr = class_getconstant (class, i, CONSTANT_Fieldref); + fi = class_findfield (fr->class, fr->name, fr->descriptor); + OP2I(opcode, fi->type, fi->offset); + } + break; + + + /*** method invocation ***/ + + case JAVA_INVOKESTATIC: + i = code_get_u2(p + 1); + { + constant_FMIref *mr; + methodinfo *mi; + + mr = class_getconstant (class, i, CONSTANT_Methodref); + mi = class_findmethod (mr->class, mr->name, mr->descriptor); + if (! (mi->flags & ACC_STATIC)) + panic ("Static/Nonstatic mismatch calling static method"); + descriptor2types(mi); + isleafmethod=false; + OP2A(opcode, mi->paramcount, mi); + } + break; + case JAVA_INVOKESPECIAL: + case JAVA_INVOKEVIRTUAL: + i = code_get_u2(p + 1); + { + constant_FMIref *mr; + methodinfo *mi; + + mr = class_getconstant (class, i, CONSTANT_Methodref); + mi = class_findmethod (mr->class, mr->name, mr->descriptor); + if (mi->flags & ACC_STATIC) + panic ("Static/Nonstatic mismatch calling static method"); + descriptor2types(mi); + isleafmethod=false; + OP2A(opcode, mi->paramcount, mi); + } + break; + case JAVA_INVOKEINTERFACE: + i = code_get_u2(p + 1); + { + constant_FMIref *mr; + methodinfo *mi; + + mr = class_getconstant (class, i, CONSTANT_InterfaceMethodref); + mi = class_findmethod (mr->class, mr->name, mr->descriptor); + if (mi->flags & ACC_STATIC) + panic ("Static/Nonstatic mismatch calling static method"); + descriptor2types(mi); + isleafmethod=false; + OP2A(opcode, mi->paramcount, mi); + } + break; + + /***** miscellaneous object operations ****/ + + case JAVA_NEW: + i = code_get_u2 (p+1); + LOADCONST_A(class_getconstant(class, i, CONSTANT_Class)); + BUILTIN1((functionptr) builtin_new, TYPE_ADR); + break; + + case JAVA_CHECKCAST: + i = code_get_u2(p+1); + + /* array type cast-check */ + if (class_constanttype (class, i) == CONSTANT_Arraydescriptor) { + LOADCONST_A(class_getconstant(class, i, CONSTANT_Arraydescriptor)); + BUILTIN2((functionptr) new_builtin_checkarraycast, TYPE_ADR); + } + else { /* object type cast-check */ + LOADCONST_A(class_getconstant(class, i, CONSTANT_Class)); + BUILTIN2((functionptr) new_builtin_checkcast, TYPE_ADR); + } + break; + + case JAVA_INSTANCEOF: + i = code_get_u2(p+1); + + /* array type cast-check */ + if (class_constanttype (class, i) == CONSTANT_Arraydescriptor) { + LOADCONST_A(class_getconstant(class, i, CONSTANT_Arraydescriptor)); + BUILTIN2((functionptr) builtin_arrayinstanceof, TYPE_INT); + } + else { /* object type cast-check */ + LOADCONST_A(class_getconstant(class, i, CONSTANT_Class)); + BUILTIN2((functionptr) builtin_instanceof, TYPE_INT); + } + break; + + case JAVA_MONITORENTER: +#ifdef USE_THREADS + if (checksync) { +#ifdef SOFTNULLPTRCHECK + if (checknull) { + BUILTIN1((functionptr) new_builtin_monitorenter, TYPE_VOID); + } + else { +/* BUILTIN1((functionptr) builtin_monitorenter, TYPE_VOID); */ + BUILTIN1((functionptr) new_builtin_monitorenter, TYPE_VOID); + } +#else + BUILTIN1((functionptr) builtin_monitorenter, TYPE_VOID); +#endif + } + else +#endif + { + OP(ICMD_NULLCHECKPOP); + } + break; + + case JAVA_MONITOREXIT: +#ifdef USE_THREADS + if (checksync) { + BUILTIN1((functionptr) builtin_monitorexit, TYPE_VOID); + } + else +#endif + { + OP(ICMD_POP); + } + break; + + /************** any other basic operation **********/ + + case JAVA_IDIV: + if (SUPPORT_DIVISION) { + OP(opcode); + } + else { + BUILTIN2((functionptr) new_builtin_idiv, TYPE_INT); + } + break; + + case JAVA_IREM: + if (SUPPORT_DIVISION) { + OP(opcode); + } + else { + BUILTIN2((functionptr) new_builtin_irem, TYPE_INT); + } + break; + + case JAVA_LDIV: + if (SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_MULDIV) { + OP(opcode); + } + else { + BUILTIN2((functionptr) new_builtin_ldiv, TYPE_LONG); + } + break; + + case JAVA_LREM: + if (SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_MULDIV) { + OP(opcode); + } + else { + BUILTIN2((functionptr) new_builtin_lrem, TYPE_LONG); + } + break; + + case JAVA_FREM: + BUILTIN2((functionptr) builtin_frem, TYPE_FLOAT); + break; + + case JAVA_DREM: + BUILTIN2((functionptr) builtin_drem, TYPE_DOUBLE); + break; + + case JAVA_F2I: + if (checkfloats) { + BUILTIN1((functionptr) builtin_f2i, TYPE_INT); + } + else { + OP(opcode); + } + break; + + case JAVA_F2L: + if (checkfloats) { + BUILTIN1((functionptr) builtin_f2l, TYPE_LONG); + } + else { + OP(opcode); + } + break; + + case JAVA_D2I: + if (checkfloats) { + BUILTIN1((functionptr) builtin_d2i, TYPE_INT); + } + else { + OP(opcode); + } + break; + + case JAVA_D2L: + if (checkfloats) { + BUILTIN1((functionptr) builtin_d2l, TYPE_LONG); + } + else { + OP(opcode); + } + break; + + case JAVA_BREAKPOINT: + panic("Illegal opcode Breakpoint encountered"); + break; + + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 209: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + case 216: + case 217: + case 218: + case 219: + case 220: + case 221: + case 222: + case 223: + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + case 231: + case 232: + case 233: + case 234: + case 235: + case 236: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: + case 248: + case 249: + case 250: + case 251: + case 252: + case 253: + case 254: + case 255: + printf("Illegal opcode %d at instr %d", opcode, ipc); + panic("encountered"); + break; + + default: + OP(opcode); + break; + + } /* end switch */ + + } /* end for */ + + if (p != jcodelength) + panic("Command-sequence crosses code-boundary"); + + if (!blockend) + panic("Code does not end with branch/return/athrow - stmt"); + + /* adjust block count if target 0 is not first intermediate instruction */ + + if (!block_index[0] || (block_index[0] > 1)) + b_count++; + + /* copy local to global variables */ + + instr_count = ipc; + block_count = b_count; + stack_count = s_count + block_count * maxstack; + + /* allocate stack table */ + + stack = DMNEW(stackelement, stack_count); + + { + basicblock *bptr; + + bptr = block = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ + + b_count = 0; + + /* additional block if target 0 is not first intermediate instruction */ + + if (!block_index[0] || (block_index[0] > 1)) { + bptr->ipc = 0; + bptr->mpc = -1; + bptr->flags = -1; + bptr->type = BBTYPE_STD; + bptr->branchrefs = NULL; + bptr++; + b_count++; + } + + /* allocate blocks */ + + for (p = 0; p < jcodelength; p++) + if (block_index[p] & 1) { + bptr->ipc = block_index[p] >> 1; + bptr->mpc = -1; + bptr->flags = -1; + bptr->type = BBTYPE_STD; + bptr->branchrefs = NULL; + block_index[p] = b_count; + bptr++; + b_count++; + } + + /* allocate additional block at end */ + + bptr->ipc = instr_count; + bptr->mpc = -1; + bptr->flags = -1; + bptr->type = BBTYPE_STD; + bptr->branchrefs = NULL; + } +} diff --git a/ncomp/nreg.c b/ncomp/nreg.c new file mode 100644 index 000000000..6b8bfc5f1 --- /dev/null +++ b/ncomp/nreg.c @@ -0,0 +1,976 @@ +/******************************* comp/reg.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + The register-manager. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/23 + +*******************************************************************************/ + +static varinfo5 *locals; +static varinfo5 *interfaces; + +static int intregsnum; /* absolute number of integer registers */ +static int floatregsnum; /* absolute number of float registers */ + +static int intreg_ret; /* register to return integer values */ +static int intreg_argnum; /* number of integer argument registers */ + +static int floatreg_ret; /* register for return float values */ +static int fltreg_argnum; /* number of float argument registers */ + + +static int *argintregs; /* scratch integer registers */ +static int *tmpintregs = NULL; /* scratch integer registers */ +static int *savintregs; /* saved integer registers */ +static int *argfltregs; /* scratch float registers */ +static int *tmpfltregs; /* scratch float registers */ +static int *savfltregs; /* saved float registers */ +static int *freetmpintregs; /* free scratch integer registers */ +static int *freesavintregs; /* free saved integer registers */ +static int *freetmpfltregs; /* free scratch float registers */ +static int *freesavfltregs; /* free saved float registers */ + +static int *freemem; /* free scratch memory */ +static int memuse; /* used memory count */ +static int ifmemuse; /* interface used memory count */ +static int maxmemuse; /* maximal used memory count (spills) */ +static int freememtop; /* free memory count */ + +static int tmpintregcnt; /* scratch integer register count */ +static int savintregcnt; /* saved integer register count */ +static int tmpfltregcnt; /* scratch float register count */ +static int savfltregcnt; /* saved float register count */ + +static int iftmpintregcnt; /* iface scratch integer register count */ +static int ifsavintregcnt; /* iface saved integer register count */ +static int iftmpfltregcnt; /* iface scratch float register count */ +static int ifsavfltregcnt; /* iface saved float register count */ + +static int tmpintreguse; /* used scratch integer register count */ +static int savintreguse; /* used saved integer register count */ +static int tmpfltreguse; /* used scratch float register count */ +static int savfltreguse; /* used saved float register count */ + +static int maxtmpintreguse; /* max used scratch int register count */ +static int maxsavintreguse; /* max used saved int register count */ +static int maxtmpfltreguse; /* max used scratch float register count */ +static int maxsavfltreguse; /* max used saved float register count */ + +static int freetmpinttop; /* free scratch integer register count */ +static int freesavinttop; /* free saved integer register count */ +static int freetmpflttop; /* free scratch float register count */ +static int freesavflttop; /* free saved float register count */ + +static int savedregs_num; /* total number of registers to be saved */ +static int arguments_num; /* size of parameter field in the stackframe */ + + + +/****************** function reg_init ****************************************** + + initialises the register-allocator + +*******************************************************************************/ + +static void reg_init() +{ + int n; + + if (!tmpintregs) { + + if (TYPE_INT != 0 || TYPE_ADR != 4) + panic ("JAVA-Basictypes have been changed"); + + intreg_argnum = 0; + tmpintregcnt = 0; + savintregcnt = 0; + + for (intregsnum = 0; nregdescint[intregsnum] != REG_END; intregsnum++) { + switch (nregdescint[intregsnum]) { + case REG_SAV: savintregcnt++; + break; + case REG_TMP: tmpintregcnt++; + break; + case REG_ARG: intreg_argnum++; + } + } + + argintregs = MNEW (int, intreg_argnum); + tmpintregs = MNEW (int, tmpintregcnt); + savintregs = MNEW (int, savintregcnt); + freetmpintregs = MNEW (int, tmpintregcnt); + freesavintregs = MNEW (int, savintregcnt); + + intreg_argnum = 0; + tmpintreguse = 0; + savintreguse = 0; + + for (n = 0; n < intregsnum; n++) { + switch (nregdescint[n]) { + case REG_RET: intreg_ret = n; + break; + case REG_SAV: savintregs[savintreguse++] = n; + break; + case REG_TMP: tmpintregs[tmpintreguse++] = n; + break; + case REG_ARG: argintregs[intreg_argnum++] = n; + break; + } + } + + + fltreg_argnum = 0; + tmpfltregcnt = 0; + savfltregcnt = 0; + + for (floatregsnum = 0; nregdescfloat[floatregsnum] != REG_END; floatregsnum++) { + switch (nregdescfloat[floatregsnum]) { + case REG_SAV: savfltregcnt++; + break; + case REG_TMP: tmpfltregcnt++; + break; + case REG_ARG: fltreg_argnum++; + break; + } + } + + argfltregs = MNEW (int, fltreg_argnum); + tmpfltregs = MNEW (int, tmpfltregcnt); + savfltregs = MNEW (int, savfltregcnt); + freetmpfltregs = MNEW (int, tmpfltregcnt); + freesavfltregs = MNEW (int, savfltregcnt); + + fltreg_argnum = 0; + tmpfltreguse = 0; + savfltreguse = 0; + + for (n = 0; n < floatregsnum; n++) { + switch (nregdescfloat[n]) { + case REG_RET: floatreg_ret = n; + break; + case REG_SAV: savfltregs[savfltreguse++] = n; + break; + case REG_TMP: tmpfltregs[tmpfltreguse++] = n; + break; + case REG_ARG: argfltregs[fltreg_argnum++] = n; + break; + } + } + + } + +} + + +/********************** function reg_close ************************************* + + releases all allocated space for registers + +*******************************************************************************/ + +static void reg_close () +{ + if (argintregs) MFREE (argintregs, int, intreg_argnum); + if (argfltregs) MFREE (argfltregs, int, fltreg_argnum); + if (tmpintregs) MFREE (tmpintregs, int, tmpintregcnt); + if (savintregs) MFREE (savintregs, int, savintregcnt); + if (tmpfltregs) MFREE (tmpfltregs, int, tmpfltregcnt); + if (savfltregs) MFREE (savfltregs, int, savfltregcnt); + + if (freetmpintregs) MFREE (freetmpintregs, int, tmpintregcnt); + if (freesavintregs) MFREE (freesavintregs, int, savintregcnt); + if (freetmpfltregs) MFREE (freetmpfltregs, int, tmpfltregcnt); + if (freesavfltregs) MFREE (freesavfltregs, int, savfltregcnt); +} + + +/****************** function local_init **************************************** + + initialises the local variable and interfaces table + +*******************************************************************************/ + +static void local_init() +{ + int i; + varinfo5 *v; + + freemem = DMNEW(int, maxstack); + locals = DMNEW(varinfo5, maxlocals); + interfaces = DMNEW(varinfo5, maxstack); + + for (v = locals, i = maxlocals; i > 0; v++, i--) { + v[0][TYPE_INT].type = -1; + v[0][TYPE_LNG].type = -1; + v[0][TYPE_FLT].type = -1; + v[0][TYPE_DBL].type = -1; + v[0][TYPE_ADR].type = -1; + } + + for (v = interfaces, i = maxstack; i > 0; v++, i--) { + v[0][TYPE_INT].type = -1; + v[0][TYPE_INT].flags = 0; + v[0][TYPE_LNG].type = -1; + v[0][TYPE_LNG].flags = 0; + v[0][TYPE_FLT].type = -1; + v[0][TYPE_FLT].flags = 0; + v[0][TYPE_DBL].type = -1; + v[0][TYPE_DBL].flags = 0; + v[0][TYPE_ADR].type = -1; + v[0][TYPE_ADR].flags = 0; + } +} + + +/************************* function interface_regalloc ***************************** + + allocates registers for all interface variables + +*******************************************************************************/ + +static void interface_regalloc () +{ + int s, t, saved; + int intalloc, fltalloc; + varinfo *v; + + /* allocate stack space for passing arguments to called methods */ + + if (arguments_num > intreg_argnum) + ifmemuse = arguments_num - intreg_argnum; + else + ifmemuse = 0; + + iftmpintregcnt = tmpintregcnt; + ifsavintregcnt = savintregcnt; + iftmpfltregcnt = tmpfltregcnt; + ifsavfltregcnt = savfltregcnt; + + for (s = 0; s < maxstack; s++) { + intalloc = -1; fltalloc = -1; + saved = (interfaces[s][TYPE_INT].flags | interfaces[s][TYPE_LNG].flags | + interfaces[s][TYPE_FLT].flags | interfaces[s][TYPE_DBL].flags | + interfaces[s][TYPE_ADR].flags) & SAVEDVAR; + for (t = TYPE_INT; t <= TYPE_ADR; t++) { + v = &interfaces[s][t]; + if (v->type >= 0) { + if (!saved) { + if (IS_FLT_DBL_TYPE(t)) { + if (fltalloc >= 0) { + v->flags |= interfaces[s][fltalloc].flags & INMEMORY; + v->regoff = interfaces[s][fltalloc].regoff; + } + else if (iftmpfltregcnt > 0) { + iftmpfltregcnt--; + v->regoff = tmpfltregs[iftmpfltregcnt]; + } + else if (ifsavfltregcnt > 0) { + ifsavfltregcnt--; + v->regoff = savfltregs[ifsavfltregcnt]; + } + else { + v->flags |= INMEMORY; + v->regoff = ifmemuse++; + } + fltalloc = t; + } + else { + if (intalloc >= 0) { + v->flags |= interfaces[s][intalloc].flags & INMEMORY; + v->regoff = interfaces[s][intalloc].regoff; + } + else if (iftmpintregcnt > 0) { + iftmpintregcnt--; + v->regoff = tmpintregs[iftmpintregcnt]; + } + else if (ifsavintregcnt > 0) { + ifsavintregcnt--; + v->regoff = savintregs[ifsavintregcnt]; + } + else { + v->flags |= INMEMORY; + v->regoff = ifmemuse++; + } + intalloc = t; + } + } + else { + if (IS_FLT_DBL_TYPE(t)) { + if (fltalloc >= 0) { + v->flags |= interfaces[s][fltalloc].flags & INMEMORY; + v->regoff = interfaces[s][fltalloc].regoff; + } + else if (ifsavfltregcnt > 0) { + ifsavfltregcnt--; + v->regoff = savfltregs[ifsavfltregcnt]; + } + else { + v->flags |= INMEMORY; + v->regoff = ifmemuse++; + } + fltalloc = t; + } + else { + if (intalloc >= 0) { + v->flags |= interfaces[s][intalloc].flags & INMEMORY; + v->regoff = interfaces[s][intalloc].regoff; + } + else if (ifsavintregcnt > 0) { + ifsavintregcnt--; + v->regoff = savintregs[ifsavintregcnt]; + } + else { + v->flags |= INMEMORY; + v->regoff = ifmemuse++; + } + intalloc = t; + } + } + } /* if (type >= 0) */ + } /* for t */ + } /* for s */ + maxmemuse = ifmemuse; + maxtmpintreguse = iftmpintregcnt; + maxsavintreguse = ifsavintregcnt; + maxtmpfltreguse = iftmpfltregcnt; + maxsavfltreguse = ifsavfltregcnt; +} + + +/************************* function local_regalloc ***************************** + + allocates registers for all local variables + +*******************************************************************************/ + +static void local_regalloc () +{ + int s, t; + int intalloc, fltalloc; + varinfo *v; + + if (isleafmethod) { + for (s = 0; s < maxlocals; s++) { + intalloc = -1; fltalloc = -1; + for (t = TYPE_INT; t <= TYPE_ADR; t++) { + v = &locals[s][t]; + if (v->type >= 0) { + if (IS_FLT_DBL_TYPE(t)) { + if (fltalloc >= 0) { + v->flags = locals[s][fltalloc].flags; + v->regoff = locals[s][fltalloc].regoff; + } + else if (s < fltreg_argnum) { + v->flags = 0; + v->regoff = argfltregs[s]; + } + else if (maxtmpfltreguse > 0) { + maxtmpfltreguse--; + v->flags = 0; + v->regoff = tmpfltregs[maxtmpfltreguse]; + } + else if (maxsavfltreguse > 0) { + maxsavfltreguse--; + v->flags = 0; + v->regoff = savfltregs[maxsavfltreguse]; + } + else { + v->flags = INMEMORY; + v->regoff = maxmemuse++; + } + fltalloc = t; + } + else { + if (intalloc >= 0) { + v->flags = locals[s][intalloc].flags; + v->regoff = locals[s][intalloc].regoff; + } + else if (s < intreg_argnum) { + v->flags = 0; + v->regoff = argintregs[s]; + } + else if (maxtmpintreguse > 0) { + maxtmpintreguse--; + v->flags = 0; + v->regoff = tmpintregs[maxtmpintreguse]; + } + else if (maxsavintreguse > 0) { + maxsavintreguse--; + v->flags = 0; + v->regoff = savintregs[maxsavintreguse]; + } + else { + v->flags = INMEMORY; + v->regoff = maxmemuse++; + } + intalloc = t; + } + } + } + } + return; + } + for (s = 0; s < maxlocals; s++) { + intalloc = -1; fltalloc = -1; + for (t=TYPE_INT; t<=TYPE_ADR; t++) { + v = &locals[s][t]; + if (v->type >= 0) { + if (IS_FLT_DBL_TYPE(t)) { + if (fltalloc >= 0) { + v->flags = locals[s][fltalloc].flags; + v->regoff = locals[s][fltalloc].regoff; + } + else if (maxsavfltreguse > 0) { + maxsavfltreguse--; + v->flags = 0; + v->regoff = savfltregs[maxsavfltreguse]; + } + else { + v->flags = INMEMORY; + v->regoff = maxmemuse++; + } + fltalloc = t; + } + else { + if (intalloc >= 0) { + v->flags = locals[s][intalloc].flags; + v->regoff = locals[s][intalloc].regoff; + } + else if (maxsavintreguse > 0) { + maxsavintreguse--; + v->flags = 0; + v->regoff = savintregs[maxsavintreguse]; + } + else { + v->flags = INMEMORY; + v->regoff = maxmemuse++; + } + intalloc = t; + } + } + } + } +} + + +static void reg_init_temp() +{ + freememtop = 0; + memuse = ifmemuse; + + freetmpinttop = 0; + freesavinttop = 0; + freetmpflttop = 0; + freesavflttop = 0; + tmpintreguse = iftmpintregcnt; + savintreguse = ifsavintregcnt; + tmpfltreguse = iftmpfltregcnt; + savfltreguse = ifsavfltregcnt; +} + + +#define reg_new_temp(s) if(s->varkind==TEMPVAR)reg_new_temp_func(s) + +static void reg_new_temp_func(stackptr s) +{ +if (s->flags & SAVEDVAR) { + if (IS_FLT_DBL_TYPE(s->type)) { + if (freesavflttop > 0) { + freesavflttop--; + s->regoff = freesavfltregs[freesavflttop]; + return; + } + else if (savfltreguse > 0) { + savfltreguse--; + if (savfltreguse < maxsavfltreguse) + maxsavfltreguse = savfltreguse; + s->regoff = savfltregs[savfltreguse]; + return; + } + } + else { + if (freesavinttop > 0) { + freesavinttop--; + s->regoff = freesavintregs[freesavinttop]; + return; + } + else if (savintreguse > 0) { + savintreguse--; + if (savintreguse < maxsavintreguse) + maxsavintreguse = savintreguse; + s->regoff = savintregs[savintreguse]; + return; + } + } + } +else { + if (IS_FLT_DBL_TYPE(s->type)) { + if (freetmpflttop > 0) { + freetmpflttop--; + s->regoff = freetmpfltregs[freetmpflttop]; + return; + } + else if (tmpfltreguse > 0) { + tmpfltreguse--; + if (tmpfltreguse < maxtmpfltreguse) + maxtmpfltreguse = tmpfltreguse; + s->regoff = tmpfltregs[tmpfltreguse]; + return; + } + } + else { + if (freetmpinttop > 0) { + freetmpinttop--; + s->regoff = freetmpintregs[freetmpinttop]; + return; + } + else if (tmpintreguse > 0) { + tmpintreguse--; + if (tmpintreguse < maxtmpintreguse) + maxtmpintreguse = tmpintreguse; + s->regoff = tmpintregs[tmpintreguse]; + return; + } + } + } +if (freememtop > 0) { + freememtop--; + s->regoff = freemem[freememtop]; + } +else { + s->regoff = memuse++; + if (memuse > maxmemuse) + maxmemuse = memuse; + } +s->flags |= INMEMORY; +} + + +#define reg_free_temp(s) if(s->varkind==TEMPVAR)reg_free_temp_func(s) + +static void reg_free_temp_func(stackptr s) +{ +if (s->flags & INMEMORY) + freemem[freememtop++] = s->regoff; +else if (IS_FLT_DBL_TYPE(s->type)) { + if (s->flags & SAVEDVAR) + freesavfltregs[freesavflttop++] = s->regoff; + else + freetmpfltregs[freetmpflttop++] = s->regoff; + } +else + if (s->flags & SAVEDVAR) + freesavintregs[freesavinttop++] = s->regoff; + else + freetmpintregs[freetmpinttop++] = s->regoff; +} + + +static void allocate_scratch_registers() +{ + int b_count; + int opcode, i, len; + stackptr src, dst; + instruction *iptr = instr; + basicblock *bptr; + + b_count = block_count; + bptr = block; + while (--b_count >= 0) { + if (bptr->flags >= BBREACHED) { + dst = bptr->instack; + reg_init_temp(); + i = bptr[0].ipc; + len = bptr[1].ipc - i; + iptr = &instr[i]; + while (--len >= 0) { + src = dst; + dst = iptr->dst; + opcode = iptr->opc; + switch (opcode) { + + /* pop 0 push 0 */ + + case ICMD_NOP: + case ICMD_CHECKASIZE: + case ICMD_IINC: + case ICMD_JSR: + case ICMD_RET: + case ICMD_RETURN: + case ICMD_GOTO: + break; + + /* pop 0 push 1 const */ + + case ICMD_ICONST: + case ICMD_LCONST: + case ICMD_FCONST: + case ICMD_DCONST: + case ICMD_ACONST: + + /* pop 0 push 1 load */ + + case ICMD_ILOAD: + case ICMD_LLOAD: + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + reg_new_temp(dst); + break; + + /* pop 2 push 1 */ + + case ICMD_IALOAD: + case ICMD_LALOAD: + case ICMD_FALOAD: + case ICMD_DALOAD: + case ICMD_AALOAD: + + case ICMD_BALOAD: + case ICMD_CALOAD: + case ICMD_SALOAD: + reg_free_temp(src); + reg_free_temp(src->prev); + reg_new_temp(dst); + break; + + /* pop 3 push 0 */ + + case ICMD_IASTORE: + case ICMD_LASTORE: + case ICMD_FASTORE: + case ICMD_DASTORE: + case ICMD_AASTORE: + + case ICMD_BASTORE: + case ICMD_CASTORE: + case ICMD_SASTORE: + reg_free_temp(src); + reg_free_temp(src->prev); + reg_free_temp(src->prev->prev); + break; + + /* pop 1 push 0 store */ + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + + /* pop 1 push 0 */ + + case ICMD_POP: + + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_FRETURN: + case ICMD_DRETURN: + case ICMD_ARETURN: + + case ICMD_ATHROW: + + case ICMD_PUTSTATIC: + + /* pop 1 push 0 branch */ + + case ICMD_IFNULL: + case ICMD_IFNONNULL: + + case ICMD_IFEQ: + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFGE: + case ICMD_IFGT: + case ICMD_IFLE: + + case ICMD_IF_LEQ: + case ICMD_IF_LNE: + case ICMD_IF_LLT: + case ICMD_IF_LGE: + case ICMD_IF_LGT: + case ICMD_IF_LLE: + + /* pop 1 push 0 table branch */ + + case ICMD_TABLESWITCH: + case ICMD_LOOKUPSWITCH: + + case ICMD_NULLCHECKPOP: + case ICMD_MONITORENTER: + case ICMD_MONITOREXIT: + reg_free_temp(src); + break; + + /* pop 2 push 0 branch */ + + case ICMD_IF_ICMPEQ: + case ICMD_IF_ICMPNE: + case ICMD_IF_ICMPLT: + case ICMD_IF_ICMPGE: + case ICMD_IF_ICMPGT: + case ICMD_IF_ICMPLE: + + case ICMD_IF_LCMPEQ: + case ICMD_IF_LCMPNE: + case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPGE: + case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPLE: + + case ICMD_IF_ACMPEQ: + case ICMD_IF_ACMPNE: + + /* pop 2 push 0 */ + + case ICMD_POP2: + + case ICMD_PUTFIELD: + reg_free_temp(src); + reg_free_temp(src->prev); + break; + + /* pop 0 push 1 dup */ + + case ICMD_DUP: + reg_new_temp(dst); + break; + + /* pop 0 push 2 dup */ + + case ICMD_DUP2: + reg_new_temp(dst->prev); + reg_new_temp(dst); + break; + + /* pop 2 push 3 dup */ + + case ICMD_DUP_X1: + reg_new_temp(dst->prev->prev); + reg_new_temp(dst->prev); + reg_new_temp(dst); + reg_free_temp(src); + reg_free_temp(src->prev); + break; + + /* pop 3 push 4 dup */ + + case ICMD_DUP_X2: + reg_new_temp(dst->prev->prev->prev); + reg_new_temp(dst->prev->prev); + reg_new_temp(dst->prev); + reg_new_temp(dst); + reg_free_temp(src); + reg_free_temp(src->prev); + reg_free_temp(src->prev->prev); + break; + + /* pop 3 push 5 dup */ + + case ICMD_DUP2_X1: + reg_new_temp(dst->prev->prev->prev->prev); + reg_new_temp(dst->prev->prev->prev); + reg_new_temp(dst->prev->prev); + reg_new_temp(dst->prev); + reg_new_temp(dst); + reg_free_temp(src); + reg_free_temp(src->prev); + reg_free_temp(src->prev->prev); + break; + + /* pop 4 push 6 dup */ + + case ICMD_DUP2_X2: + reg_new_temp(dst->prev->prev->prev->prev->prev); + reg_new_temp(dst->prev->prev->prev->prev); + reg_new_temp(dst->prev->prev->prev); + reg_new_temp(dst->prev->prev); + reg_new_temp(dst->prev); + reg_new_temp(dst); + reg_free_temp(src); + reg_free_temp(src->prev); + reg_free_temp(src->prev->prev); + reg_free_temp(src->prev->prev->prev); + break; + + /* pop 2 push 2 swap */ + + case ICMD_SWAP: + reg_new_temp(dst->prev); + reg_new_temp(dst); + reg_free_temp(src); + reg_free_temp(src->prev); + break; + + /* pop 2 push 1 */ + + case ICMD_IADD: + case ICMD_ISUB: + case ICMD_IMUL: + case ICMD_IDIV: + case ICMD_IREM: + + case ICMD_ISHL: + case ICMD_ISHR: + case ICMD_IUSHR: + case ICMD_IAND: + case ICMD_IOR: + case ICMD_IXOR: + + case ICMD_LADD: + case ICMD_LSUB: + case ICMD_LMUL: + case ICMD_LDIV: + case ICMD_LREM: + + case ICMD_LOR: + case ICMD_LAND: + case ICMD_LXOR: + + case ICMD_LSHL: + case ICMD_LSHR: + case ICMD_LUSHR: + + case ICMD_FADD: + case ICMD_FSUB: + case ICMD_FMUL: + case ICMD_FDIV: + case ICMD_FREM: + + case ICMD_DADD: + case ICMD_DSUB: + case ICMD_DMUL: + case ICMD_DDIV: + case ICMD_DREM: + + case ICMD_LCMP: + case ICMD_FCMPL: + case ICMD_FCMPG: + case ICMD_DCMPL: + case ICMD_DCMPG: + reg_free_temp(src); + reg_free_temp(src->prev); + reg_new_temp(dst); + break; + + /* pop 1 push 1 */ + + case ICMD_IADDCONST: + case ICMD_ISUBCONST: + case ICMD_IMULCONST: + case ICMD_IANDCONST: + case ICMD_IORCONST: + case ICMD_IXORCONST: + case ICMD_ISHLCONST: + case ICMD_ISHRCONST: + case ICMD_IUSHRCONST: + + case ICMD_LADDCONST: + case ICMD_LSUBCONST: + case ICMD_LMULCONST: + case ICMD_LANDCONST: + case ICMD_LORCONST: + case ICMD_LXORCONST: + case ICMD_LSHLCONST: + case ICMD_LSHRCONST: + case ICMD_LUSHRCONST: + + case ICMD_INEG: + case ICMD_INT2BYTE: + case ICMD_INT2CHAR: + case ICMD_INT2SHORT: + case ICMD_LNEG: + case ICMD_FNEG: + case ICMD_DNEG: + + case ICMD_I2L: + case ICMD_I2F: + case ICMD_I2D: + case ICMD_L2I: + case ICMD_L2F: + case ICMD_L2D: + case ICMD_F2I: + case ICMD_F2L: + case ICMD_F2D: + case ICMD_D2I: + case ICMD_D2L: + case ICMD_D2F: + + case ICMD_CHECKCAST: + + case ICMD_ARRAYLENGTH: + case ICMD_INSTANCEOF: + + case ICMD_NEWARRAY: + case ICMD_ANEWARRAY: + + case ICMD_GETFIELD: + reg_free_temp(src); + reg_new_temp(dst); + break; + + /* pop 0 push 1 */ + + case ICMD_GETSTATIC: + + case ICMD_NEW: + + reg_new_temp(dst); + break; + + /* pop many push any */ + + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKESTATIC: + case ICMD_INVOKEINTERFACE: + { + i = iptr->op1; + while (--i >= 0) { + reg_free_temp(src); + src = src->prev; + } + if (((methodinfo*)iptr->val.a)->returntype != TYPE_VOID) + reg_new_temp(dst); + break; + } + + case ICMD_BUILTIN3: + reg_free_temp(src); + src = src->prev; + case ICMD_BUILTIN2: + reg_free_temp(src); + src = src->prev; + case ICMD_BUILTIN1: + reg_free_temp(src); + src = src->prev; + if (iptr->op1 != TYPE_VOID) + reg_new_temp(dst); + break; + + case ICMD_MULTIANEWARRAY: + i = iptr->op1; + while (--i >= 0) { + reg_free_temp(src); + src = src->prev; + } + reg_new_temp(dst); + break; + + default: + printf("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr)); + panic("Missing ICMD code during register allocation"); + } /* switch */ + iptr++; + } /* while instructions */ + } /* if */ + bptr++; + } /* while blocks */ +} diff --git a/ncomp/nstack.c b/ncomp/nstack.c new file mode 100644 index 000000000..eeeeacbe5 --- /dev/null +++ b/ncomp/nstack.c @@ -0,0 +1,1498 @@ +/****************************** ncomp/nstack.c ********************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Parser for JavaVM to intermediate code translation + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/18 + +*******************************************************************************/ + + +#ifdef STATISTICS +#define COUNT(cnt) cnt++ +#else +#define COUNT(cnt) +#endif + +#define STACKRESET {curstack=0;stackdepth=0;} + +#define TYPEPANIC {show_icmd_method();panic("Stack type mismatch");} +#define CURKIND curstack->varkind +#define CURTYPE curstack->type + +#define NEWSTACK(s,v,n) {new->prev=curstack;new->type=s;new->flags=0;\ + new->varkind=v;new->varnum=n;curstack=new;new++;} +#define NEWSTACKn(s,n) NEWSTACK(s,UNDEFVAR,n) +#define NEWSTACK0(s) NEWSTACK(s,UNDEFVAR,0) +#define NEWXSTACK {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=0;} + +#define SETDST {iptr->dst=curstack;} +#define POP(s) {if(s!=curstack->type){TYPEPANIC;}\ + if(curstack->varkind==UNDEFVAR)curstack->varkind=TEMPVAR;\ + curstack=curstack->prev;} +#define POPANY {if(curstack->varkind==UNDEFVAR)curstack->varkind=TEMPVAR;\ + curstack=curstack->prev;} +#define COPY(s,d) {(d)->flags=0;(d)->type=(s)->type;\ + (d)->varkind=(s)->varkind;(d)->varnum=(s)->varnum;} + +#define CONST(s) {NEWSTACKn(s,stackdepth);SETDST;stackdepth++;} +#define LOAD(s,v,n) {NEWSTACK(s,v,n);SETDST;stackdepth++;} +#define STORE(s) {POP(s);SETDST;stackdepth--;} +#define OP1_0(s) {POP(s);SETDST;stackdepth--;} +#define OP1_0ANY {POPANY;SETDST;stackdepth--;} +#define OP0_1(s) {NEWSTACKn(s,stackdepth);SETDST;stackdepth++;} +#define OP1_1(s,d) {POP(s);NEWSTACKn(d,stackdepth-1);SETDST;} +#define OP2_0(s) {POP(s);POP(s);SETDST;stackdepth-=2;} +#define OPTT2_0(t,b){POP(t);POP(b);SETDST;stackdepth-=2;} +#define OP2_1(s) {POP(s);POP(s);NEWSTACKn(s,stackdepth-2);SETDST;stackdepth--;} +#define OP2IAT_1(s) {POP(TYPE_INT);POP(TYPE_ADR);NEWSTACKn(s,stackdepth-2);\ + SETDST;stackdepth--;} +#define OP2IT_1(s) {POP(TYPE_INT);POP(s);NEWSTACKn(s,stackdepth-2);\ + SETDST;stackdepth--;} +#define OPTT2_1(s,d){POP(s);POP(s);NEWSTACKn(d,stackdepth-2);SETDST;stackdepth--;} +#define OP2_2(s) {POP(s);POP(s);NEWSTACKn(s,stackdepth-2);\ + NEWSTACKn(s,stackdepth-1);SETDST;} +#define OP3TIA_0(s) {POP(s);POP(TYPE_INT);POP(TYPE_ADR);SETDST;stackdepth-=3;} +#define OP3_0(s) {POP(s);POP(s);POP(s);SETDST;stackdepth-=3;} +#define POPMANY(i) {stackdepth-=i;while(--i>=0){POPANY;}SETDST;} +#define DUP {NEWSTACK(CURTYPE,CURKIND,curstack->varnum);SETDST;\ + stackdepth++;} +#define SWAP {COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\ + new[0].prev=curstack;new[1].prev=new;\ + curstack=new+1;new+=2;SETDST;} +#define DUP_X1 {COPY(curstack,new);COPY(curstack,new+2);POPANY;\ + COPY(curstack,new+1);POPANY;new[0].prev=curstack;\ + new[1].prev=new;new[2].prev=new+1;\ + curstack=new+2;new+=3;SETDST;stackdepth++;} +#define DUP2_X1 {COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\ + COPY(curstack,new);COPY(curstack,new+3);POPANY;\ + COPY(curstack,new+2);POPANY;new[0].prev=curstack;\ + new[1].prev=new;new[2].prev=new+1;\ + new[3].prev=new+2;new[4].prev=new+3;\ + curstack=new+4;new+=5;SETDST;stackdepth+=2;} +#define DUP_X2 {COPY(curstack,new);COPY(curstack,new+3);POPANY;\ + COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\ + new[0].prev=curstack;new[1].prev=new;\ + new[2].prev=new+1;new[3].prev=new+2;\ + curstack=new+3;new+=4;SETDST;stackdepth++;} +#define DUP2_X2 {COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\ + COPY(curstack,new);COPY(curstack,new+4);POPANY;\ + COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\ + new[0].prev=curstack;new[1].prev=new;\ + new[2].prev=new+1;new[3].prev=new+2;\ + new[4].prev=new+3;new[5].prev=new+4;\ + curstack=new+5;new+=6;SETDST;stackdepth+=2;} + +#define COPYCURSTACK(copy) {\ + int d;\ + stackptr s;\ + if(curstack){\ + s=curstack;\ + new+=stackdepth;\ + d=stackdepth;\ + copy=new;\ + while(s){\ + copy--;d--;\ + copy->prev=copy-1;\ + copy->type=s->type;\ + copy->flags=0;\ + copy->varkind=STACKVAR;\ + copy->varnum=d;\ + s=s->prev;\ + }\ + copy->prev=NULL;\ + copy=new-1;\ + }\ + else\ + copy=NULL;\ +} + + +#define BBEND(s,i){\ + i=stackdepth-1;\ + copy=s;\ + while(copy){\ + if((copy->varkind==STACKVAR)&&(copy->varnum>i))\ + copy->varkind=TEMPVAR;\ + else {\ + copy->varkind=STACKVAR;\ + copy->varnum=i;\ + }\ + interfaces[i][copy->type].type = copy->type;\ + interfaces[i][copy->type].flags |= copy->flags;\ + i--;copy=copy->prev;\ + }\ + i=bptr->indepth-1;\ + copy=bptr->instack;\ + while(copy){\ + interfaces[i][copy->type].type = copy->type;\ + if(copy->varkind==STACKVAR){\ + if (copy->flags & SAVEDVAR)\ + interfaces[i][copy->type].flags |= SAVEDVAR;\ + }\ + i--;copy=copy->prev;\ + }\ +} + + +#define MARKREACHED(b,c) {\ + if(b->flags<0)\ + {COPYCURSTACK(c);b->flags=0;b->instack=c;b->indepth=stackdepth;}\ + else {stackptr s=curstack;stackptr t=b->instack;\ + if(b->indepth!=stackdepth)\ + {show_icmd_method();panic("Stack depth mismatch");}\ + while(s){if (s->type!=t->type)\ + TYPEPANIC\ + s=s->prev;t=t->prev;\ + }\ + }\ +} + + +static void show_icmd_method(); + +static void analyse_stack() +{ + int b_count; + int stackdepth; + stackptr curstack, new, copy; + int opcode, i, len, loops; + int superblockend, repeat, deadcode; + instruction *iptr = instr; + basicblock *bptr, *tbptr; + s4 *s4ptr; + + arguments_num = 0; + new = stack; + loops = 0; + block[0].flags = BBREACHED; + block[0].instack = 0; + block[0].indepth = 0; + + for (i = 0; i < exceptiontablelength; i++) { + bptr = &block[block_index[extable[i].handlerpc]]; + bptr->flags = BBREACHED; + bptr->type = BBTYPE_EXH; + bptr->instack = new; + bptr->indepth = 1; + STACKRESET; + NEWXSTACK; + } + + do { + loops++; + b_count = block_count; + bptr = block; + superblockend = true; + repeat = false; + STACKRESET; + deadcode = true; + while (--b_count >= 0) { + if (superblockend && (bptr->flags < BBREACHED)) + repeat = true; + else if (bptr->flags <= BBREACHED) { + if (superblockend) + stackdepth = bptr->indepth; + else if (bptr->flags < BBREACHED) { + COPYCURSTACK(copy); + bptr->instack = copy; + bptr->indepth = stackdepth; + } + else if (bptr->indepth != stackdepth) { + show_icmd_method(); + panic("Stack depth mismatch"); + + } + curstack = bptr->instack; + deadcode = false; + superblockend = false; + bptr->flags = BBFINISHED; + i = bptr[0].ipc; + len = bptr[1].ipc - i; + iptr = &instr[i]; + while (--len >= 0) { + opcode = iptr->opc; + switch (opcode) { + + /* pop 0 push 0 */ + + case ICMD_NOP: + case ICMD_CHECKASIZE: + SETDST; + break; + case ICMD_RET: + locals[iptr->op1][TYPE_ADR].type = TYPE_ADR; + case ICMD_RETURN: + COUNT(count_pcmd_return); + SETDST; + superblockend = true; + break; + + /* pop 0 push 1 const */ + + case ICMD_ICONST: + COUNT(count_pcmd_load); + if (len > 0) { + switch (iptr[1].opc) { + case ICMD_IADD: + iptr[0].opc = ICMD_IADDCONST; +icmd_iconst_tail: + iptr[1].opc = ICMD_NOP; + OP1_1(TYPE_INT,TYPE_INT); + COUNT(count_pcmd_op); + break; + case ICMD_ISUB: + iptr[0].opc = ICMD_ISUBCONST; + goto icmd_iconst_tail; + case ICMD_IMUL: + iptr[0].opc = ICMD_IMULCONST; + goto icmd_iconst_tail; + case ICMD_IAND: + iptr[0].opc = ICMD_IANDCONST; + goto icmd_iconst_tail; + case ICMD_IOR: + iptr[0].opc = ICMD_IORCONST; + goto icmd_iconst_tail; + case ICMD_IXOR: + iptr[0].opc = ICMD_IXORCONST; + goto icmd_iconst_tail; + case ICMD_ISHL: + iptr[0].opc = ICMD_ISHLCONST; + goto icmd_iconst_tail; + case ICMD_ISHR: + iptr[0].opc = ICMD_ISHRCONST; + goto icmd_iconst_tail; + case ICMD_IUSHR: + iptr[0].opc = ICMD_IUSHRCONST; + goto icmd_iconst_tail; + case ICMD_IF_ICMPEQ: + iptr[0].opc = ICMD_IFEQ; +icmd_if_icmp_tail: + iptr[0].op1 = iptr[1].op1; + iptr[1].opc = ICMD_NOP; + OP1_0(TYPE_INT); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + COUNT(count_pcmd_bra); + break; + case ICMD_IF_ICMPLT: + iptr[0].opc = ICMD_IFLT; + goto icmd_if_icmp_tail; + case ICMD_IF_ICMPLE: + iptr[0].opc = ICMD_IFLE; + goto icmd_if_icmp_tail; + case ICMD_IF_ICMPNE: + iptr[0].opc = ICMD_IFNE; + goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGT: + iptr[0].opc = ICMD_IFGT; + goto icmd_if_icmp_tail; + case ICMD_IF_ICMPGE: + iptr[0].opc = ICMD_IFGE; + goto icmd_if_icmp_tail; + default: + CONST(TYPE_INT); + } + } + else + CONST(TYPE_INT); + break; + case ICMD_LCONST: + COUNT(count_pcmd_load); + if (len > 0) { + switch (iptr[1].opc) { + case ICMD_LADD: + iptr[0].opc = ICMD_LADDCONST; +icmd_lconst_tail: + iptr[1].opc = ICMD_NOP; + OP1_1(TYPE_LNG,TYPE_LNG); + COUNT(count_pcmd_op); + break; + case ICMD_LSUB: + iptr[0].opc = ICMD_LSUBCONST; + goto icmd_lconst_tail; + case ICMD_LMUL: + iptr[0].opc = ICMD_LMULCONST; + goto icmd_lconst_tail; + case ICMD_LAND: + iptr[0].opc = ICMD_LANDCONST; + goto icmd_lconst_tail; + case ICMD_LOR: + iptr[0].opc = ICMD_LORCONST; + goto icmd_lconst_tail; + case ICMD_LXOR: + iptr[0].opc = ICMD_LXORCONST; + goto icmd_lconst_tail; + case ICMD_LSHL: + iptr[0].opc = ICMD_LSHLCONST; + goto icmd_lconst_tail; + case ICMD_LSHR: + iptr[0].opc = ICMD_LSHRCONST; + goto icmd_lconst_tail; + case ICMD_LUSHR: + iptr[0].opc = ICMD_LUSHRCONST; + goto icmd_lconst_tail; + case ICMD_LCMP: + if ((len > 1) && (iptr[2].val.i == 0)) { + switch (iptr[2].opc) { + case ICMD_IFEQ: + iptr[0].opc = ICMD_IF_LEQ; +icmd_lconst_lcmp_tail: + iptr[0].op1 = iptr[2].op1; + iptr[1].opc = ICMD_NOP; + iptr[2].opc = ICMD_NOP; + OP1_0(TYPE_LNG); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + COUNT(count_pcmd_bra); + COUNT(count_pcmd_op); + break; + case ICMD_IFNE: + iptr[0].opc = ICMD_IF_LNE; + goto icmd_lconst_lcmp_tail; + case ICMD_IFLT: + iptr[0].opc = ICMD_IF_LLT; + goto icmd_lconst_lcmp_tail; + case ICMD_IFGT: + iptr[0].opc = ICMD_IF_LGT; + goto icmd_lconst_lcmp_tail; + case ICMD_IFLE: + iptr[0].opc = ICMD_IF_LLE; + goto icmd_lconst_lcmp_tail; + case ICMD_IFGE: + iptr[0].opc = ICMD_IF_LGE; + goto icmd_lconst_lcmp_tail; + default: + CONST(TYPE_LNG); + } /* switch (iptr[2].opc) */ + } /* if (iptr[2].val.i == 0) */ + else + CONST(TYPE_LNG); + break; + default: + CONST(TYPE_LNG); + } + } + else + CONST(TYPE_LNG); + break; + case ICMD_FCONST: + COUNT(count_pcmd_load); + CONST(TYPE_FLT); + break; + case ICMD_DCONST: + COUNT(count_pcmd_load); + CONST(TYPE_DBL); + break; + case ICMD_ACONST: + COUNT(count_pcmd_load); + CONST(TYPE_ADR); + break; + + /* pop 0 push 1 load */ + + case ICMD_ILOAD: + case ICMD_LLOAD: + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + COUNT(count_load_instruction); + i = opcode-ICMD_ILOAD; + locals[iptr->op1][i].type = i; + LOAD(i, LOCALVAR, iptr->op1); + break; + + /* pop 2 push 1 */ + + case ICMD_IALOAD: + case ICMD_LALOAD: + case ICMD_FALOAD: + case ICMD_DALOAD: + case ICMD_AALOAD: + COUNT(count_check_null); + COUNT(count_check_bound); + COUNT(count_pcmd_mem); + OP2IAT_1(opcode-ICMD_IALOAD); + break; + + case ICMD_BALOAD: + case ICMD_CALOAD: + case ICMD_SALOAD: + COUNT(count_check_null); + COUNT(count_check_bound); + COUNT(count_pcmd_mem); + OP2IAT_1(TYPE_INT); + break; + + /* pop 0 push 0 iinc */ + + case ICMD_IINC: +#ifdef STATISTICS + i = stackdepth; + if (i >= 10) + count_store_depth[10]++; + else + count_store_depth[i]++; +#endif + copy = curstack; + i = stackdepth - 1; + while (copy) { + if ((copy->varkind == LOCALVAR) && + (copy->varnum == curstack->varnum)) { + copy->varkind = TEMPVAR; + copy->varnum = i; + } + i--; + copy = copy->prev; + } + SETDST; + break; + + /* pop 1 push 0 store */ + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + i = opcode-ICMD_ISTORE; + locals[iptr->op1][i].type = i; +#ifdef STATISTICS + count_pcmd_store++; + i = new - curstack; + if (i >= 20) + count_store_length[20]++; + else + count_store_length[i]++; + i = stackdepth - 1; + if (i >= 10) + count_store_depth[10]++; + else + count_store_depth[i]++; +#endif + copy = curstack->prev; + i = stackdepth - 2; + while (copy) { + if ((copy->varkind == LOCALVAR) && + (copy->varnum == curstack->varnum)) { + copy->varkind = TEMPVAR; + copy->varnum = i; + } + i--; + copy = copy->prev; + } + if ((new - curstack) == 1) { + curstack->varkind = LOCALVAR; + curstack->varnum = iptr->op1; + }; + STORE(opcode-ICMD_ISTORE); + break; + + /* pop 3 push 0 */ + + case ICMD_IASTORE: + case ICMD_LASTORE: + case ICMD_FASTORE: + case ICMD_DASTORE: + case ICMD_AASTORE: + COUNT(count_check_null); + COUNT(count_check_bound); + COUNT(count_pcmd_mem); + OP3TIA_0(opcode-ICMD_IASTORE); + break; + case ICMD_BASTORE: + case ICMD_CASTORE: + case ICMD_SASTORE: + COUNT(count_check_null); + COUNT(count_check_bound); + COUNT(count_pcmd_mem); + OP3TIA_0(TYPE_INT); + break; + + /* pop 1 push 0 */ + + case ICMD_POP: + OP1_0ANY; + break; + + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_FRETURN: + case ICMD_DRETURN: + case ICMD_ARETURN: + COUNT(count_pcmd_return); + OP1_0(opcode-ICMD_IRETURN); + superblockend = true; + break; + + case ICMD_ATHROW: + COUNT(count_check_null); + OP1_0(TYPE_ADR); + STACKRESET; + SETDST; + superblockend = true; + break; + + case ICMD_PUTSTATIC: + COUNT(count_pcmd_mem); + OP1_0(iptr->op1); + break; + + /* pop 1 push 0 branch */ + + case ICMD_IFNULL: + case ICMD_IFNONNULL: + COUNT(count_pcmd_bra); + OP1_0(TYPE_ADR); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + break; + + case ICMD_IFEQ: + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFGE: + case ICMD_IFGT: + case ICMD_IFLE: + COUNT(count_pcmd_bra); + OP1_0(TYPE_INT); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + break; + + /* pop 0 push 0 branch */ + + case ICMD_GOTO: + COUNT(count_pcmd_bra); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + SETDST; + superblockend = true; + break; + + /* pop 1 push 0 table branch */ + + case ICMD_TABLESWITCH: + COUNT(count_pcmd_table); + OP1_0(TYPE_INT); + s4ptr = iptr->val.a; + tbptr = block + block_index[*s4ptr++]; /* default */ + MARKREACHED(tbptr, copy); + i = *s4ptr++; /* low */ + i = *s4ptr++ - i + 1; /* high */ + while (--i >= 0) { + tbptr = block + block_index[*s4ptr++]; + MARKREACHED(tbptr, copy); + } + SETDST; + superblockend = true; + break; + + /* pop 1 push 0 table branch */ + + case ICMD_LOOKUPSWITCH: + COUNT(count_pcmd_table); + OP1_0(TYPE_INT); + s4ptr = iptr->val.a; + tbptr = block + block_index[*s4ptr++]; /* default */ + MARKREACHED(tbptr, copy); + i = *s4ptr++; /* count */ + while (--i >= 0) { + tbptr = block + block_index[s4ptr[1]]; + MARKREACHED(tbptr, copy); + s4ptr += 2; + } + SETDST; + superblockend = true; + break; + + case ICMD_NULLCHECKPOP: + case ICMD_MONITORENTER: + COUNT(count_check_null); + case ICMD_MONITOREXIT: + OP1_0(TYPE_ADR); + break; + + /* pop 2 push 0 branch */ + + case ICMD_IF_ICMPEQ: + case ICMD_IF_ICMPNE: + case ICMD_IF_ICMPLT: + case ICMD_IF_ICMPGE: + case ICMD_IF_ICMPGT: + case ICMD_IF_ICMPLE: + COUNT(count_pcmd_bra); + OP2_0(TYPE_INT); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + break; + + case ICMD_IF_ACMPEQ: + case ICMD_IF_ACMPNE: + COUNT(count_pcmd_bra); + OP2_0(TYPE_ADR); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + break; + + /* pop 2 push 0 */ + + case ICMD_PUTFIELD: + COUNT(count_check_null); + COUNT(count_pcmd_mem); + OPTT2_0(iptr->op1,TYPE_ADR); + break; + + case ICMD_POP2: + if (! IS_2_WORD_TYPE(curstack->type)) { + OP1_0ANY; /* second pop */ + } + else + iptr->opc = ICMD_POP; + OP1_0ANY; + break; + + /* pop 0 push 1 dup */ + + case ICMD_DUP: + COUNT(count_dup_instruction); + DUP; + break; + + case ICMD_DUP2: + if (IS_2_WORD_TYPE(curstack->type)) { + iptr->opc = ICMD_DUP; + DUP; + } + else { + copy = curstack; + NEWSTACK(copy[-1].type, copy[-1].varkind, + copy[-1].varnum); + NEWSTACK(copy[ 0].type, copy[ 0].varkind, + copy[ 0].varnum); + SETDST; + stackdepth+=2; + } + break; + + /* pop 2 push 3 dup */ + + case ICMD_DUP_X1: + DUP_X1; + break; + + case ICMD_DUP2_X1: + if (IS_2_WORD_TYPE(curstack->type)) { + iptr->opc = ICMD_DUP_X1; + DUP_X1; + } + else { + DUP2_X1; + } + break; + + /* pop 3 push 4 dup */ + + case ICMD_DUP_X2: + if (IS_2_WORD_TYPE(curstack[-1].type)) { + iptr->opc = ICMD_DUP_X1; + DUP_X1; + } + else { + DUP_X2; + } + break; + + case ICMD_DUP2_X2: + if (IS_2_WORD_TYPE(curstack->type)) { + if (IS_2_WORD_TYPE(curstack[-1].type)) { + iptr->opc = ICMD_DUP_X1; + DUP_X1; + } + else { + iptr->opc = ICMD_DUP_X2; + DUP_X2; + } + } + else + if (IS_2_WORD_TYPE(curstack[-2].type)) { + iptr->opc = ICMD_DUP2_X1; + DUP2_X1; + } + else { + DUP2_X2; + } + break; + + /* pop 2 push 2 swap */ + + case ICMD_SWAP: + SWAP; + break; + + /* pop 2 push 1 */ + + case ICMD_IADD: + case ICMD_ISUB: + case ICMD_IMUL: + case ICMD_IDIV: + case ICMD_IREM: + + case ICMD_ISHL: + case ICMD_ISHR: + case ICMD_IUSHR: + case ICMD_IAND: + case ICMD_IOR: + case ICMD_IXOR: + COUNT(count_pcmd_op); + OP2_1(TYPE_INT); + break; + + case ICMD_LADD: + case ICMD_LSUB: + case ICMD_LMUL: + case ICMD_LDIV: + case ICMD_LREM: + + case ICMD_LOR: + case ICMD_LAND: + case ICMD_LXOR: + COUNT(count_pcmd_op); + OP2_1(TYPE_LNG); + break; + + case ICMD_LSHL: + case ICMD_LSHR: + case ICMD_LUSHR: + COUNT(count_pcmd_op); + OP2IT_1(TYPE_LNG); + break; + + case ICMD_FADD: + case ICMD_FSUB: + case ICMD_FMUL: + case ICMD_FDIV: + case ICMD_FREM: + COUNT(count_pcmd_op); + OP2_1(TYPE_FLT); + break; + + case ICMD_DADD: + case ICMD_DSUB: + case ICMD_DMUL: + case ICMD_DDIV: + case ICMD_DREM: + COUNT(count_pcmd_op); + OP2_1(TYPE_DBL); + break; + + case ICMD_LCMP: + COUNT(count_pcmd_op); + if ((len > 0) && (iptr[1].val.i == 0)) { + switch (iptr[1].opc) { + case ICMD_IFEQ: + iptr[0].opc = ICMD_IF_LCMPEQ; +icmd_lcmp_if_tail: + iptr[0].op1 = iptr[1].op1; + iptr[1].opc = ICMD_NOP; + OP2_0(TYPE_LNG); + tbptr = block + block_index[iptr->op1]; + MARKREACHED(tbptr, copy); + COUNT(count_pcmd_bra); + break; + case ICMD_IFNE: + iptr[0].opc = ICMD_IF_LCMPNE; + goto icmd_lcmp_if_tail; + case ICMD_IFLT: + iptr[0].opc = ICMD_IF_LCMPLT; + goto icmd_lcmp_if_tail; + case ICMD_IFGT: + iptr[0].opc = ICMD_IF_LCMPGT; + goto icmd_lcmp_if_tail; + case ICMD_IFLE: + iptr[0].opc = ICMD_IF_LCMPLE; + goto icmd_lcmp_if_tail; + case ICMD_IFGE: + iptr[0].opc = ICMD_IF_LCMPGE; + goto icmd_lcmp_if_tail; + default: + OPTT2_1(TYPE_LNG, TYPE_INT); + } + } + else + OPTT2_1(TYPE_LNG, TYPE_INT); + break; + case ICMD_FCMPL: + case ICMD_FCMPG: + COUNT(count_pcmd_op); + OPTT2_1(TYPE_FLT, TYPE_INT); + break; + case ICMD_DCMPL: + case ICMD_DCMPG: + COUNT(count_pcmd_op); + OPTT2_1(TYPE_DBL, TYPE_INT); + break; + + /* pop 1 push 1 */ + + case ICMD_INEG: + case ICMD_INT2BYTE: + case ICMD_INT2CHAR: + case ICMD_INT2SHORT: + COUNT(count_pcmd_op); + OP1_1(TYPE_INT, TYPE_INT); + break; + case ICMD_LNEG: + COUNT(count_pcmd_op); + OP1_1(TYPE_LNG, TYPE_LNG); + break; + case ICMD_FNEG: + COUNT(count_pcmd_op); + OP1_1(TYPE_FLT, TYPE_FLT); + break; + case ICMD_DNEG: + COUNT(count_pcmd_op); + OP1_1(TYPE_DBL, TYPE_DBL); + break; + + case ICMD_I2L: + COUNT(count_pcmd_op); + OP1_1(TYPE_INT, TYPE_LNG); + break; + case ICMD_I2F: + COUNT(count_pcmd_op); + OP1_1(TYPE_INT, TYPE_FLT); + break; + case ICMD_I2D: + COUNT(count_pcmd_op); + OP1_1(TYPE_INT, TYPE_DBL); + break; + case ICMD_L2I: + COUNT(count_pcmd_op); + OP1_1(TYPE_LNG, TYPE_INT); + break; + case ICMD_L2F: + COUNT(count_pcmd_op); + OP1_1(TYPE_LNG, TYPE_FLT); + break; + case ICMD_L2D: + COUNT(count_pcmd_op); + OP1_1(TYPE_LNG, TYPE_DBL); + break; + case ICMD_F2I: + COUNT(count_pcmd_op); + OP1_1(TYPE_FLT, TYPE_INT); + break; + case ICMD_F2L: + COUNT(count_pcmd_op); + OP1_1(TYPE_FLT, TYPE_LNG); + break; + case ICMD_F2D: + COUNT(count_pcmd_op); + OP1_1(TYPE_FLT, TYPE_DBL); + break; + case ICMD_D2I: + COUNT(count_pcmd_op); + OP1_1(TYPE_DBL, TYPE_INT); + break; + case ICMD_D2L: + COUNT(count_pcmd_op); + OP1_1(TYPE_DBL, TYPE_LNG); + break; + case ICMD_D2F: + COUNT(count_pcmd_op); + OP1_1(TYPE_DBL, TYPE_FLT); + break; + + case ICMD_CHECKCAST: + OP1_1(TYPE_ADR, TYPE_ADR); + break; + + case ICMD_ARRAYLENGTH: + case ICMD_INSTANCEOF: + OP1_1(TYPE_ADR, TYPE_INT); + break; + + case ICMD_NEWARRAY: + case ICMD_ANEWARRAY: + OP1_1(TYPE_INT, TYPE_ADR); + break; + + case ICMD_GETFIELD: + COUNT(count_check_null); + COUNT(count_pcmd_mem); + OP1_1(TYPE_ADR, iptr->op1); + break; + + /* pop 0 push 1 */ + + case ICMD_GETSTATIC: + COUNT(count_pcmd_mem); + OP0_1(iptr->op1); + break; + + case ICMD_NEW: + OP0_1(TYPE_ADR); + break; + + case ICMD_JSR: + OP0_1(TYPE_ADR); + tbptr = block + block_index[iptr->op1]; + tbptr->type=BBTYPE_SBR; + MARKREACHED(tbptr, copy); + OP1_0ANY; + break; + + /* pop many push any */ + + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKEINTERFACE: + case ICMD_INVOKESTATIC: + COUNT(count_pcmd_met); + { + methodinfo *m = iptr->val.a; + if (m->flags & ACC_STATIC) + {COUNT(count_check_null);} + i = iptr->op1; + if (i > arguments_num) + arguments_num = i; + copy = curstack; + while (--i >= 0) { + if (! (copy->flags & SAVEDVAR)) { + copy->varkind = ARGVAR; + copy->varnum = i; + } + copy = copy->prev; + } + while (copy) { + copy->flags |= SAVEDVAR; + copy = copy->prev; + } + i = iptr->op1; + POPMANY(i); + if (m->returntype != TYPE_VOID) { + OP0_1(m->returntype); + } + break; + } + + case ICMD_BUILTIN3: + if (! (curstack->flags & SAVEDVAR)) { + curstack->varkind = ARGVAR; + curstack->varnum = 2; + } + OP1_0ANY; + case ICMD_BUILTIN2: + if (! (curstack->flags & SAVEDVAR)) { + curstack->varkind = ARGVAR; + curstack->varnum = 1; + } + OP1_0ANY; + case ICMD_BUILTIN1: + if (! (curstack->flags & SAVEDVAR)) { + curstack->varkind = ARGVAR; + curstack->varnum = 0; + } + OP1_0ANY; + copy = curstack; + while (copy) { + copy->flags |= SAVEDVAR; + copy = copy->prev; + } + if (iptr->op1 != TYPE_VOID) + OP0_1(iptr->op1); + break; + + case ICMD_MULTIANEWARRAY: + i = iptr->op1; + if ((i + intreg_argnum) > arguments_num) + arguments_num = i + intreg_argnum; + copy = curstack; + while (--i >= 0) { + if (! (copy->flags & SAVEDVAR)) { + copy->varkind = ARGVAR; + copy->varnum = i + intreg_argnum; + } + copy = copy->prev; + } + while (copy) { + copy->flags |= SAVEDVAR; + copy = copy->prev; + } + i = iptr->op1; + POPMANY(i); + OP0_1(TYPE_ADR); + break; + + default: + printf("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr)); + panic("Missing ICMD code during stack analysis"); + } /* switch */ + iptr++; + } /* while instructions */ + bptr->outstack = curstack; + bptr->outdepth = stackdepth; + BBEND(curstack, i); + } /* if */ + else + superblockend = true; + bptr++; + } /* while blocks */ + } while (repeat && ! deadcode); + +#ifdef STATISTICS + if (block_count > count_max_basic_blocks) + count_max_basic_blocks = block_count; + count_basic_blocks += block_count; + if (block[block_count].ipc > count_max_javainstr) + count_max_javainstr = block[block_count].ipc; + count_javainstr += block[block_count].ipc; + if (stack_count > count_upper_bound_new_stack) + count_upper_bound_new_stack = stack_count; + if ((new - stack) > count_max_new_stack) + count_max_new_stack = (new - stack); + + b_count = block_count; + bptr = block; + while (--b_count >= 0) { + if (bptr->flags > BBREACHED) { + if (bptr->indepth >= 10) + count_block_stack[10]++; + else + count_block_stack[bptr->indepth]++; + len = bptr[1].ipc - bptr[0].ipc; + if (len <= 10) + count_block_size_distribution[len - 1]++; + else if (len <= 12) + count_block_size_distribution[10]++; + else if (len <= 14) + count_block_size_distribution[11]++; + else if (len <= 16) + count_block_size_distribution[12]++; + else if (len <= 18) + count_block_size_distribution[13]++; + else if (len <= 20) + count_block_size_distribution[14]++; + else if (len <= 25) + count_block_size_distribution[15]++; + else if (len <= 30) + count_block_size_distribution[16]++; + else + count_block_size_distribution[17]++; + } + bptr++; + } + + if (loops == 1) + count_analyse_iterations[0]++; + else if (loops == 2) + count_analyse_iterations[1]++; + else if (loops == 3) + count_analyse_iterations[2]++; + else if (loops == 4) + count_analyse_iterations[3]++; + else + count_analyse_iterations[4]++; + + if (block_count <= 5) + count_method_bb_distribution[0]++; + else if (block_count <= 10) + count_method_bb_distribution[1]++; + else if (block_count <= 15) + count_method_bb_distribution[2]++; + else if (block_count <= 20) + count_method_bb_distribution[3]++; + else if (block_count <= 30) + count_method_bb_distribution[4]++; + else if (block_count <= 40) + count_method_bb_distribution[5]++; + else if (block_count <= 50) + count_method_bb_distribution[6]++; + else if (block_count <= 75) + count_method_bb_distribution[7]++; + else + count_method_bb_distribution[8]++; +#endif +} + + +static void print_stack(stackptr s) { + int i, j; + stackptr t; + + i = maxstack; + t = s; + + while (t) { + i--; + t = t->prev; + } + j = maxstack - i; + while (--i >= 0) + printf(" "); + while (s) { + j--; + if (s->flags & SAVEDVAR) + switch (s->varkind) { + case TEMPVAR: + if (s->flags & INMEMORY) + printf(" m%02d", s->regoff); + else + printf(" r%02d", s->regoff); + break; + case STACKVAR: + printf(" s%02d", s->varnum); + break; + case LOCALVAR: + printf(" l%02d", s->varnum); + break; + case ARGVAR: + printf(" a%02d", s->varnum); + break; + default: + printf(" !%02d", j); + } + else + switch (s->varkind) { + case TEMPVAR: + if (s->flags & INMEMORY) + printf(" M%02d", s->regoff); + else + printf(" R%02d", s->regoff); + break; + case STACKVAR: + printf(" S%02d", s->varnum); + break; + case LOCALVAR: + printf(" L%02d", s->varnum); + break; + case ARGVAR: + printf(" A%02d", s->varnum); + break; + default: + printf(" ?%02d", j); + } + s = s->prev; + } +} + + +static void print_reg(stackptr s) { + if (s) { + if (s->flags & SAVEDVAR) + switch (s->varkind) { + case TEMPVAR: + if (s->flags & INMEMORY) + printf(" tm%02d", s->regoff); + else + printf(" tr%02d", s->regoff); + break; + case STACKVAR: + printf(" s %02d", s->varnum); + break; + case LOCALVAR: + printf(" l %02d", s->varnum); + break; + case ARGVAR: + printf(" a %02d", s->varnum); + break; + default: + printf(" ! %02d", s->varnum); + } + else + switch (s->varkind) { + case TEMPVAR: + if (s->flags & INMEMORY) + printf(" Tm%02d", s->regoff); + else + printf(" Tr%02d", s->regoff); + break; + case STACKVAR: + printf(" S %02d", s->varnum); + break; + case LOCALVAR: + printf(" L %02d", s->varnum); + break; + case ARGVAR: + printf(" A %02d", s->varnum); + break; + default: + printf(" ? %02d", s->varnum); + } + } + else + printf(" "); + +} + + +static char *builtin_name(functionptr bptr) +{ + builtin_descriptor *bdesc = builtin_desc; + while ((bdesc->bptr != NULL) && (bdesc->bptr != bptr)) + bdesc++; + return bdesc->name; +} + + +static void show_icmd_method() +{ + int b, i, j; + int deadcode; + s4 *s4ptr; + + printf("\n"); + unicode_fprint(stdout, class->name); + printf("."); + unicode_fprint(stdout, method->name); + printf(" "); + unicode_fprint(stdout, method->descriptor); + printf ("\n\nMax locals: %d\n", (int) maxlocals); + printf ("Max stack: %d\n", (int) maxstack); + + printf ("Exceptions:\n"); + for (i = 0; i < exceptiontablelength; i++) { + printf(" L%03d ... ", block_index[extable[i].startpc]); + printf("L%03d = ", block_index[extable[i].endpc]); + printf("L%03d\n", block_index[extable[i].handlerpc]); + } + + printf ("Local Table:\n"); + for (i = 0; i < maxlocals; i++) { + printf(" %3d: ", i); + for (j = TYPE_INT; j <= TYPE_ADR; j++) + if (locals[i][j].type >= 0) { + printf(" (%d) ", j); + if (locals[i][j].flags) + printf("m"); + else + printf("r"); + printf("%2d", locals[i][j].regoff); + } + printf("\n"); + } + printf("\n"); + + printf ("Interface Table:\n"); + for (i = 0; i < maxstack; i++) { + if ((interfaces[i][0].type >= 0) || (interfaces[i][1].type >= 0) || + (interfaces[i][2].type >= 0) || (interfaces[i][3].type >= 0) || + (interfaces[i][4].type >= 0)) { + printf(" %3d: ", i); + for (j = TYPE_INT; j <= TYPE_ADR; j++) + if (interfaces[i][j].type >= 0) { + printf(" (%d) ", j); + if (interfaces[i][j].flags & SAVEDVAR) + printf("s"); + else + printf("t"); + if (interfaces[i][j].flags & INMEMORY) + printf("m"); + else + printf("r"); + printf("%2d", interfaces[i][j].regoff); + } + printf("\n"); + } + } + printf("\n"); + for (b = 0; b < block_count; b++) { + deadcode = block[b].flags <= BBREACHED; + printf("["); + if (deadcode) + for (j = maxstack; j > 0; j--) + printf(" ? "); + else + print_stack(block[b].instack); + printf("] L%03d:\n", b); + for (i = block[b].ipc; i < block[b + 1].ipc; i++) { + printf("["); + if (deadcode) { + for (j = maxstack; j > 0; j--) + printf(" ? "); + } + else + print_stack(instr[i].dst); + printf("] %4d %s", i, icmd_names[instr[i].opc]); + switch ((int) instr[i].opc) { + case ICMD_IADDCONST: + case ICMD_ISUBCONST: + case ICMD_IMULCONST: + case ICMD_IANDCONST: + case ICMD_IORCONST: + case ICMD_IXORCONST: + case ICMD_ISHLCONST: + case ICMD_ISHRCONST: + case ICMD_IUSHRCONST: + case ICMD_ICONST: + case ICMD_GETFIELD: + case ICMD_PUTFIELD: + printf(" %d", instr[i].val.i); + break; + case ICMD_LADDCONST: + case ICMD_LSUBCONST: + case ICMD_LMULCONST: + case ICMD_LANDCONST: + case ICMD_LORCONST: + case ICMD_LXORCONST: + case ICMD_LSHLCONST: + case ICMD_LSHRCONST: + case ICMD_LUSHRCONST: + case ICMD_LCONST: + printf(" %ld", instr[i].val.l); + break; + case ICMD_FCONST: + printf(" %f", instr[i].val.f); + break; + case ICMD_DCONST: + printf(" %f", instr[i].val.d); + break; + case ICMD_ACONST: + case ICMD_PUTSTATIC: + case ICMD_GETSTATIC: + printf(" %p", instr[i].val.a); + break; + case ICMD_IINC: + printf(" %d + %d", instr[i].op1, instr[i].val.i); + break; + case ICMD_RET: + case ICMD_ILOAD: + case ICMD_LLOAD: + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + printf(" %d", instr[i].op1); + break; + case ICMD_NEW: + printf(" "); + unicode_fprint(stdout, + ((classinfo *) instr[i].val.a)->name); + break; + case ICMD_NEWARRAY: + switch (instr[i].op1) { + case 4: + printf(" boolean"); + break; + case 5: + printf(" char"); + break; + case 6: + printf(" float"); + break; + case 7: + printf(" double"); + break; + case 8: + printf(" byte"); + break; + case 9: + printf(" short"); + break; + case 10: + printf(" int"); + break; + case 11: + printf(" long"); + break; + } + break; + case ICMD_ANEWARRAY: + if (instr[i].op1) { + printf(" "); + unicode_fprint(stdout, + ((classinfo *) instr[i].val.a)->name); + } + break; + case ICMD_CHECKCAST: + case ICMD_INSTANCEOF: + if (instr[i].op1) { + printf(" "); + unicode_fprint(stdout, + ((classinfo *) instr[i].val.a)->name); + } + break; + case ICMD_BUILTIN3: + case ICMD_BUILTIN2: + case ICMD_BUILTIN1: + printf(" %s", builtin_name((functionptr) instr[i].val.a)); + break; + case ICMD_INVOKEVIRTUAL: + case ICMD_INVOKESPECIAL: + case ICMD_INVOKESTATIC: + case ICMD_INVOKEINTERFACE: + printf(" "); + unicode_fprint(stdout, + ((methodinfo *) instr[i].val.a)->class->name); + printf("."); + unicode_fprint(stdout, + ((methodinfo *) instr[i].val.a)->name); + break; + case ICMD_IFEQ: + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFGE: + case ICMD_IFGT: + case ICMD_IFLE: + case ICMD_IF_LEQ: + case ICMD_IF_LNE: + case ICMD_IF_LLT: + case ICMD_IF_LGE: + case ICMD_IF_LGT: + case ICMD_IF_LLE: + printf("(%d) L%03d", instr[i].val.i, block_index[instr[i].op1]); + break; + case ICMD_JSR: + case ICMD_GOTO: + case ICMD_IFNULL: + case ICMD_IFNONNULL: + case ICMD_IF_ICMPEQ: + case ICMD_IF_ICMPNE: + case ICMD_IF_ICMPLT: + case ICMD_IF_ICMPGE: + case ICMD_IF_ICMPGT: + case ICMD_IF_ICMPLE: + case ICMD_IF_LCMPEQ: + case ICMD_IF_LCMPNE: + case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPGE: + case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPLE: + case ICMD_IF_ACMPEQ: + case ICMD_IF_ACMPNE: + printf(" L%03d", block_index[instr[i].op1]); + break; + case ICMD_TABLESWITCH: + s4ptr = instr[i].val.a; + printf(" L%03d;", block_index[*s4ptr++]); /* default */ + j = *s4ptr++; /* low */ + j = *s4ptr++ - j; /* high */ + while (j >= 0) { + printf(" L%03d", block_index[*s4ptr++]); + j--; + } + break; + case ICMD_LOOKUPSWITCH: + s4ptr = instr[i].val.a; + printf(" L%d", block_index[*s4ptr++]); /* default */ + j = *s4ptr++; /* count */ + while (--j >= 0) { + printf(" L%03d", block_index[s4ptr[1]]); + s4ptr += 2; + } + break; + } + printf("\n"); + } + } +} diff --git a/ncomp/ntools.c b/ncomp/ntools.c new file mode 100644 index 000000000..ddedc4397 --- /dev/null +++ b/ncomp/ntools.c @@ -0,0 +1,170 @@ +/***************************** ncomp/ntools.c ********************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Ein paar zus"atzlich notwendige Funktionen, die sonst nirgends + hinpassen. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/03 + +*******************************************************************************/ + + +/***************** Funktion: compiler_addinitclass **************************** + + zum Eintragen einer Klasse in die Liste der noch zu initialisierenden + Klassen + +******************************************************************************/ + +static void compiler_addinitclass (classinfo *c) +{ + classinfo *cl; + + if (c->initialized) return; + + cl = chain_first(uninitializedclasses); + if (cl == c) + return; + + if (cl == class) + cl = chain_next(uninitializedclasses); + for (;;) { + if (cl == c) + return; + if (cl == NULL) { + if (runverbose) { + sprintf(logtext, "compiler_addinitclass: "); + unicode_sprint(logtext+strlen(logtext), c->name); + dolog(); + } + chain_addlast(uninitializedclasses, c); + return; + } + if (c < cl) { + if (runverbose) { + sprintf(logtext, "compiler_addinitclass: "); + unicode_sprint(logtext+strlen(logtext), c->name); + dolog(); + } + chain_addbefore(uninitializedclasses, c); + return; + } + cl = chain_next(uninitializedclasses); + } +} + + + +/***************** Hilfsfunktionen zum Decodieren des Bytecodes *************** + + lesen ein Datum des gew"unschten Typs aus dem Bytecode an der + angegebenen Stelle + +******************************************************************************/ + +#define code_get_u1(pos) jcode[pos] +#define code_get_s1(pos) ((s1)jcode[pos]) +#define code_get_u2(pos) ((((u2)jcode[pos])<<8)+jcode[pos+1]) +#define code_get_s2(pos) ((s2)((((u2)jcode[pos])<<8)+jcode[pos+1])) +#define code_get_u4(pos) ((((u4)jcode[pos])<<24)+(((u4)jcode[pos+1])<<16)+\ + (((u4)jcode[pos+2])<<8)+jcode[pos+3]) +#define code_get_s4(pos) ((s4)((((u4)jcode[pos])<<24)+(((u4)jcode[pos+1])<<16)+\ + (((u4)jcode[pos+2])<<8)+jcode[pos+3])) + + +/******************** Funktion: descriptor2types ***************************** + + Decodiert einen Methoddescriptor. + Beim Aufruf dieser Funktion MUSS (!!!) der Descriptor ein + gueltiges Format haben (wird eh vorher vom loader ueberprueft). + + Die Funktion erzeugt ein Array von integers (u2), in das die + Parametertypen eingetragen werden, und liefert einen Zeiger auf + das Array in einem Referenzparameter ('paramtypes') zur"uck. + Die L"ange dieses Arrays und der Methodenr"uckgabewert werden ebenfalls + in Referenzparametern zur"uckgeliefert. + + Der Parameter 'isstatic' gibt an (wenn true), dass kein zus"atzlicher + erster Eintrag f"ur den this-Zeiger in das Array eingetragen + werden soll (sonst wird er n"amlich automatisch erzeugt, mit dem + Typ TYPE_ADR). + +******************************************************************************/ + +static void descriptor2types (methodinfo *m) +{ + u1 *types, *tptr; + int pcount, c; + u2 *cptr; + + pcount = 0; + types = DMNEW (u1, m->descriptor->length); + + tptr = types; + if (!(m->flags & ACC_STATIC)) { + *tptr++ = TYPE_ADR; + pcount++; + } + + cptr = m->descriptor->text; + cptr++; + while ((c = *cptr++) != ')') { + pcount++; + switch (c) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': *tptr++ = TYPE_INT; + break; + case 'J': *tptr++ = TYPE_LNG; + break; + case 'F': *tptr++ = TYPE_FLT; + break; + case 'D': *tptr++ = TYPE_DBL; + break; + case 'L': *tptr++ = TYPE_ADR; + while (*cptr++ != ';'); + break; + case '[': *tptr++ = TYPE_ADR; + while (c == '[') + c = *cptr++; + if (c == 'L') + while (*cptr++ != ';') /* skip */; + break; + default: panic ("Ill formed methodtype-descriptor"); + } + } + + switch (*cptr) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': m->returntype = TYPE_INT; + break; + case 'J': m->returntype = TYPE_LNG; + break; + case 'F': m->returntype = TYPE_FLT; + break; + case 'D': m->returntype = TYPE_DBL; + break; + case '[': + case 'L': m->returntype = TYPE_ADR; + break; + case 'V': m->returntype = TYPE_VOID; + break; + + default: panic ("Ill formed methodtype-descriptor"); + } + + m->paramcount = pcount; + m->paramtypes = types; +} + diff --git a/newcomp.c b/newcomp.c new file mode 100644 index 000000000..dad147620 --- /dev/null +++ b/newcomp.c @@ -0,0 +1,437 @@ +/***************************** ncomp/ncomp.c *********************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties. + + Contains the functions which translates a JavaVM method into native code. + This is the new version of the compiler which is a lot faster and has new + exception handling schemes. The main function is new_comp. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/05 + +*******************************************************************************/ + +#include "signal.h" +#include "global.h" +#include "ncomp/ncomp.h" + +#include "loader.h" +#include "tables.h" +#include "builtin.h" +#include "native.h" +#include "asmpart.h" + +#include "threads/thread.h" + + +/*************************** global switches **********************************/ + +bool compileverbose = false; +bool showstack = false; +bool showdisassemble = false; +bool showintermediate = false; +int optimizelevel = 0; + +bool checkbounds = true; +bool checknull = true; +bool checkfloats = true; +bool checksync = true; + +bool getcompilingtime = false; +long compilingtime = 0; + +int has_ext_instr_set = 0; + +bool statistics = false; + +int count_jit_calls = 0; +int count_methods = 0; +int count_spills = 0; +int count_pcmd_activ = 0; +int count_pcmd_drop = 0; +int count_pcmd_zero = 0; +int count_pcmd_const_store = 0; +int count_pcmd_const_alu = 0; +int count_pcmd_const_bra = 0; +int count_pcmd_load = 0; +int count_pcmd_move = 0; +int count_load_instruction = 0; +int count_pcmd_store = 0; +int count_pcmd_store_comb = 0; +int count_dup_instruction = 0; +int count_pcmd_op = 0; +int count_pcmd_mem = 0; +int count_pcmd_met = 0; +int count_pcmd_bra = 0; +int count_pcmd_table = 0; +int count_pcmd_return = 0; +int count_pcmd_returnx = 0; +int count_check_null = 0; +int count_check_bound = 0; +int count_max_basic_blocks = 0; +int count_basic_blocks = 0; +int count_javainstr = 0; +int count_max_javainstr = 0; +int count_javacodesize = 0; +int count_javaexcsize = 0; +int count_calls = 0; +int count_tryblocks = 0; +int count_code_len = 0; +int count_data_len = 0; +int count_cstub_len = 0; +int count_nstub_len = 0; +int count_max_new_stack = 0; +int count_upper_bound_new_stack = 0; +static int count_block_stack_init[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int *count_block_stack = count_block_stack_init; +static int count_analyse_iterations_init[5] = {0, 0, 0, 0, 0}; +int *count_analyse_iterations = count_analyse_iterations_init; +static int count_method_bb_distribution_init[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +int *count_method_bb_distribution = count_method_bb_distribution_init; +static int count_block_size_distribution_init[18] = {0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int *count_block_size_distribution = count_block_size_distribution_init; +static int count_store_length_init[21] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int *count_store_length = count_store_length_init; +static int count_store_depth_init[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int *count_store_depth = count_store_depth_init; + + +/*********************** include compiler data types **************************/ + +#include "ncomp/ncompdef.h" + + +/*********************** global compiler variables ****************************/ + + /* data about the currently compiled method */ + +static classinfo *class; /* class the compiled method belongs to */ +static methodinfo *method; /* pointer to method info of compiled method */ +static unicode *descriptor; /* type descriptor of compiled method */ +static u2 mparamcount; /* number of parameters (incl. this) */ +static u1 *mparamtypes; /* types of all parameters (TYPE_INT, ...) */ +static u2 mreturntype; /* return type of method */ + +static int maxstack; /* maximal JavaVM stack size */ +static int maxlocals; /* maximal number of local JavaVM variables */ +static int jcodelength; /* length of JavaVM-codes */ +static u1 *jcode; /* pointer to start of JavaVM-code */ +static int exceptiontablelength;/* length of exception table */ +static exceptiontable *extable; /* pointer to start of exception table */ + +static int block_count; /* number of basic blocks */ +static basicblock *block; /* points to basic block array */ +static int *block_index; /* a table which contains for every byte of */ + /* JavaVM code a basic block index if at this */ + /* byte there is the start of a basic block */ + +static int instr_count; /* number of JavaVM instructions */ +static instruction *instr; /* points to intermediate code instructions */ + +static int stack_count; /* number of stack elements */ +static stackelement *stack; /* points to intermediate code instructions */ + +static bool isleafmethod; /* true if a method doesn't call subroutines */ + +/* list of all classes used by the compiled method which have to be */ +/* initialised (if not already done) before execution of this method */ + +static chain *uninitializedclasses; + + +/******************** include compiler subsystems *****************************/ + +#include "sysdep/ngen.h" /* code generator header file */ +#include "ncomp/ntools.c" /* compiler tool functions */ +#include "ncomp/mcode.c" /* code generation tool functions */ +#include "ncomp/nparse.c" /* parsing of JavaVM code */ +#include "ncomp/nreg.c" /* register allocation and support routines */ +#include "ncomp/nstack.c" /* analysing the stack operations */ +#include "sysdep/ngen.c" /* code generator */ +#include "sysdep/disass.c" /* disassembler (for debug purposes only) */ + + + + +/* dummy function, used when there is no JavaVM code available */ + +static void* do_nothing_function() +{ + return NULL; +} + + +/******************************************************************************* + + new_compile, new version of compiler, translates one method to machine code + +*******************************************************************************/ + +methodptr new_compile(methodinfo *m) +{ + int dumpsize; + long starttime = 0; + long stoptime = 0; + + /* if method has been already compiled return immediately */ + + count_jit_calls++; + + if (m->entrypoint) + return m->entrypoint; + + count_methods++; + + intsDisable(); /* disable interrupts */ + + + /* mark start of dump memory area */ + + dumpsize = dump_size (); + + /* measure time */ + + if (getcompilingtime) + starttime = getcputime(); + + /* if there is no javacode print error message and return empty method */ + + if (! m->jcode) { + sprintf(logtext, "No code given for: "); + unicode_sprint(logtext+strlen(logtext), m->class->name); + strcpy(logtext+strlen(logtext), "."); + unicode_sprint(logtext+strlen(logtext), m->name); + unicode_sprint(logtext+strlen(logtext), m->descriptor); + dolog(); + intsRestore(); /* enable interrupts again */ + return (methodptr) do_nothing_function; /* return empty method */ + } + + /* print log message for compiled method */ + + if (compileverbose) { + sprintf(logtext, "Compiling: "); + unicode_sprint(logtext+strlen(logtext), m->class->name); + strcpy(logtext+strlen(logtext), "."); + unicode_sprint(logtext+strlen(logtext), m->name); + unicode_sprint(logtext+strlen(logtext), m->descriptor); + dolog (); + } + + + /* initialisation of variables and subsystems */ + + isleafmethod = true; + + method = m; + class = m->class; + descriptor = m->descriptor; + maxstack = m->maxstack; + maxlocals = m->maxlocals; + jcodelength = m->jcodelength; + jcode = m->jcode; + exceptiontablelength = m->exceptiontablelength; + extable = m->exceptiontable; + +#ifdef STATISTICS + count_tryblocks += exceptiontablelength; + count_javacodesize += jcodelength + 18; + count_javaexcsize += exceptiontablelength * 8; +#endif + + /* initialise parameter type descriptor */ + + descriptor2types (m); + mreturntype = m->returntype; + mparamcount = m->paramcount; + mparamtypes = m->paramtypes; + + /* initialize class list with class the compiled method belongs to */ + + uninitializedclasses = chain_new(); + compiler_addinitclass (m->class); + + + /********************** call the compiler passes **************************/ + + reg_init(); + local_init(); + mcode_init(); + + if (runverbose) + allocate_literals(); + + parse(); + + analyse_stack(); + + interface_regalloc(); + + allocate_scratch_registers(); + + local_regalloc(); + + gen_mcode(); + + + /*********** Zwischendarstellungen auf Wunsch ausgeben **********/ + + if (showintermediate) + show_icmd_method(); + + if (showdisassemble) { + dseg_display((void*) (m->mcode)); + disassemble((void*) (m->mcode + dseglen), m->mcodelength - dseglen); + fflush(stdout); + } + + + /* release dump area */ + + dump_release (dumpsize); + + /* measure time */ + + if (getcompilingtime) { + stoptime = getcputime(); + compilingtime += (stoptime-starttime); + } + + /* initialize all used classes */ + /* because of reentrant code global variables are not allowed here */ + + { + chain *ul = uninitializedclasses; /* list of uninitialized classes */ + classinfo *c; /* single class */ + + while ((c = chain_first(ul)) != NULL) { + chain_remove (ul); + class_init (c); /* may again call the compiler */ + } + chain_free (ul); + } + + intsRestore(); /* enable interrupts again */ + + /* return pointer to the methods entry point */ + + return m -> entrypoint; +} + + +/************ functions for compiler initialisation and finalisation **********/ + +void ncomp_init () +{ + int i; + + has_ext_instr_set = ! has_no_x_instr_set(); + + for (i = 0; i < 256; i++) + stackreq[i] = 1; + + stackreq[JAVA_NOP] = 0; + stackreq[JAVA_ISTORE] = 0; + stackreq[JAVA_LSTORE] = 0; + stackreq[JAVA_FSTORE] = 0; + stackreq[JAVA_DSTORE] = 0; + stackreq[JAVA_ASTORE] = 0; + stackreq[JAVA_ISTORE_0] = 0; + stackreq[JAVA_ISTORE_1] = 0; + stackreq[JAVA_ISTORE_2] = 0; + stackreq[JAVA_ISTORE_3] = 0; + stackreq[JAVA_LSTORE_0] = 0; + stackreq[JAVA_LSTORE_1] = 0; + stackreq[JAVA_LSTORE_2] = 0; + stackreq[JAVA_LSTORE_3] = 0; + stackreq[JAVA_FSTORE_0] = 0; + stackreq[JAVA_FSTORE_1] = 0; + stackreq[JAVA_FSTORE_2] = 0; + stackreq[JAVA_FSTORE_3] = 0; + stackreq[JAVA_DSTORE_0] = 0; + stackreq[JAVA_DSTORE_1] = 0; + stackreq[JAVA_DSTORE_2] = 0; + stackreq[JAVA_DSTORE_3] = 0; + stackreq[JAVA_ASTORE_0] = 0; + stackreq[JAVA_ASTORE_1] = 0; + stackreq[JAVA_ASTORE_2] = 0; + stackreq[JAVA_ASTORE_3] = 0; + stackreq[JAVA_IASTORE] = 0; + stackreq[JAVA_LASTORE] = 0; + stackreq[JAVA_FASTORE] = 0; + stackreq[JAVA_DASTORE] = 0; + stackreq[JAVA_AASTORE] = 0; + stackreq[JAVA_BASTORE] = 0; + stackreq[JAVA_CASTORE] = 0; + stackreq[JAVA_SASTORE] = 0; + stackreq[JAVA_POP] = 0; + stackreq[JAVA_POP2] = 0; + stackreq[JAVA_IINC] = 0; + stackreq[JAVA_IFEQ] = 0; + stackreq[JAVA_IFNE] = 0; + stackreq[JAVA_IFLT] = 0; + stackreq[JAVA_IFGE] = 0; + stackreq[JAVA_IFGT] = 0; + stackreq[JAVA_IFLE] = 0; + stackreq[JAVA_IF_ICMPEQ] = 0; + stackreq[JAVA_IF_ICMPNE] = 0; + stackreq[JAVA_IF_ICMPLT] = 0; + stackreq[JAVA_IF_ICMPGE] = 0; + stackreq[JAVA_IF_ICMPGT] = 0; + stackreq[JAVA_IF_ICMPLE] = 0; + stackreq[JAVA_IF_ACMPEQ] = 0; + stackreq[JAVA_IF_ACMPNE] = 0; + stackreq[JAVA_GOTO] = 0; + stackreq[JAVA_RET] = 0; + stackreq[JAVA_TABLESWITCH] = 0; + stackreq[ICMD_LOOKUPSWITCH] = 0; + stackreq[JAVA_IRETURN] = 0; + stackreq[JAVA_LRETURN] = 0; + stackreq[JAVA_FRETURN] = 0; + stackreq[JAVA_DRETURN] = 0; + stackreq[JAVA_ARETURN] = 0; + stackreq[JAVA_RETURN] = 0; + stackreq[JAVA_PUTSTATIC] = 0; + stackreq[JAVA_PUTFIELD] = 0; + stackreq[JAVA_MONITORENTER] = 0; + stackreq[ICMD_MONITOREXIT] = 0; + stackreq[JAVA_WIDE] = 0; + stackreq[JAVA_IFNULL] = 0; + stackreq[JAVA_IFNONNULL] = 0; + stackreq[JAVA_GOTO_W] = 0; + stackreq[JAVA_BREAKPOINT] = 0; + + stackreq[JAVA_SWAP] = 2; + stackreq[JAVA_DUP2] = 2; + stackreq[JAVA_DUP_X1] = 3; + stackreq[JAVA_DUP_X2] = 4; + stackreq[JAVA_DUP2_X1] = 3; + stackreq[JAVA_DUP2_X2] = 4; + + for (i = 0; i < 256; i++) stdopdescriptors[i] = NULL; + + for (i = 0; i < sizeof(stdopdescriptortable)/sizeof(stdopdescriptor); i++) { + + if (stdopdescriptortable[i].isfloat && checkfloats) { + stdopdescriptortable[i].supported = false; + } + + stdopdescriptors[stdopdescriptortable[i].opcode] = + &(stdopdescriptortable[i]); + } + + init_exceptions(); +} + + +void ncomp_close() +{ +/* mcode_close(); */ +} + diff --git a/src/cacao/cacao.c b/src/cacao/cacao.c new file mode 100644 index 000000000..d91cfc830 --- /dev/null +++ b/src/cacao/cacao.c @@ -0,0 +1,750 @@ +/******************************* main.c **************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enthaelt die Funktion main() und die Variablen fuer die + globalen Optionen. + Dieser Modul erledigt folgende Aufgaben: + - Bearbeiten der command-line-options + - Aufrufen aller Initialisierungsroutinen + - Aufrufen des Classloaders + - Starten der main - Methode + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Andi Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/29 + +*******************************************************************************/ + +#include "global.h" + +#include "tables.h" +#include "compiler.h" +#include "ncomp/ncomp.h" +#include "loader.h" + +#include "asmpart.h" +#include "builtin.h" +#include "native.h" + +#include "threads/thread.h" /* schani */ + +bool compileall = false; +int newcompiler = true; +bool verbose = false; + +#ifndef USE_THREADS +void **stackbottom = 0; +#endif + + +/********************* interne Funktion: get_opt ***************************** + + liest die n"achste Option aus der Kommandozeile + +******************************************************************************/ + +#define OPT_DONE -1 +#define OPT_ERROR 0 +#define OPT_IGNORE 1 + +#define OPT_CLASSPATH 2 +#define OPT_D 3 +#define OPT_MS 4 +#define OPT_MX 5 +#define OPT_VERBOSE1 6 +#define OPT_VERBOSE 7 +#define OPT_VERBOSEGC 8 +#define OPT_VERBOSECALL 9 +#define OPT_IEEE 10 +#define OPT_SOFTNULL 11 +#define OPT_TIME 12 +#define OPT_STAT 13 +#define OPT_LOG 14 +#define OPT_CHECK 15 +#define OPT_LOAD 16 +#define OPT_METHOD 17 +#define OPT_SIGNATURE 18 +#define OPT_SHOW 19 +#define OPT_ALL 20 +#define OPT_OLD 21 + +struct { char *name; bool arg; int value; } opts[] = { + { "classpath", true, OPT_CLASSPATH }, + { "D", true, OPT_D }, + { "ms", true, OPT_MS }, + { "mx", true, OPT_MX }, + { "noasyncgc", false, OPT_IGNORE }, + { "noverify", false, OPT_IGNORE }, + { "oss", true, OPT_IGNORE }, + { "ss", true, OPT_IGNORE }, + { "v", false, OPT_VERBOSE1 }, + { "verbose", false, OPT_VERBOSE }, + { "verbosegc", false, OPT_VERBOSEGC }, + { "verbosecall", false, OPT_VERBOSECALL }, + { "ieee", false, OPT_IEEE }, + { "softnull", false, OPT_SOFTNULL }, + { "time", false, OPT_TIME }, + { "stat", false, OPT_STAT }, + { "log", true, OPT_LOG }, + { "c", true, OPT_CHECK }, + { "l", false, OPT_LOAD }, + { "m", true, OPT_METHOD }, + { "sig", true, OPT_SIGNATURE }, + { "s", true, OPT_SHOW }, + { "all", false, OPT_ALL }, + { "old", false, OPT_OLD }, + { NULL, false, 0 } +}; + +static int opt_ind = 1; +static char *opt_arg; + +static int get_opt (int argc, char **argv) +{ + char *a; + int i; + + if (opt_ind >= argc) return OPT_DONE; + + a = argv[opt_ind]; + if (a[0] != '-') return OPT_DONE; + + for (i=0; opts[i].name; i++) { + if (! opts[i].arg) { + if (strcmp(a+1, opts[i].name) == 0) { /* boolean option found */ + opt_ind++; + return opts[i].value; + } + } + else { + if (strcmp(a+1, opts[i].name) == 0) { /* parameter option found */ + opt_ind++; + if (opt_ind < argc) { + opt_arg = argv[opt_ind]; + opt_ind++; + return opts[i].value; + } + return OPT_ERROR; + } + else { + size_t l = strlen(opts[i].name); + if (strlen(a+1) > l) { + if (memcmp (a+1, opts[i].name, l)==0) { + opt_ind++; + opt_arg = a+1+l; + return opts[i].value; + } + } + } + } + } /* end for */ + + return OPT_ERROR; +} + + + + +/******************** interne Funktion: print_usage ************************ + +Gibt die richtige Aufrufsyntax des JavaVM-Compilers auf stdout aus. + +***************************************************************************/ + +static void print_usage() +{ + printf ("USAGE: cacao [options] classname [program arguments\n"); + printf ("Options:\n"); + printf (" -classpath path ...... specify a path to look for classes\n"); + printf (" -Dpropertyname=value . add an entry to the property list\n"); + printf (" -mx maxmem[k|m] ...... specify the size for the heap\n"); + printf (" -ms initmem[k|m] ..... specify the initial size for the heap\n"); + printf (" -v ................... write state-information\n"); + printf (" -verbose ............. write more information\n"); + printf (" -verbosegc ........... write message for each GC\n"); + printf (" -verbosecall ......... write message for each call\n"); + printf (" -ieee ................ use ieee compliant arithmetic\n"); + printf (" -softnull ............ use software nullpointer check\n"); + printf (" -time ................ measure the runtime\n"); + printf (" -stat ................ detailed compiler statistics\n"); + printf (" -log logfile ......... specify a name for the logfile\n"); + printf (" -c(heck) b(ounds...... don't check array bounds\n"); + printf (" s(ync) ...... don't check for synchronization\n"); + printf (" -l ................... don't start the class after loading\n"); + printf (" -all ................. compile all methods, no execution\n"); + printf (" -old ................. use old JIT compiler\n"); + printf (" -m ................... compile only a specific method\n"); + printf (" -sig ................. specify signature for a specific method\n"); + printf (" -s(how)m(ethods) ..... show all methods&fields of a class\n"); + printf (" c(onstants) ... show the constant pool\n"); + printf (" a(ssembler) ... show disassembled listing\n"); + printf (" s(tack) ....... show stack for every javaVM-command\n"); + printf (" i(ntermediate). show intermediate representation\n"); + printf (" u(nicode) ..... show the unicode - hash\n"); +} + + + +/***************************** Funktion: print_times ********************* + + gibt eine Aufstellung der verwendeten CPU-Zeit aus + +**************************************************************************/ + +static void print_times() +{ + long int totaltime = getcputime(); + long int runtime = totaltime - loadingtime - compilingtime; + + sprintf (logtext, "Time for loading classes: %ld secs, %ld millis", + loadingtime / 1000000, (loadingtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Time for compiling code: %ld secs, %ld millis", + compilingtime / 1000000, (compilingtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Time for running program: %ld secs, %ld millis", + runtime / 1000000, (runtime % 1000000) / 1000); + dolog(); + sprintf (logtext, "Total time: %ld secs, %ld millis", + totaltime / 1000000, (totaltime % 1000000) / 1000); + dolog(); +} + + + + + + +/***************************** Funktion: print_stats ********************* + + outputs detailed compiler statistics + +**************************************************************************/ + +static void print_stats() +{ + sprintf (logtext, "Number of JitCompiler Calls: %d", count_jit_calls); + dolog(); + sprintf (logtext, "Number of compiled Methods: %d", count_methods); + dolog(); + sprintf (logtext, "Number of max basic blocks per method: %d", count_max_basic_blocks); + dolog(); + sprintf (logtext, "Number of compiled basic blocks: %d", count_basic_blocks); + dolog(); + sprintf (logtext, "Number of max JavaVM-Instructions per method: %d", count_max_javainstr); + dolog(); + sprintf (logtext, "Number of compiled JavaVM-Instructions: %d", count_javainstr); + dolog(); + sprintf (logtext, "Size of compiled JavaVM-Instructions: %d(%d)", count_javacodesize, + count_javacodesize - count_methods * 18); + dolog(); + sprintf (logtext, "Size of compiled Exception Tables: %d", count_javaexcsize); + dolog(); + sprintf (logtext, "Value of extended instruction set var: %d", has_ext_instr_set); + dolog(); + sprintf (logtext, "Number of Alpha-Instructions: %d", count_code_len >> 2); + dolog(); + sprintf (logtext, "Number of Spills: %d", count_spills); + dolog(); + sprintf (logtext, "Number of Activ Pseudocommands: %5d", count_pcmd_activ); + dolog(); + sprintf (logtext, "Number of Drop Pseudocommands: %5d", count_pcmd_drop); + dolog(); + sprintf (logtext, "Number of Const Pseudocommands: %5d (zero:%5d)", count_pcmd_load, count_pcmd_zero); + dolog(); + sprintf (logtext, "Number of ConstAlu Pseudocommands: %5d (cmp: %5d, store:%5d)", count_pcmd_const_alu, count_pcmd_const_bra, count_pcmd_const_store); + dolog(); + sprintf (logtext, "Number of Move Pseudocommands: %5d", count_pcmd_move); + dolog(); + sprintf (logtext, "Number of Load Pseudocommands: %5d", count_load_instruction); + dolog(); + sprintf (logtext, "Number of Store Pseudocommands: %5d (combined: %5d)", count_pcmd_store, count_pcmd_store - count_pcmd_store_comb); + dolog(); + sprintf (logtext, "Number of OP Pseudocommands: %5d", count_pcmd_op); + dolog(); + sprintf (logtext, "Number of DUP Pseudocommands: %5d", count_dup_instruction); + dolog(); + sprintf (logtext, "Number of Mem Pseudocommands: %5d", count_pcmd_mem); + dolog(); + sprintf (logtext, "Number of Method Pseudocommands: %5d", count_pcmd_met); + dolog(); + sprintf (logtext, "Number of Branch Pseudocommands: %5d (rets:%5d, Xrets: %5d)", + count_pcmd_bra, count_pcmd_return, count_pcmd_returnx); + dolog(); + sprintf (logtext, "Number of Table Pseudocommands: %5d", count_pcmd_table); + dolog(); + sprintf (logtext, "Number of Useful Pseudocommands: %5d", count_pcmd_table + + count_pcmd_bra + count_pcmd_load + count_pcmd_mem + count_pcmd_op); + dolog(); + sprintf (logtext, "Number of Null Pointer Checks: %5d", count_check_null); + dolog(); + sprintf (logtext, "Number of Array Bound Checks: %5d", count_check_bound); + dolog(); + sprintf (logtext, "Number of Try-Blocks: %d", count_tryblocks); + dolog(); + sprintf (logtext, "Maximal count of stack elements: %d", count_max_new_stack); + dolog(); + sprintf (logtext, "Upper bound of max stack elements: %d", count_upper_bound_new_stack); + dolog(); + sprintf (logtext, "Distribution of stack sizes at block boundary"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_block_stack[0], + count_block_stack[1],count_block_stack[2],count_block_stack[3],count_block_stack[4], + count_block_stack[5],count_block_stack[6],count_block_stack[7],count_block_stack[8], + count_block_stack[9],count_block_stack[10]); + dolog(); + sprintf (logtext, "Distribution of store stack depth"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 >=10"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_depth[0], + count_store_depth[1],count_store_depth[2],count_store_depth[3],count_store_depth[4], + count_store_depth[5],count_store_depth[6],count_store_depth[7],count_store_depth[8], + count_store_depth[9],count_store_depth[10]); + dolog(); + sprintf (logtext, "Distribution of store creator chains first part"); + dolog(); + sprintf (logtext, " 0 1 2 3 4 5 6 7 8 9 "); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_length[0], + count_store_length[1],count_store_length[2],count_store_length[3],count_store_length[4], + count_store_length[5],count_store_length[6],count_store_length[7],count_store_length[8], + count_store_length[9]); + dolog(); + sprintf (logtext, "Distribution of store creator chains second part"); + dolog(); + sprintf (logtext, " 10 11 12 13 14 15 16 17 18 19 >=20"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_store_length[10], + count_store_length[11],count_store_length[12],count_store_length[13],count_store_length[14], + count_store_length[15],count_store_length[16],count_store_length[17],count_store_length[18], + count_store_length[19],count_store_length[20]); + dolog(); + sprintf (logtext, "Distribution of analysis iterations"); + dolog(); + sprintf (logtext, " 1 2 3 4 >=5"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d", count_analyse_iterations[0],count_analyse_iterations[1], + count_analyse_iterations[2],count_analyse_iterations[3],count_analyse_iterations[4]); + dolog(); + sprintf (logtext, "Distribution of basic blocks per method"); + dolog(); + sprintf (logtext, " <= 5 <=10 <=15 <=20 <=30 <=40 <=50 <=75 >75"); + dolog(); + sprintf (logtext, "%5d%5d%5d%5d%5d%5d%5d%5d%5d", count_method_bb_distribution[0], + count_method_bb_distribution[1],count_method_bb_distribution[2],count_method_bb_distribution[3], + count_method_bb_distribution[4],count_method_bb_distribution[5],count_method_bb_distribution[6], + count_method_bb_distribution[7],count_method_bb_distribution[8]); + dolog(); + sprintf (logtext, "Distribution of basic block sizes"); + dolog(); + sprintf (logtext, + " 1 2 3 4 5 6 7 8 9 10 <13 <15 <17 <19 <21 <26 <31 >30"); + dolog(); + sprintf (logtext, "%3d%5d%5d%5d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d", + count_block_size_distribution[0], count_block_size_distribution[1], count_block_size_distribution[2], + count_block_size_distribution[3], count_block_size_distribution[4], count_block_size_distribution[5], + count_block_size_distribution[6], count_block_size_distribution[7], count_block_size_distribution[8], + count_block_size_distribution[9], count_block_size_distribution[10],count_block_size_distribution[11], + count_block_size_distribution[12],count_block_size_distribution[13],count_block_size_distribution[14], + count_block_size_distribution[15],count_block_size_distribution[16],count_block_size_distribution[17]); + dolog(); + sprintf (logtext, "Size of Code Area (Kb): %10.3f", (float) count_code_len / 1024); + dolog(); + sprintf (logtext, "Size of data Area (Kb): %10.3f", (float) count_data_len / 1024); + dolog(); + sprintf (logtext, "Size of Class Infos (Kb):%10.3f", (float) (count_class_infos) / 1024); + dolog(); + sprintf (logtext, "Size of Const Pool (Kb): %10.3f", (float) (count_const_pool_len + count_unicode_len) / 1024); + dolog(); + sprintf (logtext, "Size of Vftbl (Kb): %10.3f", (float) count_vftbl_len / 1024); + dolog(); + sprintf (logtext, "Size of comp stub (Kb): %10.3f", (float) count_cstub_len / 1024); + dolog(); + sprintf (logtext, "Size of native stub (Kb):%10.3f", (float) count_nstub_len / 1024); + dolog(); + sprintf (logtext, "Size of Unicode (Kb): %10.3f", (float) count_unicode_len / 1024); + dolog(); + sprintf (logtext, "Size of VMCode (Kb): %10.3f(%d)", (float) count_vmcode_len / 1024, + count_vmcode_len - 18 * count_all_methods); + dolog(); + sprintf (logtext, "Size of ExTable (Kb): %10.3f", (float) count_extable_len / 1024); + dolog(); + sprintf (logtext, "Number of loaded Methods: %d\n\n", count_all_methods); + dolog(); +} + + +/********** Funktion: class_compile_methods (nur f"ur Debug-Zwecke) ********/ + +void class_compile_methods () +{ + int i; + classinfo *c; + methodinfo *m; + + c = list_first (&linkedclasses); + while (c) { + for (i = 0; i < c -> methodscount; i++) { + m = &(c->methods[i]); + if (m->jcode) { + if (newcompiler) + (void) new_compile(m); + else + (void) compiler_compile(m); + } + } + c = list_next (&linkedclasses, c); + } +} + + +/************************** Funktion: main ******************************* + + Das Hauptprogramm. + Wird vom System zu Programstart aufgerufen (eh klar). + +**************************************************************************/ + + +int main(int argc, char **argv) +{ + s4 i,j; + char *cp; + classinfo *topclass; + java_objectheader *exceptionptr; + void *dummy; + + + /********** interne (nur fuer main relevante Optionen) **************/ + + char logfilename[200] = ""; + u4 heapsize = 16000000; + u4 heapstartsize = 200000; + char classpath[500] = ".:/usr/local/lib/java/classes"; + bool showmethods = false; + bool showconstantpool = false; + bool showunicode = false; + bool startit = true; + char *specificmethodname = NULL; + char *specificsignature = NULL; + +#ifndef USE_THREADS + stackbottom = &dummy; +#endif + + + /************ Infos aus der Environment lesen ************************/ + + cp = getenv ("CLASSPATH"); + if (cp) { + strcpy (classpath, cp); + } + + /***************** Interpretieren der Kommandozeile *****************/ + + checknull = false; + checkfloats = false; + + while ( (i = get_opt(argc,argv)) != OPT_DONE) { + + switch (i) { + case OPT_IGNORE: break; + + case OPT_CLASSPATH: + strcpy (classpath + strlen(classpath), ":"); + strcpy (classpath + strlen(classpath), opt_arg); + break; + + case OPT_D: + { + int n,l=strlen(opt_arg); + for (n=0; n= argc) { + print_usage (); + exit(10); + } + + + /**************************** Programmstart *****************************/ + + log_init (logfilename); + if (verbose) { + log_text ( + "CACAO started -------------------------------------------------------"); + } + + suck_init (classpath); + native_setclasspath (classpath); + + unicode_init(); + heap_init(heapsize, heapstartsize, &dummy); + loader_init(); + compiler_init(); + ncomp_init(); + + native_loadclasses (); + + + /*********************** JAVA-Klassen laden ***************************/ + + cp = argv[opt_ind++]; + for (i=strlen(cp)-1; i>=0; i--) { /* Punkte im Klassennamen */ + if (cp[i]=='.') cp[i]='/'; /* auf slashes umbauen */ + } + + topclass = loader_load ( unicode_new_char (cp) ); + + gc_init(); + +#ifdef USE_THREADS + initThreads((u1*)&dummy); /* schani */ +#endif + + /************************* Arbeitsroutinen starten ********************/ + + if (startit) { + methodinfo *mainmethod; + java_objectarray *a; + + mainmethod = class_findmethod ( + topclass, + unicode_new_char ("main"), + unicode_new_char ("([Ljava/lang/String;)V") + ); + if (!mainmethod) panic ("Can not find method 'void main(String[])'"); + if ((mainmethod->flags & ACC_STATIC) != ACC_STATIC) panic ("main is not static!"); + + a = builtin_anewarray (argc - opt_ind, class_java_lang_String); + for (i=opt_ind; idata[i-opt_ind] = javastring_new (unicode_new_char (argv[i]) ); + } + exceptionptr = asm_calljavamethod (mainmethod, a, NULL,NULL,NULL ); + + if (exceptionptr) { + printf ("#### Program has thrown: "); + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + } + +/* killThread(currentThread); */ + + } + + /************* Auf Wunsch alle Methode "ubersetzen ********************/ + + if (compileall) { + class_compile_methods(); + } + + + /******** Auf Wunsch eine spezielle Methode "ubersetzen ***************/ + + if (specificmethodname) { + methodinfo *m; + if (specificsignature) + m = class_findmethod(topclass, + unicode_new_char(specificmethodname), + unicode_new_char(specificsignature)); + else + m = class_findmethod(topclass, + unicode_new_char(specificmethodname), NULL); + if (!m) panic ("Specific method not found"); + if (newcompiler) + (void) new_compile(m); + else + (void) compiler_compile(m); + } + + /********************* Debug-Tabellen ausgeben ************************/ + + if (showmethods) class_showmethods (topclass); + if (showconstantpool) class_showconstantpool (topclass); + if (showunicode) unicode_show (); + + + + /************************ Freigeben aller Resourcen *******************/ + + compiler_close (); + loader_close (); + heap_close (); + unicode_close ( literalstring_free ); + + + /* Endemeldung ausgeben und mit entsprechendem exit-Status terminieren */ + + if (verbose || getcompilingtime || statistics) { + log_text ("CACAO terminated"); + if (statistics) + print_stats (); + if (getcompilingtime) + print_times (); + mem_usagelog(1); + } + + exit(0); + return 1; +} + + + +/************************************ SHUTDOWN-Funktion ********************************* + + Terminiert das System augenblicklich, ohne den Speicher + explizit freizugeben (eigentlich nur f"ur abnorme + Programmterminierung) + +*****************************************************************************************/ + +void cacao_shutdown(s4 status) +{ + if (verbose || getcompilingtime || statistics) { + log_text ("CACAO terminated by shutdown"); + if (statistics) + print_stats (); + if (getcompilingtime) + print_times (); + mem_usagelog(0); + sprintf (logtext, "Exit status: %d\n", (int) status); + dolog(); + } + + exit(status); +} diff --git a/src/cacaoh/headers.c b/src/cacaoh/headers.c new file mode 100644 index 000000000..dce631e1a --- /dev/null +++ b/src/cacaoh/headers.c @@ -0,0 +1,465 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** headers.c ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Dieser Modul ersetzt f"ur den Headerfile-Betrieb den Modul 'main', + und 'f"alscht' einige Verweise auf externe Module (damit nicht schon + alle Module des eigentlichen Programmes fertig sein m"ussen, was ja + unm"oglich w"are, da die Headerfile-Tabellen ja erst hier und jetzt + generiert werden). + + Dieser Modul ist ein ziemlich schneller Hack und dementsprechend + schlecht (nicht) kommentiert. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/05/23 + +*******************************************************************************/ + +#include "global.h" + +#include "tables.h" +#include "loader.h" + + +/******* verschiedene externe Funktionen "faelschen" (=durch Dummys ersetzen), + damit der Linker zufrieden ist *********/ + +functionptr native_findfunction + (unicode *cname, unicode *mname, unicode *desc, bool isstatic) +{ return NULL; } + +java_objectheader *literalstring_new (unicode *text) +{ return NULL; } + +java_objectheader *javastring_new (unicode *text) /* schani */ +{ return NULL; } + +void synchronize_caches() { } +void asm_call_jit_compiler () { } +void asm_calljavamethod () { } +void asm_dumpregistersandcall () { } + +s4 new_builtin_idiv (s4 a, s4 b) {return 0;} +s4 new_builtin_irem (s4 a, s4 b) {return 0;} +s8 new_builtin_ldiv (s8 a, s8 b) {return 0;} +s8 new_builtin_lrem (s8 a, s8 b) {return 0;} + + +void new_builtin_monitorenter (java_objectheader *o) {} +void new_builtin_monitorexit (java_objectheader *o) {} + +s4 new_builtin_checkcast(java_objectheader *o, classinfo *c) + {return 0;} +s4 new_builtin_checkarraycast + (java_objectheader *o, constant_arraydescriptor *d) + {return 0;} + +void new_builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o) {} + +u1 *createcompilerstub (methodinfo *m) {return NULL;} +u1 *createnativestub (functionptr f, methodinfo *m) {return NULL;} +u1 *ncreatenativestub (functionptr f, methodinfo *m) {return NULL;} + +void removecompilerstub (u1 *stub) {} +void removenativestub (u1 *stub) {} + +void perform_alpha_threadswitch (u1 **from, u1 **to) {} +u1* initialize_thread_stack (void *func, u1 *stack) { return NULL; } +u1* used_stack_top (void) { return NULL; } + +java_objectheader *native_new_and_init (void *p) { return NULL; } + +/************************ globale Variablen **********************/ + +java_objectheader *exceptionptr; /* schani */ +int newcompiler = true; +bool verbose = false; + +static chain *nativechain; +static FILE *file = NULL; + +static void printIDpart (int c) +{ + if ( (c>='a' && c<='z') + || (c>='A' && c<='Z') + || (c>='0' && c<='9') + || (c=='_') ) + putc (c,file); + else putc ('_',file); + +} + +static void printID (unicode *name) +{ + int i; + for (i=0; ilength; i++) { + printIDpart (name->text[i]); + } +} + + +u4 outputsize; +bool dopadding; + +static void addoutputsize (int len) +{ + u4 newsize,i; + if (!dopadding) return; + + newsize = ALIGN (outputsize, len); + + for (i=outputsize; isuper); + + for (i=0; ifieldscount; i++) { + f = &(c->fields[i]); + + if (! (f->flags & ACC_STATIC) ) { + fprintf (file," "); + printtype (f->descriptor->text); + fprintf (file, " "); + unicode_fprint (file, f->name); + fprintf (file, ";\n"); + } + } +} + + + + +static void remembermethods (classinfo *c) +{ + u2 i; + methodinfo *m; + + for (i=0; imethodscount; i++) { + m = &(c->methods[i]); + + if (m->flags & ACC_NATIVE) { + chain_addlast (nativechain, m); + } + + } +} + + + + +static void printmethod (methodinfo *m) +{ + u2 *d; + u2 paramnum=1; + + d = m->descriptor->text; + while (*(d++) != ')'); + + printtype (d); + fprintf (file," "); + printID (m->class->name); + fprintf (file,"_"); + printID (m->name); + fprintf (file," ("); + + d = m->descriptor->text+1; + + if (! (m->flags & ACC_STATIC) ) { + fprintf (file, "struct "); + printID (m->class->name); + fprintf (file, "* this"); + if ((*d)!=')') fprintf (file, ", "); + } + + while ((*d)!=')') { + d = printtype (d); + fprintf (file, " par%d", paramnum++); + if ((*d)!=')') fprintf (file, ", "); + } + + fprintf (file, ");\n"); +} + + +static void headers_generate (classinfo *c) +{ + fprintf (file, "/* Structure information for class: "); + unicode_fprint (file, c->name); + fprintf (file, " */\n\n"); + + fprintf (file, "typedef struct "); + printID (c->name); + fprintf (file, " {\n"); + + outputsize=0; + dopadding=true; + printfields (c); + + fprintf (file, "} "); + printID (c->name); + fprintf (file, ";\n\n"); + + remembermethods (c); + + + fprintf (file, "\n\n"); +} + + + +static void printnativetableentry (methodinfo *m) +{ + fprintf (file, " { \""); + unicode_fprint (file, m->class->name); + fprintf (file, "\",\n \""); + unicode_fprint (file, m->name); + fprintf (file, "\",\n \""); + unicode_fprint (file, m->descriptor); + fprintf (file, "\",\n "); + if ( (m->flags & ACC_STATIC) !=0) fprintf (file, "true"); + else fprintf (file, "false"); + fprintf (file, ",\n "); + fprintf (file, "(functionptr) "); + printID (m->class->name); + fprintf (file,"_"); + printID (m->name); + fprintf (file,"\n },\n"); +} + + + + + +static void headers_start () +{ + file = fopen ("nativetypes.hh", "w"); + if (!file) panic ("Can not open file 'native.h' to store header information"); + + fprintf (file, "/* Headerfile for native methods: nativetypes.hh */\n"); + fprintf (file, "/* This file is machine generated, don't edit it !*/\n\n"); + + nativechain = chain_new (); +} + + +static void headers_finish () +{ + methodinfo *m; + + fprintf (file, "\n/* Prototypes for native methods */\n\n"); + + m = chain_first (nativechain); + while (m) { + dopadding=false; + printmethod (m); + + m = chain_next (nativechain); + } + + + file = fopen ("nativetable.hh", "w"); + if (!file) panic ("Can not open file 'nativetable' to store native-link-table"); + + fprintf (file, "/* Table of native methods: nativetables.hh */\n"); + fprintf (file, "/* This file is machine generated, don't edit it !*/\n\n"); + + while ( (m = chain_first (nativechain)) != NULL) { + chain_remove (nativechain); + + printnativetableentry (m); + + } + + chain_free (nativechain); + fclose (file); +} + + + + + +/******************** interne Funktion: print_usage ************************ + +Gibt die richtige Aufrufsyntax des JAVA-Header-Generators auf stdout aus. + +***************************************************************************/ + +static void print_usage() +{ + printf ("USAGE: jch class [class..]\n"); +} + + + + +/************************** Funktion: main ******************************* + + Das Hauptprogramm. + Wird vom System zu Programstart aufgerufen (eh klar). + +**************************************************************************/ + +int main(int argc, char **argv) +{ + s4 i,a; + char *cp; + classinfo *topclass; + void *dummy; + + + /********** interne (nur fuer main relevante Optionen) **************/ + + char classpath[500] = ""; + u4 heapsize = 100000; + + /*********** Optionen, damit wirklich nur headers generiert werden ***/ + + makeinitializations=false; + + + /************ Infos aus der Environment lesen ************************/ + + cp = getenv ("CLASSPATH"); + if (cp) { + strcpy (classpath + strlen(classpath), ":"); + strcpy (classpath + strlen(classpath), cp); + } + + if (argc < 2) { + print_usage (); + exit(10); + } + + + /**************************** Programmstart *****************************/ + + log_init (NULL); + log_text ("Java - header-generator started"); + + + suck_init (classpath); + + unicode_init (); + heap_init (heapsize, heapsize, &dummy); + loader_init (); + + + /*********************** JAVA-Klassen laden ***************************/ + + headers_start (); + + + for (a=1; a=0; i--) { /* Punkte im Klassennamen */ + if (cp[i]=='.') cp[i]='/'; /* auf slashes umbauen */ + } + + topclass = loader_load ( unicode_new_char (cp) ); + + headers_generate (topclass); + } + + + headers_finish (); + + + /************************ Freigeben aller Resourcen *******************/ + + loader_close (); + heap_close (); + unicode_close (NULL); + + + /* Endemeldung ausgeben und mit entsprechendem exit-Status terminieren */ + + log_text ("Java - header-generator stopped"); + log_cputime (); + mem_usagelog(1); + + return 0; +} + + diff --git a/src/mm/memory.c b/src/mm/memory.c new file mode 100644 index 000000000..2cc8e9437 --- /dev/null +++ b/src/mm/memory.c @@ -0,0 +1,458 @@ +/************************* toolbox/memory.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see memory.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "../callargs.h" +#include "loging.h" +#include "memory.h" + + + /********* allgemeine Typen, Variablen und Hilfsfunktionen *********/ + +#define DUMPBLOCKSIZE (2<<18) +#define ALIGNSIZE 8 + +typedef struct dumplist { + struct dumplist *prev; + char *dumpmem; +} dumplist; + + + +long int memoryusage = 0; + +long int dumpsize = 0; +long int dumpspace = 0; +dumplist *topdumpblock = NULL; + +long int maxmemusage = 0; +long int maxdumpsize = 0; + +/* #define TRACECALLARGS */ + +#ifdef TRACECALLARGS +static char nomallocmem[16777216]; +static char *nomalloctop = nomallocmem + 16777216; +static char *nomallocptr = nomallocmem; + +static void *lit_checked_alloc (int length) +{ + void *m; + + nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE); + + m = nomallocptr; + nomallocptr += length; + if (nomallocptr > nomalloctop) panic ("Out of memory"); + return m; +} + +#else + +static void *lit_checked_alloc (int length) +{ + void *m = malloc(length); + if (!m) panic ("Out of memory"); + return m; +} + +#endif + + +static void *checked_alloc (int length) +{ + void *m = malloc(length); + if (!m) panic ("Out of memory"); + return m; +} + +static int mmapcodesize = 0; +static void *mmapcodeptr = NULL; + +void *mem_mmap(int length) +{ + void *retptr; + + length = (ALIGN(length,ALIGNSIZE)); + if (length > mmapcodesize) { + mmapcodesize = 0x10000; + if (length > mmapcodesize) + mmapcodesize = length; + mmapcodesize = (ALIGN(mmapcodesize, getpagesize())); + mmapcodeptr = mmap (NULL, (size_t) mmapcodesize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0); + if (mmapcodeptr == (void*) -1) + panic ("Out of memory"); + } + retptr = mmapcodeptr; + mmapcodeptr = (void*) ((char*) mmapcodeptr + length); + mmapcodesize -= length; + return retptr; +} + + +#ifdef DEBUG + + /************ Sichere Version des Speichermanages **************/ + + +typedef struct memblock { + struct memblock *prev,*next; + int length; +} memblock; + +#define BLOCKOFFSET (ALIGN(sizeof(memblock),ALIGNSIZE)) + +struct memblock *firstmemblock; + + + +void *mem_alloc(int length) +{ + memblock *mb; + + if (length==0) return NULL; + mb = checked_alloc (length + BLOCKOFFSET); + + mb -> prev = NULL; + mb -> next = firstmemblock; + mb -> length = length; + + if (firstmemblock) firstmemblock -> prev = mb; + firstmemblock = mb; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return ((char*) mb) + BLOCKOFFSET; +} + + +void *lit_mem_alloc(int length) +{ + memblock *mb; + + if (length==0) return NULL; + mb = lit_checked_alloc (length + BLOCKOFFSET); + + mb -> prev = NULL; + mb -> next = firstmemblock; + mb -> length = length; + + if (firstmemblock) firstmemblock -> prev = mb; + firstmemblock = mb; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return ((char*) mb) + BLOCKOFFSET; +} + + +void mem_free(void *m, int length) +{ + memblock *mb; + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + mb = (memblock*) (((char*) m) - BLOCKOFFSET); + + if (mb->length != length) { + sprintf (logtext, + "Memory block of size %d has been return as size %d", + mb->length, length); + error(); + } + + if (mb->prev) mb->prev->next = mb->next; + else firstmemblock = mb->next; + if (mb->next) mb->next->prev = mb->prev; + + free (mb); + + memoryusage -= length; +} + + +void lit_mem_free(void *m, int length) +{ + memblock *mb; + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + mb = (memblock*) (((char*) m) - BLOCKOFFSET); + + if (mb->length != length) { + sprintf (logtext, + "Memory block of size %d has been return as size %d", + mb->length, length); + error(); + } + + if (mb->prev) mb->prev->next = mb->next; + else firstmemblock = mb->next; + if (mb->next) mb->next->prev = mb->prev; + +#ifdef TRACECALLARGS +#else + free (mb); +#endif + + memoryusage -= length; +} + + +void *mem_realloc (void *m1, int len1, int len2) +{ + void *m2; + + m2 = mem_alloc (len2); + memcpy (m2, m1, len1); + mem_free (m1, len1); + + return m2; +} + + + + +static void mem_characterlog (unsigned char *m, int len) +{ +# define LINESIZE 16 + int z,i; + + for (z=0; z=' ' && m[i]<=127) ? m[i] : '.'); + } + + dolog(); + } +} + +#else + /******* Schnelle Version des Speichermanagers ******/ + + +void *mem_alloc(int length) +{ + if (length==0) return NULL; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return checked_alloc (length); +} + + +void *lit_mem_alloc(int length) +{ + if (length==0) return NULL; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return lit_checked_alloc (length); +} + + +void mem_free(void *m, int length) +{ + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + memoryusage -= length; + + free (m); +} + + +void lit_mem_free(void *m, int length) +{ + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + memoryusage -= length; + +#ifdef TRACECALLARGS +#else + free (m); +#endif +} + + +void *mem_realloc (void *m1, int len1, int len2) +{ + void *m2; + + if (!m1) { + if (len1!=0) + panic ("reallocating memoryblock with address NULL, length != 0"); + } + + memoryusage = (memoryusage - len1) + len2; + + m2 = realloc (m1, len2); + if (!m2) panic ("Out of memory"); + return m2; +} + + +#endif + + /******* allgemeine Teile des Speichermanagers ******/ + + + +long int mem_usage() +{ + return memoryusage; +} + + + + + +void *dump_alloc(int length) +{ + void *m; + + if (length==0) return NULL; + + length = ALIGN (length, ALIGNSIZE); + + assert (length <= DUMPBLOCKSIZE); + assert (length > 0); + + if (dumpsize + length > dumpspace) { + dumplist *newdumpblock = checked_alloc (sizeof(dumplist)); + + newdumpblock -> prev = topdumpblock; + topdumpblock = newdumpblock; + + newdumpblock -> dumpmem = checked_alloc (DUMPBLOCKSIZE); + + dumpsize = dumpspace; + dumpspace += DUMPBLOCKSIZE; + } + + m = topdumpblock -> dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize); + dumpsize += length; + + if (dumpsize > maxdumpsize) { + maxdumpsize = dumpsize; + } + + return m; +} + + +void *dump_realloc(void *ptr, int len1, int len2) +{ + void *p2 = dump_alloc (len2); + memcpy (p2, ptr, len1); + return p2; +} + + +long int dump_size() +{ + return dumpsize; +} + + +void dump_release(long int size) +{ + assert (size >= 0 && size <= dumpsize); + + dumpsize = size; + + while (dumpspace > dumpsize + DUMPBLOCKSIZE) { + dumplist *oldtop = topdumpblock; + + topdumpblock = oldtop -> prev; + dumpspace -= DUMPBLOCKSIZE; + +#ifdef TRACECALLARGS +#else + free (oldtop -> dumpmem); + free (oldtop); +#endif + } +} + + + + +void mem_usagelog (int givewarnings) +{ + if ((memoryusage!=0) && givewarnings) { + sprintf (logtext, "Allocated memory not returned: %d", + (int)memoryusage); + dolog(); + +#ifdef DEBUG + { + memblock *mb = firstmemblock; + while (mb) { + sprintf (logtext, " Memory block size: %d", + (int)(mb->length) ); + dolog(); + mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length); + mb = mb->next; + } + } +#endif + + } + + if ((dumpsize!=0) && givewarnings) { + sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize); + dolog(); + } + + + sprintf (logtext, "Random/Dump - memory usage: %dK/%dK", + (int)((maxmemusage+1023)/1024), + (int)((maxdumpsize+1023)/1024) ); + dolog(); + +} + diff --git a/src/mm/memory.h b/src/mm/memory.h new file mode 100644 index 000000000..c4122f96e --- /dev/null +++ b/src/mm/memory.h @@ -0,0 +1,121 @@ +/************************* toolbox/memory.h ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Headerfiles und Makros f"ur die Speicherverwaltung. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#define CODEMMAP + +#define ALIGN(pos,size) ( ( ((pos)+(size)-1) / (size))*(size) ) +#define PADDING(pos,size) ( ALIGN((pos),(size)) - (pos) ) +#define OFFSET(s,el) ( (int) &( ((s*)0) -> el ) ) + + +#define NEW(type) ((type*) mem_alloc ( sizeof(type) )) +#define FREE(ptr,type) mem_free (ptr, sizeof(type) ) + +#define LNEW(type) ((type*) lit_mem_alloc ( sizeof(type) )) +#define LFREE(ptr,type) lit_mem_free (ptr, sizeof(type) ) + +#define MNEW(type,num) ((type*) mem_alloc ( sizeof(type) * (num) )) +#define MFREE(ptr,type,num) mem_free (ptr, sizeof(type) * (num) ) +#define MREALLOC(ptr,type,num1,num2) mem_realloc (ptr, sizeof(type) * (num1), \ + sizeof(type) * (num2) ) + +#define DNEW(type) ((type*) dump_alloc ( sizeof(type) )) +#define DMNEW(type,num) ((type*) dump_alloc ( sizeof(type) * (num) )) +#define DMREALLOC(ptr,type,num1,num2) dump_realloc (ptr, sizeof(type)*(num1),\ + sizeof(type) * (num2) ) + +#define MCOPY(dest,src,type,num) memcpy (dest,src, sizeof(type)* (num) ) + +#ifdef CODEMMAP +#define CNEW(type,num) ((type*) mem_mmap ( sizeof(type) * (num) )) +#define CFREE(ptr,num) +#else +#define CNEW(type,num) ((type*) mem_alloc ( sizeof(type) * (num) )) +#define CFREE(ptr,num) mem_free (ptr, num) +#endif + +void *mem_alloc(int length); +void *mem_mmap(int length); +void *lit_mem_alloc(int length); +void mem_free(void *m, int length); +void lit_mem_free(void *m, int length); +void *mem_realloc(void *m, int len1, int len2); +long int mem_usage(); + +void *dump_alloc(int length); +void *dump_realloc(void *m, int len1, int len2); +long int dump_size(); +void dump_release(long int size); + +void mem_usagelog(int givewarnings); + + + +/* +---------------------------- Schnittstellenbeschreibung ----------------------- + +Der Speicherverwalter hat zwei m"ogliche Arten Speicher zu reservieren +und freizugeben: + + 1. explizites Anfordern / Freigeben + + mem_alloc ..... Anfordern eines Speicherblocks + mem_free ...... Freigeben eines Speicherblocks + mem_realloc ... Vergr"o"sern eines Speicherblocks (wobei + der Inhalt eventuell an eine neue Position kommt) + mem_usage ..... Menge des bereits belegten Speichers + + + 2. explizites Anfordern und automatisches Freigeben + + dump_alloc .... Anfordern eines Speicherblocks vom + (wie ich es nenne) DUMP-Speicher + dump_realloc .. Vergr"o"sern eines Speicherblocks + dump_size ..... Merkt sich eine Freigabemarke am Dump + dump_release .. Gibt allen Speicher, der nach der Marke angelegt + worden ist, wieder frei. + + +Es gibt f"ur diese Funktionen ein paar praktische Makros: + + NEW (type) ....... legt Speicher f"ur ein Element des Typs `type` an. + FREE (ptr,type) .. gibt Speicher zur"uck + + MNEW (type,num) .. legt Speicher f"ur ein ganzes Array an + MFREE (ptr,type,num) .. gibt den Speicher wieder her + + MREALLOC (ptr,type,num1,num2) .. vergr"o"sert den Speicher f"ur das Array + auf die Gr"o"se num2 + +Die meisten der Makros gibt es auch f"ur den DUMP-Speicher, na"mlich mit +gleichem Namen, nur mit vorangestelltem 'D', also: + + DNEW, DMNEW, DMREALLOC (DFREE gibt es nat"urlich keines) + + +------------------------------------------------------------------------------- + +Die restlichen Makros: + + ALIGN (pos, size) ... Rundet den Wert von 'pos' auf die n"achste durch + 'size' teilbare Zahl auf. + + + OFFSET (s,el) ....... Berechnet den Offset (in Bytes) des Elementes 'el' + in der Struktur 's'. + + MCOPY (dest,src,type,num) ... Kopiert 'num' Elemente vom Typ 'type'. + + +*/ diff --git a/src/native/native.c b/src/native/native.c new file mode 100644 index 000000000..771ec5406 --- /dev/null +++ b/src/native/native.c @@ -0,0 +1,340 @@ +/****************************** native.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt die Tabellen f"ur die native-methods. + Die vom Headerfile-Generator erzeugten -.hh - Dateien werden hier + eingebunden, und ebenso alle C-Funktionen, mit denen diese + Methoden implementiert werden. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + +#include +#include + + +#include "global.h" +#include "native.h" + +#include "builtin.h" +#include "nativetypes.hh" +#include "asmpart.h" +#include "tables.h" +#include "loader.h" + + +java_objectheader* exceptionptr = NULL; + + + +static char *classpath; + + +/******************** die f"r die native-Methoden n"otigen Systemklassen *****/ + +static classinfo *class_java_lang_Class; +static classinfo *class_java_lang_Cloneable; +static classinfo *class_java_lang_CloneNotSupportedException; +static classinfo *class_java_lang_Double; +static classinfo *class_java_lang_Float; +static classinfo *class_java_io_IOException; +static classinfo *class_java_lang_ClassNotFoundException; +static classinfo *class_java_lang_InstantiationException; + + + +/************************** alle Funktionen einbinden ************************/ + +#include "nat/lang.c" +#include "nat/io.c" +#include "nat/util.c" + + +/********************** Tabellen f"ur die Methoden ***************************/ + +static struct nativeref { + char *classname; + char *methodname; + char *descriptor; + bool isstatic; + functionptr func; +} nativetable [] = { + +#include "nativetable.hh" + +}; + + +#define NATIVETABLESIZE (sizeof(nativetable)/sizeof(struct nativeref)) + +static struct nativecompref { + unicode *classname; + unicode *methodname; + unicode *descriptor; + bool isstatic; + functionptr func; + } nativecomptable [NATIVETABLESIZE]; + +static bool nativecompdone = false; + + +/*********************** Funktion: native_loadclasses ************************** + + L"adt alle Klassen, die die native Methoden zus"atzlich ben"otigen + +*******************************************************************************/ + +void native_loadclasses() +{ + class_java_lang_Cloneable = + loader_load ( unicode_new_char ("java/lang/Cloneable") ); + class_java_lang_CloneNotSupportedException = + loader_load ( unicode_new_char ("java/lang/CloneNotSupportedException") ); + class_java_lang_Class = + loader_load ( unicode_new_char ("java/lang/Class") ); + class_java_lang_Double = + loader_load ( unicode_new_char ("java/lang/Double") ); + class_java_lang_Float = + loader_load ( unicode_new_char ("java/lang/Float") ); + class_java_io_IOException = + loader_load ( unicode_new_char ("java/io/IOException") ); + class_java_lang_ClassNotFoundException = + loader_load ( unicode_new_char ("java/lang/ClassNotFoundException") ); + class_java_lang_InstantiationException= + loader_load ( unicode_new_char ("java/lang/InstantiationException") ); + +} + +/********************* Funktion: native_setclasspath ***************************/ + +void native_setclasspath (char *path) +{ + classpath = path; +} + + +/*********************** Funktion: native_findfunction ************************ + + Sucht in der Tabelle die passende Methode (muss mit Klassennamen, + Methodennamen, Descriptor und 'static'-Status "ubereinstimmen), + und gibt den Funktionszeiger darauf zur"uck. + Return: Funktionszeiger oder NULL (wenn es keine solche Methode gibt) + + Anmerkung: Zu Beschleunigung des Suchens werden die als C-Strings + vorliegenden Namen/Descriptors in entsprechende unicode-Symbole + umgewandelt (beim ersten Aufruf dieser Funktion). + +*******************************************************************************/ + +functionptr native_findfunction (unicode *cname, unicode *mname, + unicode *desc, bool isstatic) +{ + u4 i; + struct nativecompref *n; + + isstatic = isstatic ? true : false; + + if (!nativecompdone) { + for (i=0; iclassname && mname==n->methodname && + desc==n->descriptor && isstatic==n->isstatic) return n->func; + } + + return NULL; +} + + +/********************** Funktion: javastring_new ***************************** + + Legt ein neues Objekt vom Typ java/lang/String an, und tr"agt als Text + das "ubergebene unicode-Symbol ein. + Return: Zeiger auf den String, oder NULL (wenn Speicher aus) + +*****************************************************************************/ + +java_objectheader *javastring_new (unicode *text) +{ + u4 i; + java_lang_String *s; + java_chararray *a; + + s = (java_lang_String*) builtin_new (class_java_lang_String); + a = builtin_newarray_char (text->length); + + if ( (!a) || (!s) ) return NULL; + + for (i=0; ilength; i++) a->data[i] = text->text[i]; + s -> value = a; + s -> offset = 0; + s -> count = text->length; + + return (java_objectheader*) s; +} + + +/********************** Funktion: javastring_new_char ************************ + + Legt ein neues Objekt vom Typ java/lang/String an, und tr"agt als Text + den "ubergebenen C-String ein. + Return: Zeiger auf den String, oder NULL (wenn Speicher aus) + +*****************************************************************************/ + +java_objectheader *javastring_new_char (char *text) +{ + u4 i; + u4 len = strlen(text); + java_lang_String *s; + java_chararray *a; + + s = (java_lang_String*) builtin_new (class_java_lang_String); + a = builtin_newarray_char (len); + + if ( (!a) || (!s) ) return NULL; + + for (i=0; idata[i] = text[i]; + s -> value = a; + s -> offset = 0; + s -> count = len; + + return (java_objectheader*) s; +} + + +/************************* Funktion: javastring_tochar ***************************** + + Macht aus einem java-string einen C-String, und liefert den Zeiger + darauf zur"uck. + Achtung: Beim n"achsten Aufruf der Funktion wird der vorige String + "uberschrieben + +***********************************************************************************/ + +#define MAXSTRINGSIZE 1000 +char stringbuffer[MAXSTRINGSIZE]; + +char *javastring_tochar (java_objectheader *so) +{ + java_lang_String *s = (java_lang_String*) so; + java_chararray *a; + u4 i; + + if (!s) return ""; + a = s->value; + if (!a) return ""; + if (s->count > MAXSTRINGSIZE) return ""; + for (i=0; icount; i++) stringbuffer[i] = a->data[s->offset+i]; + stringbuffer[i] = '\0'; + return stringbuffer; +} + + +/******************** Funktion: native_new_and_init ************************* + + Legt ein neues Objekt einer Klasse am Heap an, und ruft automatisch + die Initialisierungsmethode auf. + Return: Der Zeiger auf das Objekt, oder NULL, wenn kein Speicher + mehr frei ist. + +*****************************************************************************/ + +java_objectheader *native_new_and_init (classinfo *c) +{ + methodinfo *m; + java_objectheader *o = builtin_new (c); + + if (!o) return NULL; + + m = class_findmethod (c, + unicode_new_char (""), + unicode_new_char ("()V")); + if (!m) { + log_text ("warning: class has no instance-initializer:"); + unicode_sprint (logtext, c->name); + dolog(); + return o; + } + + asm_calljavamethod (m, o,NULL,NULL,NULL); + return o; +} + + +/********************* Funktion: literalstring_new **************************** + + erzeugt einen Java-String mit dem angegebenen Text, allerdings nicht + auf dem HEAP, sondern in einem anderen Speicherbereich (der String + muss dann sp"ater explizit wieder freigegeben werden). + Alle Strings, die auf diese Art erzeugt werden, werden in einer + gemeinsamen Struktur gespeichert (n"amlich auch "uber die + Unicode-Hashtabelle), sodass identische Strings auch wirklich den + gleichen Zeiger liefern. + +******************************************************************************/ + +java_objectheader *literalstring_new (unicode *text) +{ + u4 i; + java_lang_String *s; + java_chararray *a; + + if (text->string) return text->string; + + a = lit_mem_alloc (sizeof(java_chararray) + sizeof(u2)*(text->length-1) ); + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = text->length; + a -> header.arraytype = ARRAYTYPE_CHAR; + for (i=0; ilength; i++) a->data[i] = text->text[i]; + + s = LNEW (java_lang_String); + s -> header.vftbl = class_java_lang_String -> vftbl; + s -> value = a; + s -> offset = 0; + s -> count = text->length; + + unicode_setstringlink (text, (java_objectheader*) s); + return (java_objectheader*) s; +} + + +/********************** Funktion: literalstring_free ************************** + + L"oscht einen Java-String wieder aus dem Speicher (wird zu Systemende + vom Hashtabellen-Verwalter aufgerufen) + +******************************************************************************/ + +void literalstring_free (java_objectheader* sobj) +{ + java_lang_String *s = (java_lang_String*) sobj; + java_chararray *a = s->value; + + LFREE (s, java_lang_String); + LFREE (a, sizeof(java_chararray) + sizeof(u2)*(a->header.size-1)); +} + + + diff --git a/src/native/native.h b/src/native/native.h new file mode 100644 index 000000000..c484642b4 --- /dev/null +++ b/src/native/native.h @@ -0,0 +1,35 @@ +/****************************** native.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the codegenerator for an Alpha processor. + This module generates Alpha machine code for a sequence of + pseudo commands (PCMDs). + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/03/12 + +*******************************************************************************/ + + +extern java_objectheader* exceptionptr; + +void native_loadclasses (); +void native_setclasspath (char *path); + +functionptr native_findfunction (unicode *cname, unicode *mname, + unicode *desc, bool isstatic); + +java_objectheader *javastring_new (unicode *text); +java_objectheader *javastring_new_char (char *text); +char *javastring_tochar (java_objectheader *s); + +java_objectheader *native_new_and_init (classinfo *c); + +java_objectheader *literalstring_new (unicode *text); +void literalstring_free (java_objectheader*); + +void attach_property(char *name, char *value); diff --git a/src/threads/green/locks.c b/src/threads/green/locks.c new file mode 100644 index 000000000..f921f47b7 --- /dev/null +++ b/src/threads/green/locks.c @@ -0,0 +1,576 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/* + * locks.c + * Manage locking system + * This include the mutex's and cv's. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#include +#include + +#include "thread.h" +#include "locks.h" + +#include "../tables.h" +#include "../native.h" +#include "../loader.h" + +static classinfo *class_java_lang_IllegalMonitorStateException; + +#if 1 +#define DBG(s) +#else +#define DBG(s) s +#endif + +extern thread* currentThread; + +#if defined(USE_INTERNAL_THREADS) + +mutexHashEntry *mutexHashTable; +int mutexHashTableSize; +long mutexHashMask; + +mutexHashEntry *mutexOverflowTable; +int mutexOverflowTableSize; +mutexHashEntry *firstFreeOverflowEntry = 0; + +conditionHashEntry *conditionHashTable; +int conditionHashTableSize; +long conditionHashMask; + +/* + * Init the tables. + */ +void +initLocks (void) +{ + int i; + + mutexHashTableSize = MUTEX_HASH_TABLE_SIZE; + mutexHashTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) * mutexHashTableSize); + mutexHashMask = (mutexHashTableSize - 1) << 3; + + for (i = 0; i < mutexHashTableSize; ++i) + { + mutexHashTable[i].object = 0; + mutexHashTable[i].mutex.holder = 0; + mutexHashTable[i].mutex.count = 0; + mutexHashTable[i].mutex.muxWaiters = 0; + mutexHashTable[i].conditionCount = 0; + mutexHashTable[i].next = 0; + } + + mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE; + mutexOverflowTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) + * mutexOverflowTableSize); + + firstFreeOverflowEntry = &mutexOverflowTable[0]; + + for (i = 0; i < mutexOverflowTableSize; ++i) + { + mutexOverflowTable[i].object = 0; + mutexOverflowTable[i].mutex.holder = 0; + mutexOverflowTable[i].mutex.count = 0; + mutexOverflowTable[i].mutex.muxWaiters = 0; + mutexOverflowTable[i].conditionCount = 0; + mutexOverflowTable[i].next = &mutexOverflowTable[i + 1]; + } + mutexOverflowTable[i - 1].next = 0; + + conditionHashTableSize = CONDITION_HASH_TABLE_SIZE; + conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry) + * conditionHashTableSize); + conditionHashMask = (conditionHashTableSize - 1) << 3; + + for (i = 0; i < conditionHashTableSize; ++i) + { + conditionHashTable[i].object = 0; + conditionHashTable[i].condition.cvWaiters = 0; + conditionHashTable[i].condition.mux = 0; + } + + /* Load exception classes */ + class_java_lang_IllegalMonitorStateException = + loader_load(unicode_new_char("java/lang/IllegalMonitorStateException")); +} + +/* + * Reorders part of the condition hash table. Must be called after an entry has been deleted. + */ +void +reorderConditionHashTable (int begin) +{ + while (conditionHashTable[begin].object != 0) + { + int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object); + + if (hashValue != begin) + { + while (conditionHashTable[hashValue].object != 0) + { + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + if (hashValue == begin) + break; + } + if (hashValue != begin) + { + conditionHashTable[hashValue] = conditionHashTable[begin]; + conditionHashTable[begin].object = 0; + conditionHashTable[begin].condition.cvWaiters = 0; + conditionHashTable[begin].condition.mux = 0; + } + } + + begin = CONDITION_HASH_SUCCESSOR(begin); + } +} + +/* + * Looks up an entry in the condition hash table. + */ +iCv* +conditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != object + && conditionHashTable[hashValue].object != 0) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + if (conditionHashTable[hashValue].object == 0) + { + intsRestore(); + return 0; + } + + intsRestore(); + return &conditionHashTable[hashValue].condition; +} + +/* + * Adds a new entry in the condition hash table and returns a pointer to the condition + */ +iCv* +addConditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != 0) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + conditionHashTable[hashValue].object = object; + + intsRestore(); + + return &conditionHashTable[hashValue].condition; +} + +/* + * Removes an entry from the condition hash table. + */ +void +removeConditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != object) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + conditionHashTable[hashValue].object = 0; + conditionHashTable[hashValue].condition.cvWaiters = 0; + conditionHashTable[hashValue].condition.mux = 0; + + reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue)); + + intsRestore(); +} + +/* + * Returns the mutex entry for the specified object and increments its conditionCount. + */ +mutexHashEntry* +conditionLockedMutexForObject (java_objectheader *object) +{ + int hashValue; + mutexHashEntry *entry; + + assert(object != 0); + + intsDisable(); + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object != 0) + { + if (entry->mutex.count == 0 && entry->conditionCount == 0) + { + entry->object = 0; + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + else + { + while (entry->next != 0 && entry->object != object) + entry = entry->next; + + if (entry->object != object) + { + entry->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = firstFreeOverflowEntry->next; + + entry = entry->next; + entry->object = 0; + entry->next = 0; + assert(entry->conditionCount == 0); + } + } + } + + if (entry->object == 0) + entry->object = object; + + ++entry->conditionCount; + + intsRestore(); + + return entry; +} + +/* + * Wait for the condition of an object to be signalled + */ +void +wait_cond_for_object (java_objectheader *obj, s8 time) +{ + iCv *condition; + mutexHashEntry *mutexEntry; + + intsDisable(); + + mutexEntry = conditionLockedMutexForObject(obj); + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); ); + + internal_wait_cond(&mutexEntry->mutex, condition, time); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); + --mutexEntry->conditionCount; + + intsRestore(); +} + +/* + * Signal the condition of an object + */ +void +signal_cond_for_object (java_objectheader *obj) +{ + iCv *condition; + + intsDisable(); + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); ); + + internal_signal_cond(condition); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); + + intsRestore(); +} + +/* + * Broadcast the condition of an object. + */ +void +broadcast_cond_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_broadcast_cond_for_object(obj); + intsRestore(); +} + +/* + * Internal: Broadcast the condition of an object. + */ +void +internal_broadcast_cond_for_object (java_objectheader *obj) +{ + iCv *condition; + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + internal_broadcast_cond(condition); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); +} + +/* + * Lock a mutex. + */ +void +lock_mutex (iMux *mux) +{ + intsDisable(); + internal_lock_mutex(mux); + intsRestore(); +} + +/* + * Lock the mutex for an object. + */ +void +lock_mutex_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_lock_mutex_for_object(obj); + intsRestore(); +} + +/* + * Unlock a mutex. + */ +void +unlock_mutex (iMux *mux) +{ + intsDisable(); + internal_unlock_mutex(mux); + intsRestore(); +} + +/* + * Unlock the mutex for an object. + */ +void +unlock_mutex_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_unlock_mutex_for_object(obj); + intsRestore(); +} + +/* + * Wait on a condition variable. + */ +void +wait_cond (iMux *mux, iCv *cond, s8 timeout) +{ + intsDisable(); + internal_wait_cond(mux, cond, timeout); + intsRestore(); +} + +/* + * Signal a condition variable. + */ +void +signal_cond (iCv *cond) +{ + intsDisable(); + internal_signal_cond(cond); + intsRestore(); +} + +/* + * Broadcast a condition variable. + */ +void +broadcast_cond (iCv *cond) +{ + intsDisable(); + internal_broadcast_cond(cond); + intsRestore(); +} + +/* + * Internal: Lock a mutex. + */ +void +internal_lock_mutex(iMux* mux) +{ + assert(blockInts == 1); + + if (mux->holder == 0) + { + mux->holder = currentThread; + mux->count = 1; + DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); ) + } + else if (mux->holder == currentThread) + { + mux->count++; + } + else + { + while (mux->holder != 0) + { + suspendOnQThread(currentThread, &mux->muxWaiters); + } + mux->holder = currentThread; + mux->count = 1; + } +} + +/* + * Internal: Release a mutex. + */ +void +internal_unlock_mutex(iMux* mux) +{ + thread* tid; + + assert(blockInts == 1); + + assert(mux->holder == currentThread); + + mux->count--; + if (mux->count == 0) + { + mux->holder = 0; + if (mux->muxWaiters != 0) + { + tid = mux->muxWaiters; + mux->muxWaiters = tid->next; + iresumeThread(tid); + } + } +} + +/* + * Internal: Wait on a conditional variable. + * (timeout currently ignored) + */ +void +internal_wait_cond(iMux* mux, iCv* cv, s8 timeout) +{ + int count; + thread* tid; + + DBG( fprintf(stderr, "waiting on %p\n", cv); ); + + if (mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + count = mux->count; + mux->holder = 0; + mux->count = 0; + cv->mux = mux; + + /* If there's anyone waiting here, wake them up */ + if (mux->muxWaiters != 0) { + tid = mux->muxWaiters; + mux->muxWaiters = tid->next; + iresumeThread(tid); + } + + /* Suspend, and keep suspended until I re-get the lock */ + suspendOnQThread(currentThread, &cv->cvWaiters); + while (mux->holder != 0) { + DBG( fprintf(stderr, "woke up\n"); ); + suspendOnQThread(currentThread, &mux->muxWaiters); + } + + mux->holder = currentThread; + mux->count = count; +} + +/* + * Internal: Wake one thread on a conditional variable. + */ +void +internal_signal_cond (iCv* cv) +{ + thread* tid; + + DBG( fprintf(stderr, "signalling on %p\n", cv); ); + + /* If 'mux' isn't set then we've never waited on this object. */ + if (cv->mux == 0) { + return; + } + + if (cv->mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + /* Remove one thread from cv list */ + if (cv->cvWaiters != 0) { + DBG( fprintf(stderr, "releasing a waiter\n"); ); + + tid = cv->cvWaiters; + cv->cvWaiters = tid->next; + + /* Place it on mux list */ + tid->next = cv->mux->muxWaiters; + cv->mux->muxWaiters = tid; + } +} + +/* + * Internal: Wake all threads on a conditional variable. + */ +void +internal_broadcast_cond (iCv* cv) +{ + thread** tidp; + + /* If 'mux' isn't set then we've never waited on this object. */ + if (cv->mux == 0) { + return; + } + + if (cv->mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + /* Find the end of the cv list */ + if (cv->cvWaiters) { + for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next) + ; + + /* Place entire cv list on mux list */ + (*tidp) = cv->mux->muxWaiters; + cv->mux->muxWaiters = cv->cvWaiters; + cv->cvWaiters = 0; + } +} + +#endif diff --git a/src/threads/green/locks.h b/src/threads/green/locks.h new file mode 100644 index 000000000..e5224677e --- /dev/null +++ b/src/threads/green/locks.h @@ -0,0 +1,141 @@ +/* + * locks.h + * Manage locking system + * This include the mutex's and cv's. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#ifndef __locks_h +#define __locks_h + +#ifdef USE_THREADS + +#include "../global.h" +#include "sysdep/defines.h" + +#define WAITFOREVER -1 + +#if defined(USE_INTERNAL_THREADS) + +struct _thread; + +typedef struct _iMux { + struct _thread *holder; + int count; + struct _thread *muxWaiters; +} iMux; + +typedef struct _iCv { + struct _thread* cvWaiters; + struct _iMux* mux; +} iCv; + +#define MAX_MUTEXES 256 + +typedef struct _mutexHashEntry +{ + java_objectheader *object; + iMux mutex; + struct _mutexHashEntry *next; + int conditionCount; +} mutexHashEntry; + +#define MUTEX_HASH_TRASH_BITS 3 +#define MUTEX_HASH_SIGN_BITS 10 + +#define MUTEX_HASH_TABLE_SIZE 1024 +#define MUTEX_OVERFLOW_TABLE_SIZE 1024 +/* +#define MAX_MUTEX_HASH_TABLE_SIZE 65536 +*/ + +/* +#define MUTEX_USE_THRESHOLD 1024 +*/ + +extern long mutexHashMask; +extern int mutexHashTableSize; +extern mutexHashEntry *mutexHashTable; + +extern mutexHashEntry *mutexOverflowTable; +extern int mutexOverflowTableSize; +extern mutexHashEntry *firstFreeOverflowEntry; + +#define MUTEX_HASH_MASK ((MUTEX_HASH_TABLE_SIZE - 1) << 3) + +#if 0 +#define MUTEX_HASH_VALUE(a) ((((long)(a)) & MUTEX_HASH_MASK) >> MUTEX_HASH_TRASH_BITS) +#else +#define MUTEX_HASH_VALUE(a) (( (((long)(a)) ^ ((long)(a) >> MUTEX_HASH_SIGN_BITS)) & mutexHashMask) >> MUTEX_HASH_TRASH_BITS) +#endif +#define MUTEX_HASH_SUCCESSOR(h) (((h) + 7) & (mutexHashTableSize - 1)) + +typedef struct _conditionHashEntry +{ + java_objectheader *object; + iCv condition; +} conditionHashEntry; + +#define CONDITION_HASH_TABLE_SIZE 1024 + +#define CONDITION_HASH_VALUE(a) ((((long)(a)) & conditionHashMask) >> 3) +#define CONDITION_HASH_SUCCESSOR(h) (((h) + 7) & (conditionHashTableSize - 1)) + +typedef struct +{ + bool free; + java_objectheader *object; + iMux mutex; + iCv condition; +} object_mutex; + +extern void initLocks (void); + +mutexHashEntry* conditionLockedMutexForObject (java_objectheader *object); + +void reorderConditionHashTable (int begin); +iCv* conditionForObject (java_objectheader *object); +iCv* addConditionForObject (java_objectheader *object); +void removeConditionForObject (java_objectheader *object); + +/* + * use these functions only outside critical sections (intsEnable/intsRestore). + */ + +void signal_cond_for_object (java_objectheader *obj); +void broadcast_cond_for_object (java_objectheader *obj); +void wait_cond_for_object (java_objectheader *obj, s8 time); +void lock_mutex_for_object (java_objectheader *obj); +void unlock_mutex_for_object (java_objectheader *obj); + +void lock_mutex (iMux*); +void unlock_mutex (iMux*); +void wait_cond (iMux*, iCv*, s8); +void signal_cond (iCv*); +void broadcast_cond (iCv*); + +/* + * use these internal functions only in critical sections. blockInts must be exactly + * 1. + */ +void internal_lock_mutex (iMux*); +void internal_unlock_mutex (iMux*); +void internal_wait_cond (iMux*, iCv*, s8); +void internal_signal_cond (iCv*); +void internal_broadcast_cond (iCv*); + +void internal_lock_mutex_for_object (java_objectheader *obj); +void internal_unlock_mutex_for_object (java_objectheader *obj); +void internal_broadcast_cond_for_object (java_objectheader *obj); + +#endif + +#endif /* USE_THREADS */ + +#endif /* __locks_h */ diff --git a/src/threads/green/threadio.c b/src/threads/green/threadio.c new file mode 100644 index 000000000..e538b409a --- /dev/null +++ b/src/threads/green/threadio.c @@ -0,0 +1,358 @@ +/* + * threadCalls.c + * Support for threaded ops which may block (read, write, connect, etc.). + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#define DBG(s) + +#include "sysdep/defines.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" + +/* + * We only need this stuff is we are using the internal thread system. + */ +#if defined(USE_INTERNAL_THREADS) + +#define TH_READ 0 +#define TH_WRITE 1 +#define TH_ACCEPT TH_READ +#define TH_CONNECT TH_WRITE + +static int maxFd; +static fd_set readsPending; +static fd_set writesPending; +static thread* readQ[FD_SETSIZE]; +static thread* writeQ[FD_SETSIZE]; +static struct timeval tm = { 0, 0 }; + +void blockOnFile(int, int); +void waitOnEvents(void); + +extern thread* currentThread; + +/* These are undefined because we do not yet support async I/O */ +#undef F_SETOWN +#undef FIOSETOWN +#undef O_ASYNC +#undef FIOASYNC + +/* + * Create a threaded file descriptor. + */ +int +threadedFileDescriptor(int fd) +{ +#if !defined(BLOCKING_CALLS) + int r; + int on = 1; + int pid; + + /* Make non-blocking */ +#if defined(HAVE_FCNTL) && defined(O_NONBLOCK) + r = fcntl(fd, F_GETFL, 0); + r = fcntl(fd, F_SETFL, r|O_NONBLOCK); +#elif defined(HAVE_IOCTL) && defined(FIONBIO) + r = ioctl(fd, FIONBIO, &on); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } + + /* Allow socket to signal this process when new data is available */ + pid = getpid(); +#if defined(HAVE_FCNTL) && defined(F_SETOWN) + r = fcntl(fd, F_SETOWN, pid); +#elif defined(HAVE_IOCTL) && defined(FIOSETOWN) + r = ioctl(fd, FIOSETOWN, &pid); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } + +#if defined(HAVE_FCNTL) && defined(O_ASYNC) + r = fcntl(fd, F_GETFL, 0); + r = fcntl(fd, F_SETFL, r|O_ASYNC); +#elif defined(HAVE_IOCTL) && defined(FIOASYNC) + r = ioctl(fd, FIOASYNC, &on); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } +#endif + return (fd); +} + +/* + * Threaded create socket. + */ +int +threadedSocket(int af, int type, int proto) +{ + int fd; + int r; + int on = 1; + int pid; + + fd = socket(af, type, proto); + return (threadedFileDescriptor(fd)); +} + +/* + * Threaded file open. + */ +int +threadedOpen(char* path, int flags, int mode) +{ + int fd; + int r; + int on = 1; + int pid; + + fd = open(path, flags, mode); + return (threadedFileDescriptor(fd)); +} + +/* + * Threaded socket connect. + */ +int +threadedConnect(int fd, struct sockaddr* addr, int len) +{ + int r; + + r = connect(fd, addr, len); +#if !defined(BLOCKING_CALLS) + if ((r < 0) + && (errno == EINPROGRESS || errno == EALREADY + || errno == EWOULDBLOCK)) { + blockOnFile(fd, TH_CONNECT); + r = 0; /* Assume it's okay when we get released */ + } +#endif + + return (r); +} + +/* + * Threaded socket accept. + */ +int +threadedAccept(int fd, struct sockaddr* addr, int* len) +{ + int r; + int on = 1; + + for (;;) + { +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_ACCEPT); +#endif + r = accept(fd, addr, len); + if (r >= 0 + || !(errno == EINPROGRESS || errno == EALREADY + || errno == EWOULDBLOCK)) + { + break; + } +#if !defined(BLOCKING_CALLS) + blockOnFile(fd, TH_ACCEPT); +#endif + } + return (threadedFileDescriptor(r)); +} + +/* + * Read but only if we can. + */ +int +threadedRead(int fd, char* buf, int len) +{ + int r; + + DBG( printf("threadedRead\n"); ) + +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_READ); +#endif + for (;;) + { + r = read(fd, buf, len); + if (r < 0 + && (errno == EAGAIN || errno == EWOULDBLOCK + || errno == EINTR)) + { + blockOnFile(fd, TH_READ); + continue; + } + return (r); + } +} + +/* + * Write but only if we can. + */ +int +threadedWrite(int fd, char* buf, int len) +{ + int r; + char* ptr; + + ptr = buf; + r = 1; + + DBG( printf("threadedWrite %dbytes\n",len); ) + + while (len > 0 && r > 0) + { +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_WRITE); +#endif + r = write(fd, ptr, len); + if (r < 0 + && (errno == EAGAIN || errno == EWOULDBLOCK + || errno == EINTR)) + { +#if !defined(BLOCKING_CALLS) + blockOnFile(fd, TH_WRITE); +#endif + r = 1; + } + else + { + ptr += r; + len -= r; + } + } + return (ptr - buf); +} + +/* + * An attempt to access a file would block, so suspend the thread until + * it will happen. + */ +void +blockOnFile(int fd, int op) +{ +DBG( printf("blockOnFile()\n"); ) + + intsDisable(); + + if (fd > maxFd) + { + maxFd = fd; + } + if (op == TH_READ) + { + FD_SET(fd, &readsPending); + suspendOnQThread(currentThread, &readQ[fd]); + FD_CLR(fd, &readsPending); + } + else + { + FD_SET(fd, &writesPending); + suspendOnQThread(currentThread, &writeQ[fd]); + FD_CLR(fd, &writesPending); + } + + intsRestore(); +} + +/* + * Check if some file descriptor or other event to become ready. + * Block if required (but make sure we can still take timer interrupts). + */ +void +checkEvents(bool block) +{ + int r; + fd_set rd; + fd_set wr; + thread* tid; + thread* ntid; + int i; + int b; + +DBG( printf("checkEvents block:%d\n", block); ) + +#if defined(FD_COPY) + FD_COPY(&readsPending, &rd); + FD_COPY(&writesPending, &wr); +#else + memcpy(&rd, &readsPending, sizeof(rd)); + memcpy(&wr, &writesPending, sizeof(wr)); +#endif + + /* + * If select() is called with indefinite wait, we have to make sure + * we can get interrupted by timer events. + */ + if (block == true) + { + b = blockInts; + blockInts = 0; + r = select(maxFd+1, &rd, &wr, 0, 0); + blockInts = b; + } + else + { + r = select(maxFd+1, &rd, &wr, 0, &tm); + } + + /* We must be holding off interrupts before we start playing with + * the read and write queues. This should be already done but a + * quick check never hurt anyone. + */ + assert(blockInts > 0); + +DBG( printf("Select returns %d\n", r); ) + + for (i = 0; r > 0 && i <= maxFd; i++) + { + if (readQ[i] != 0 && FD_ISSET(i, &rd)) + { + for (tid = readQ[i]; tid != 0; tid = ntid) + { + ntid = tid->next; + iresumeThread(tid); + } + readQ[i] = 0; + r--; + } + if (writeQ[i] != 0 && FD_ISSET(i, &wr)) + { + for (tid = writeQ[i]; tid != 0; tid = ntid) + { + ntid = tid->next; + iresumeThread(tid); + } + writeQ[i] = 0; + r--; + } + } +} +#endif diff --git a/src/threads/green/threadio.h b/src/threads/green/threadio.h new file mode 100644 index 000000000..1e9d5c2a2 --- /dev/null +++ b/src/threads/green/threadio.h @@ -0,0 +1,26 @@ +/* -*- c -*- */ + +#ifndef __threadio_h_ +#define __threadio_h_ + +#include +#include + +#include "../global.h" + +#ifdef USE_THREADS +int threadedFileDescriptor(int fd); +int threadedSocket(int af, int type, int proto); +int threadedOpen(char* path, int flags, int mode); +int threadedConnect(int fd, struct sockaddr* addr, int len); +int threadedAccept(int fd, struct sockaddr* addr, int* len); +int threadedRead(int fd, char* buf, int len); +int threadedWrite(int fd, char* buf, int len); +#else +#define threadedFileDescriptor(fd) +#define threadedRead(fd,buf,len) read(fd,buf,len) +#define threadedWrite(fd,buf,len) write(fd,buf,len) +#endif + + +#endif diff --git a/src/threads/green/threads.c b/src/threads/green/threads.c new file mode 100644 index 000000000..89dde1d28 --- /dev/null +++ b/src/threads/green/threads.c @@ -0,0 +1,681 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/* + * thread.c + * Thread support. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#include + +#include +#include /* for mprotect */ +#include + +#include "thread.h" +#include "locks.h" +#include "sysdep/defines.h" +#include "sysdep/threads.h" + +#include "../tables.h" +#include "../native.h" +#include "../loader.h" +#include "../builtin.h" +#include "../asmpart.h" + +static classinfo *class_java_lang_ThreadDeath; + +#if 1 +#define DBG(s) +#define SDBG(s) +#else +#define DBG(s) s +#define SDBG(s) s +#endif + +#if defined(USE_INTERNAL_THREADS) + +thread* currentThread; +thread* threadQhead[MAX_THREAD_PRIO + 1]; +thread* threadQtail[MAX_THREAD_PRIO + 1]; + +thread* liveThreads; +thread* alarmList; + +thread* gcDaemonThread; + +int blockInts; +bool needReschedule; + +ctx contexts[MAXTHREADS]; + +/* Number of threads alive, also counting daemons */ +static int talive; + +/* Number of daemon threads alive */ +static int tdaemon; + +static void firstStartThread(void); + +void reschedule(void); + +/* Setup default thread stack size - this can be overwritten if required */ +int threadStackSize = THREADSTACKSIZE; + +static thread* startDaemon(void* func, char* nm, int stackSize); + +/* + * Allocate the stack for a thread + */ +void +allocThreadStack (thread *tid, int size) +{ + int pageSize = getpagesize(), + result; + unsigned long pageBegin; + + CONTEXT(tid).stackMem = malloc(size + 2 * pageSize); + assert(CONTEXT(tid).stackMem != 0); + CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize; + + pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1; + pageBegin = pageBegin - pageBegin % pageSize; + + result = mprotect((void*)pageBegin, pageSize, PROT_NONE); + assert(result == 0); + + CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize; +} + +/* + * Free the stack for a thread + */ +void +freeThreadStack (thread *tid) +{ + if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC)) + { + int pageSize = getpagesize(), + result; + unsigned long pageBegin; + + pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1; + pageBegin = pageBegin - pageBegin % pageSize; + + result = mprotect((void*)pageBegin, pageSize, + PROT_READ | PROT_WRITE | PROT_EXEC); + assert(result == 0); + + free(CONTEXT(tid).stackMem); + } + CONTEXT(tid).stackMem = 0; + CONTEXT(tid).stackBase = 0; + CONTEXT(tid).stackEnd = 0; +} + +/* + * Initialize threads. + */ +void +initThreads(u1 *stackbottom) +{ + int i; + + initLocks(); + + for (i = 0; i < MAXTHREADS; ++i) + contexts[i].free = true; + + /* Allocate a thread to be the main thread */ + currentThread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread"))); + assert(currentThread != 0); + + currentThread->PrivateInfo = 1; + CONTEXT(currentThread).free = false; + + liveThreads = currentThread; + + currentThread->name = javastring_new(unicode_new_char("main")); + currentThread->priority = NORM_THREAD_PRIO; + CONTEXT(currentThread).priority = (u1)currentThread->priority; + CONTEXT(currentThread).exceptionptr = 0; + currentThread->next = 0; + CONTEXT(currentThread).status = THREAD_SUSPENDED; + CONTEXT(currentThread).stackBase = CONTEXT(currentThread).stackEnd = stackbottom; + THREADINFO(&CONTEXT(currentThread)); + + DBG( printf("main thread %p base %p end %p\n", + currentThread, + CONTEXT(currentThread).stackBase, + CONTEXT(currentThread).stackEnd); ); + + CONTEXT(currentThread).flags = THREAD_FLAGS_NOSTACKALLOC; + CONTEXT(currentThread).nextlive = 0; + currentThread->single_step = 0; + currentThread->daemon = 0; + currentThread->stillborn = 0; + currentThread->target = 0; + currentThread->interruptRequested = 0; + currentThread->group = + (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup"))); + /* we should call the constructor */ + assert(currentThread->group != 0); + + talive++; + + /* Add thread into runQ */ + iresumeThread(currentThread); + + /* Start garbage collection thread */ + gcDaemonThread = startDaemon(gc_thread, "gc", 1024*512); + iresumeThread(gcDaemonThread); + + heap_addreference((void**)&gcDaemonThread); + + /* Load exception classes */ + class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath")); + + DBG( fprintf(stderr, "finishing initThreads\n"); ); + + assert(blockInts == 0); +} + +/* + * Start a new thread running. + */ +void +startThread (thread* tid) +{ + int i; + + /* Allocate a stack context */ + for (i = 0; i < MAXTHREADS; ++i) + if (contexts[i].free) + break; + + if (i == MAXTHREADS) + panic("Too many threads"); + + tid->PrivateInfo = i + 1; + CONTEXT(tid).free = false; + CONTEXT(tid).nextlive = liveThreads; + liveThreads = tid; + allocThreadStack(tid, threadStackSize); + CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase; + CONTEXT(tid).flags = THREAD_FLAGS_GENERAL; + CONTEXT(tid).status = THREAD_SUSPENDED; + CONTEXT(tid).priority = (u1)tid->priority; + CONTEXT(tid).exceptionptr = 0; + + /* Construct the initial restore point. */ + THREADINIT((&CONTEXT(tid)), firstStartThread); + + DBG( printf("new thread %p base %p end %p\n", + tid, CONTEXT(tid).stackBase, + CONTEXT(tid).stackEnd); ); + + talive++; + if (tid->daemon) + tdaemon++; + + /* Add thread into runQ */ + iresumeThread(tid); +} + +/* + * Start a daemon thread. + */ +static thread* +startDaemon(void* func, char* nm, int stackSize) +{ + thread* tid; + int i; + + DBG( printf("startDaemon %s\n", nm); ); + + tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread"))); + assert(tid != 0); + + for (i = 0; i < MAXTHREADS; ++i) + if (contexts[i].free) + break; + if (i == MAXTHREADS) + panic("Too many threads"); + + tid->PrivateInfo = i + 1; + CONTEXT(tid).free = false; + tid->name = 0; /* for the moment */ + tid->priority = MAX_THREAD_PRIO; + CONTEXT(tid).priority = (u1)tid->priority; + tid->next = 0; + CONTEXT(tid).status = THREAD_SUSPENDED; + + allocThreadStack(tid, stackSize); + tid->single_step = 0; + tid->daemon = 1; + tid->stillborn = 0; + tid->target = 0; + tid->interruptRequested = 0; + tid->group = 0; + + /* Construct the initial restore point. */ + THREADINIT((&CONTEXT(tid)), func); + + talive++; + tdaemon++; + + return tid; +} + +/* + * All threads start here. + */ +static void +firstStartThread(void) +{ + methodinfo *method; + + DBG( printf("firstStartThread %p\n", currentThread); ); + + /* Every thread starts with the interrupts off */ + intsRestore(); + assert(blockInts == 0); + + /* Find the run()V method and call it */ + method = class_findmethod(currentThread->header.vftbl->class, + unicode_new_char("run"), unicode_new_char("()V")); + if (method == 0) + panic("Cannot find method \'void run ()\'"); + asm_calljavamethod(method, currentThread, NULL, NULL, NULL); + + killThread(0); + assert("Thread returned from killThread" == 0); +} + +/* + * Resume a thread running. + * This routine has to be called only from locations which ensure + * run / block queue consistency. There is no check for illegal resume + * conditions (like explicitly resuming an IO blocked thread). There also + * is no update of any blocking queue. Both has to be done by the caller + */ +void +iresumeThread(thread* tid) +{ + DBG( printf("resumeThread %p\n", tid); ); + + intsDisable(); + + if (CONTEXT(tid).status != THREAD_RUNNING) + { + CONTEXT(tid).status = THREAD_RUNNING; + + DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); ); + + /* Place thread on the end of its queue */ + if (threadQhead[CONTEXT(tid).priority] == 0) { + threadQhead[CONTEXT(tid).priority] = tid; + threadQtail[CONTEXT(tid).priority] = tid; + if (CONTEXT(tid).priority + > CONTEXT(currentThread).priority) + needReschedule = true; + } + else + { + threadQtail[CONTEXT(tid).priority]->next = tid; + threadQtail[CONTEXT(tid).priority] = tid; + } + tid->next = 0; + } + SDBG( else { printf("Re-resuming %p\n", tid); } ); + + intsRestore(); +} + +/* + * Yield process to another thread of equal priority. + */ +void +yieldThread() +{ + intsDisable(); + + if (threadQhead[CONTEXT(currentThread).priority] + != threadQtail[CONTEXT(currentThread).priority]) + { + /* Get the next thread and move me to the end */ + threadQhead[CONTEXT(currentThread).priority] = currentThread->next; + threadQtail[CONTEXT(currentThread).priority]->next = currentThread; + threadQtail[CONTEXT(currentThread).priority] = currentThread; + currentThread->next = 0; + needReschedule = true; + } + + intsRestore(); +} + +/* + * Explicit request by user to resume a thread + * The definition says that it is just legal to call this after a preceeding + * suspend (which got through). If the thread was blocked for some other + * reason (either sleep or IO or a muxSem), we simply can't do it + * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose + * (which is set by suspendThread(.)) + */ +void +resumeThread(thread* tid) +{ + if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0) + { + intsDisable(); + CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND; + iresumeThread(tid); + intsRestore(); + } +} + +/* + * Suspend a thread. + * This is an explicit user request to suspend the thread - the counterpart + * for resumeThreadRequest(.). It is JUST called by the java method + * Thread.suspend() + * What makes it distinct is the fact that the suspended thread is not contained + * in any block queue. Without a special flag (indicating the user suspend), we + * can't check s suspended thread for this condition afterwards (which is + * required by resumeThreadRequest()). The new thread flag + * THREAD_FLAGS_USER_SUSPEND is used for this purpose. + */ +void +suspendThread(thread* tid) +{ + thread** ntid; + + intsDisable(); + + if (CONTEXT(tid).status != THREAD_SUSPENDED) + { + CONTEXT(tid).status = THREAD_SUSPENDED; + + /* + * This is used to indicate the explicit suspend condition + * required by resumeThreadRequest() + */ + CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND; + + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + tid->next = 0; + if (tid == currentThread) + { + reschedule(); + } + break; + } + } + } + SDBG( else { printf("Re-suspending %p\n", tid); } ); + + intsRestore(); +} + +/* + * Suspend a thread on a queue. + */ +void +suspendOnQThread(thread* tid, thread** queue) +{ + thread** ntid; + + DBG( printf("suspendOnQThread %p %p\n", tid, queue); ); + + assert(blockInts == 1); + + if (CONTEXT(tid).status != THREAD_SUSPENDED) + { + CONTEXT(tid).status = THREAD_SUSPENDED; + + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + /* Insert onto head of lock wait Q */ + tid->next = *queue; + *queue = tid; + if (tid == currentThread) + { + DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n", + tid, currentThread, CONTEXT(tid).priority); ); + reschedule(); + } + break; + } + } + } + SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } ); +} + +/* + * Kill thread. + */ +void +killThread(thread* tid) +{ + thread** ntid; + + intsDisable(); + + /* A null tid means the current thread */ + if (tid == 0) + { + tid = currentThread; + } + + DBG( printf("killThread %p\n", tid); ); + + if (CONTEXT(tid).status != THREAD_DEAD) + { + /* Get thread off runq (if it needs it) */ + if (CONTEXT(tid).status == THREAD_RUNNING) + { + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + break; + } + } + } + + CONTEXT(tid).status = THREAD_DEAD; + talive--; + if (tid->daemon) { + tdaemon--; + } + + /* If we only have daemons left, then everyone is dead. */ + if (talive == tdaemon) { + /* Am I suppose to close things down nicely ?? */ + exit(0); + } + + /* Notify on the object just in case anyone is waiting */ + internal_lock_mutex_for_object(&tid->header); + internal_broadcast_cond_for_object(&tid->header); + internal_unlock_mutex_for_object(&tid->header); + + /* Remove thread from live list to it can be garbaged */ + for (ntid = &liveThreads; + *ntid != 0; + ntid = &(CONTEXT((*ntid)).nextlive)) + { + if (tid == (*ntid)) + { + (*ntid) = CONTEXT(tid).nextlive; + break; + } + } + + /* Free stack */ + freeThreadStack(tid); + + /* free context */ + CONTEXT(tid).free = true; + + /* Run something else */ + needReschedule = true; + } + intsRestore(); +} + +/* + * Change thread priority. + */ +void +setPriorityThread(thread* tid, int prio) +{ + thread** ntid; + + if (tid->PrivateInfo == 0) { + tid->priority = prio; + return; + } + + if (CONTEXT(tid).status == THREAD_SUSPENDED) { + CONTEXT(tid).priority = (u8)prio; + return; + } + + intsDisable(); + + /* Remove from current thread list */ + for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) { + if (*ntid == tid) { + *ntid = tid->next; + break; + } + } + + /* Insert onto a new one */ + tid->priority = prio; + CONTEXT(tid).priority = (u8)tid->priority; + if (threadQhead[prio] == 0) { + threadQhead[prio] = tid; + threadQtail[prio] = tid; + if (prio > CONTEXT(currentThread).priority) { + needReschedule = true; + } + } + else { + threadQtail[prio]->next = tid; + threadQtail[prio] = tid; + } + tid->next = 0; + + intsRestore(); +} + +/* + * Is this thread alive? + */ +bool +aliveThread(thread* tid) +{ + if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD) + return (true); + else + return (false); +} + +/* + * Reschedule the thread. + * Called whenever a change in the running thread is required. + */ +void +reschedule(void) +{ + int i; + thread* lastThread; + int b; + /* sigset_t nsig; */ + + /* A reschedule in a non-blocked context is half way to hell */ + assert(blockInts > 0); + b = blockInts; + + /* Check events - we may release a high priority thread */ + /* Just check IO, no need for a reschedule call by checkEvents() */ + needReschedule = false; + checkEvents(false); + + for (;;) + { + for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--) + { + if (threadQhead[i] != 0) + { + DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); ); + + if (threadQhead[i] != currentThread) + { + USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); + + lastThread = currentThread; + currentThread = threadQhead[i]; + + CONTEXT(currentThread).exceptionptr = exceptionptr; + + THREADSWITCH((&CONTEXT(currentThread)), + (&CONTEXT(lastThread))); + blockInts = b; + + exceptionptr = CONTEXT(currentThread).exceptionptr; + + /* Alarm signal may be blocked - if so + * unblock it. + */ + /* + if (alarmBlocked == true) { + alarmBlocked = false; + sigemptyset(&nsig); + sigaddset(&nsig, SIGALRM); + sigprocmask(SIG_UNBLOCK, &nsig, 0); + } + */ + + /* I might be dying */ + if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED) + != 0) + { + CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED; + exceptionptr = native_new_and_init(class_java_lang_ThreadDeath); + } + } + /* Now we kill the schedule and turn ints + back on */ + needReschedule = false; + return; + } + } + /* Nothing to run - wait for external event */ + DBG( fprintf(stderr, "nothing more to do\n"); ); + checkEvents(true); + } +} + +#endif diff --git a/src/threads/green/threads.h b/src/threads/green/threads.h new file mode 100644 index 000000000..1f72d9e9e --- /dev/null +++ b/src/threads/green/threads.h @@ -0,0 +1,151 @@ +/* + * thread.h + * Thread support. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#ifndef __thread_h +#define __thread_h + +#ifdef USE_THREADS + +#include "../global.h" + +#define MAXTHREADS 256 /* schani */ + +#define THREADCLASS "java/lang/Thread" +#define THREADGROUPCLASS "java/lang/ThreadGroup" +#define THREADDEATHCLASS "java/lang/ThreadDeath" + +#define MIN_THREAD_PRIO 1 +#define NORM_THREAD_PRIO 5 +#define MAX_THREAD_PRIO 10 + +#define THREAD_SUSPENDED 0 +#define THREAD_RUNNING 1 +#define THREAD_DEAD 2 +#define THREAD_KILL 3 + +#define THREAD_FLAGS_GENERAL 0 +#define THREAD_FLAGS_NOSTACKALLOC 1 +#define THREAD_FLAGS_USER_SUSPEND 2 /* Flag explicit suspend() call */ +#define THREAD_FLAGS_KILLED 4 + +struct _thread; + +typedef struct _ctx +{ + bool free; /* schani */ + u1 status; + u1 priority; + u1* restorePoint; + u1* stackMem; /* includes guard page */ + u1* stackBase; + u1* stackEnd; + u1* usedStackTop; + s8 time; + java_objectheader *exceptionptr; + struct _thread *nextlive; + u1 flags; +} ctx; + +/* +struct _stringClass; +struct _object; +*/ + +/* This structure mirrors java.lang.ThreadGroup.h */ + +typedef struct _threadGroup +{ + java_objectheader header; + struct _threadGroup* parent; + java_objectheader* name; + s4 maxPrio; + s4 destroyed; + s4 daemon; + s4 nthreads; + java_objectheader* threads; + s4 ngroups; + java_objectheader* groups; +} threadGroup; + +/* This structure mirrors java.lang.Thread.h */ +typedef struct _thread +{ + java_objectheader header; + java_objectheader* name; + s4 priority; + struct _thread* next; + s8 PrivateInfo; + struct java_lang_Object* eetop; /* ??? */ + s4 single_step; + s4 daemon; + s4 stillborn; + java_objectheader* target; + s4 interruptRequested; + threadGroup* group; +} thread; + +void initThreads(u1 *stackbottom); +void startThread(thread*); +void resumeThread(thread*); +void iresumeThread(thread*); +void suspendThread(thread*); +void suspendOnQThread(thread*, thread**); +void yieldThread(void); +void killThread(thread*); +void setPriorityThread(thread*, int); + +void sleepThread(s8); +bool aliveThread(thread*); +long framesThread(thread*); + +void reschedule(void); + +void checkEvents(bool block); + +extern int blockInts; +extern bool needReschedule; +extern thread *currentThread; +extern ctx contexts[]; +extern int threadStackSize; + +extern thread *liveThreads; + +extern thread *threadQhead[MAX_THREAD_PRIO + 1]; + +#define CONTEXT(_t) \ + (contexts[(_t)->PrivateInfo - 1]) + +#if 1 +#define intsDisable() blockInts++ +#define intsRestore() if (blockInts == 1 && needReschedule) { \ + reschedule(); \ + } \ + blockInts-- +#else +#define intsDisable() do { blockInts++; fprintf(stderr, "++: %d (%s:%d)\n", blockInts, __FILE__, __LINE__); } while (0) +#define intsRestore() do { \ + if (blockInts == 1 && needReschedule) { \ + reschedule(); \ + } \ + blockInts--; \ + fprintf(stderr, "--: %d (%s:%d)\n", blockInts, __FILE__, __LINE__); \ + } while (0) +#endif + +#else + +#define intsDisable() +#define intsRestore() + +#endif + +#endif diff --git a/src/toolbox/chain.c b/src/toolbox/chain.c new file mode 100644 index 000000000..7e50617d1 --- /dev/null +++ b/src/toolbox/chain.c @@ -0,0 +1,243 @@ +/************************* toolbox/chain.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see chain.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include + +#include "memory.h" +#include "chain.h" + + + +chain *chain_new () +{ + chain *c; + + c = NEW (chain); + c -> usedump = 0; + c -> first = NULL; + c -> last = NULL; + c -> active = NULL; + + return c; +} + +chain *chain_dnew () +{ + chain *c; + + c = DNEW (chain); + c -> usedump = 1; + c -> first = NULL; + c -> last = NULL; + c -> active = NULL; + + return c; +} + + +void chain_free (chain *c) +{ + chainlink *l; + + assert (! c->usedump); + + l = c->first; + while (l) { + chainlink *nextl = l->next; + + FREE (l, chainlink); + l = nextl; + } + + FREE (c, chain); +} + + +void chain_addafter(chain *c, void *element) +{ + chainlink *active,*newlink; + + active = c->active; + + if (c -> usedump) newlink = DNEW (chainlink); + else newlink = NEW (chainlink); + + newlink -> element = element; + + if (active) { + newlink -> next = active -> next; + newlink -> prev = active; + + active -> next = newlink; + if (newlink -> next) newlink -> next -> prev = newlink; + else c -> last = newlink; + } + else { + newlink -> next = NULL; + newlink -> prev = NULL; + + c -> active = newlink; + c -> first = newlink; + c -> last = newlink; + } +} + + +void chain_addbefore(chain *c, void *element) +{ + chainlink *active,*newlink; + + active = c->active; + + if (c -> usedump) newlink = DNEW (chainlink); + else newlink = NEW (chainlink); + + newlink -> element = element; + + if (active) { + newlink -> next = active; + newlink -> prev = active -> prev; + + active -> prev = newlink; + if (newlink -> prev) newlink -> prev -> next = newlink; + else c -> first = newlink; + } + else { + newlink -> next = NULL; + newlink -> prev = NULL; + + c -> active = newlink; + c -> first = newlink; + c -> last = newlink; + } +} + +void chain_addlast (chain *c, void *e) +{ + chain_last (c); + chain_addafter (c, e); +} + +void chain_addfirst (chain *c, void *e) +{ + chain_first (c); + chain_addbefore (c, e); +} + + +void chain_remove (chain *c) +{ + chainlink *active; + + active = c -> active; + assert (active); + + if (active -> next) { + active -> next -> prev = active -> prev; + } + else { + c -> last = active -> prev; + } + + if (active -> prev) { + active -> prev -> next = active -> next; + } + else { + c -> first = active -> next; + } + + + if (active->prev) + c -> active = active->prev; + else + c -> active = active->next; + + if (! c -> usedump) FREE (active, chainlink); +} + + +void *chain_remove_go_prev (chain *c) +{ + chain_remove (c); + return chain_this (c); +} + + + +void chain_removespecific(chain *c, void *e) +{ + void *ce; + + ce = chain_first (c); + while (ce) { + if (e == ce) { chain_remove (c); return; } + ce = chain_next (c); + } + +} + +void *chain_next(chain *c) +{ + chainlink *active; + + active = c -> active; + if (!active) return NULL; + + if (active -> next) { + c -> active = active -> next; + return c -> active -> element; + } + + return NULL; +} + +void *chain_prev(chain *c) +{ + chainlink *active; + + active = c -> active; + if (!active) return NULL; + + if (active -> prev) { + c -> active = active -> prev; + return c -> active -> element; + } + + return NULL; +} + + +void *chain_this(chain *c) +{ + if (c -> active) return c -> active -> element; + return NULL; +} + + +void *chain_first(chain *c) +{ + c -> active = c -> first; + if (c -> active) return c -> active -> element; + return NULL; +} + +void *chain_last(chain *c) +{ + c -> active = c -> last; + if (c -> active) return c -> active -> element;; + return NULL; +} + diff --git a/src/toolbox/chain.h b/src/toolbox/chain.h new file mode 100644 index 000000000..e065c07fe --- /dev/null +++ b/src/toolbox/chain.h @@ -0,0 +1,92 @@ +/************************* toolbox/chain.h ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + dient zur Verwaltung doppelt verketteter Listen mit externer Verkettung + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef struct chainlink { /* Struktur f"ur ein Listenelement */ + struct chainlink *next,*prev; + void *element; + } chainlink; + +typedef struct chain { /* Struktur f"ur eine Liste */ + int usedump; + + chainlink *first,*last; + chainlink *active; + } chain; + + +chain *chain_new (); +chain *chain_dnew (); +void chain_free(chain *c); + +void chain_addafter(chain *c, void *element); +void chain_addbefore(chain *c, void *element); +void chain_addlast (chain *c, void *element); +void chain_addfirst (chain *c, void *element); + +void chain_remove(chain *c); +void *chain_remove_go_prev(chain *c); +void chain_removespecific(chain *c, void *element); + +void *chain_next(chain *c); +void *chain_prev(chain *c); +void *chain_this(chain *c); + +void *chain_first(chain *c); +void *chain_last(chain *c); + + +/* +--------------------------- Schnittstellenbeschreibung ------------------------ + +Bei Verwendung dieser Funktionen f"ur die Listenverwaltung mu"s, im +Gegenstatz zum Modul 'list', keine zus"atzliche Vorbereitung in den +Element-Strukturen gemacht werden. + +Diese Funktionen sind daher auch ein wenig langsamer und brauchen +mehr Speicher. + +Eine neue Liste wird mit + chain_new + oder chain_dnew +angelegt. Der Unterschied ist, da"s bei der zweiten Variante alle +zus"atzlichen Datenstrukturen am DUMP-Speicher angelegt werden (was +schneller geht, und ein explizites Freigeben am Ende der Verarbeitung +unn"otig macht). Dabei mu"s man aber achtgeben, da"s man nicht +versehentlich Teile dieser Strukturen durch ein verfr"uhtes 'dump_release' +freigibt. + +Eine nicht mehr verwendete Liste kann mit + chain_free +freigegeben werden (nur verwenden, wenn mit 'chain_new' angefordert) + + +Das Eintragen neuer Elemente geht sehr einfach mit: + chain_addafter, chain_addlast, chain_addbefore, chain_addfirst + +Durchsuchen der Liste mit: + chain_first, chain_last, chain_prev, chain_next, chain_this + +L"oschen von Elementen aus der Liste: + chain_remove, chain_remove_go_prev, chain_removespecific + + +ACHTUNG: In den zu verkettenden Elementen gibt es ja (wie oben gesagt) keine + Referenzen auf die Liste oder irgendwelche Listenknoten, deshalb k"onnen + die Elemente nicht als Ortsangabe innerhalb der Liste fungieren. + Es gibt vielmehr ein Art 'Cursor', der ein Element als das gerade + aktuelle festh"alt, und alle Ein-/und Ausf"ugeoperationen geschehen + relativ zu diesem Cursor. + +*/ + diff --git a/src/toolbox/list.c b/src/toolbox/list.c new file mode 100644 index 000000000..6183684d5 --- /dev/null +++ b/src/toolbox/list.c @@ -0,0 +1,107 @@ +/************************** toolbox/list.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see chain.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include + +#include "list.h" + + +void list_init (list *l, int nodeoffset) +{ + l->first = NULL; + l->last = NULL; + l->nodeoffset = nodeoffset; +} + +void list_addlast (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (l->last) { + n->prev = l->last; + n->next = NULL; + l->last->next = n; + l->last = n; + } + else { + n->prev = NULL; + n->next = NULL; + l->last = n; + l->first = n; + } +} + +void list_addfirst (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (l->first) { + n->prev = NULL; + n->next = l->first; + l->first->prev = n; + l->first = n; + } + else { + n->prev = NULL; + n->next = NULL; + l->last = n; + l->first = n; + } +} + + +void list_remove (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (n->next) n->next->prev = n->prev; + else l->last = n->prev; + if (n->prev) n->prev->next = n->next; + else l->first = n->next; +} + + +void *list_first (list *l) +{ + if (!l->first) return NULL; + return ((char*) l->first) - l->nodeoffset; +} + + +void *list_last (list *l) +{ + if (!l->last) return NULL; + return ((char*) l->last) - l->nodeoffset; +} + + +void *list_next (list *l, void *element) +{ + listnode *n; + n = (listnode*) ( ((char*) element) + l->nodeoffset ); + if (!n->next) return NULL; + return ((char*) n->next) - l->nodeoffset; +} + + +void *list_prev (list *l, void *element) +{ + listnode *n; + n = (listnode*) ( ((char*) element) + l->nodeoffset ); + if (!n->prev) return NULL; + return ((char*) n->prev) - l->nodeoffset; +} + diff --git a/src/toolbox/list.h b/src/toolbox/list.h new file mode 100644 index 000000000..22f7ec061 --- /dev/null +++ b/src/toolbox/list.h @@ -0,0 +1,97 @@ +/************************** toolbox/list.h ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Verwaltung von doppelt verketteten Listen. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef struct listnode { /* Struktur f"ur ein Listenelement */ + struct listnode *next,*prev; + } listnode; + +typedef struct list { /* Struktur f"ur den Listenkopf */ + listnode *first,*last; + int nodeoffset; + } list; + + +void list_init (list *l, int nodeoffset); + +void list_addlast (list *l, void *element); +void list_addfirst (list *l, void *element); + +void list_remove (list *l, void *element); + +void *list_first (list *l); +void *list_last (list *l); + +void *list_next (list *l, void *element); +void *list_prev (list *l, void *element); + + +/* +---------------------- Schnittstellenbeschreibung ----------------------------- + +Die Listenverwaltung mit diesem Modul geht so vor sich: + + - jede Struktur, die in die Liste eingeh"angt werden soll, mu"s + eine Komponente vom Typ 'listnode' haben. + + - es mu"s ein Struktur vom Typ 'list' bereitgestellt werden. + + - die Funktion list_init (l, nodeoffset) initialisiert diese Struktur, + dabei gibt der nodeoffset den Offset der 'listnode'-Komponente in + den Knotenstrukturen an. + + - Einf"ugen, Aush"angen und Suchen von Elementen der Liste geht mit + den "ubrigen Funktionen. + +Zum besseren Verst"andnis ein kleines Beispiel: + + + void bsp() { + struct node { + listnode linkage; + int value; + } a,b,c, *el; + + list l; + + a.value = 7; + b.value = 9; + c.value = 11; + + list_init (&l, OFFSET(struct node,linkage) ); + list_addlast (&l, a); + list_addlast (&l, b); + list_addlast (&l, c); + + e = list_first (&l); + while (e) { + printf ("Element: %d\n", e->value); + e = list_next (&l,e); + } + } + + + Dieses Programm w"urde also folgendes ausgeben: + 7 + 9 + 11 + + + +Der Grund, warum beim Initialisieren der Liste der Offset mitangegeben +werden mu"s, ist der da"s ein und das selbe Datenelement gleichzeitig +in verschiedenen Listen eingeh"angt werden kann (f"ur jede Liste mu"s +also eine Komponente vom Typ 'listnode' im Element enthalten sein). + +*/ + diff --git a/src/toolbox/tree.c b/src/toolbox/tree.c new file mode 100644 index 000000000..ae74ffc19 --- /dev/null +++ b/src/toolbox/tree.c @@ -0,0 +1,166 @@ +/************************** toolbox/tree.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see tree.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include + +#include "memory.h" +#include "tree.h" + + +tree *tree_new (treeelementcomperator comperator) +{ + tree *t = NEW (tree); + + t -> usedump = 0; + t -> comperator = comperator; + t -> top = NULL; + t -> active = NULL; + + return t; +} + +tree *tree_dnew (treeelementcomperator comperator) +{ + tree *t = DNEW (tree); + + t -> usedump = 1; + t -> comperator = comperator; + t -> top = NULL; + t -> active = NULL; + + return t; +} + + +static void tree_nodefree (treenode *tn) +{ + if (!tn) return; + tree_nodefree (tn -> left); + tree_nodefree (tn -> right); + FREE (tn, treenode); +} + +void tree_free (tree *t) +{ + assert (! t -> usedump); + + tree_nodefree ( t -> top ); + FREE (t, tree); +} + + +static treenode *tree_nodeadd + (tree *t, treenode *par, treenode *n, void *element, void *key) +{ + if (!n) { + if ( t-> usedump ) n = DNEW (treenode); + else n = NEW (treenode); + + n -> left = NULL; + n -> right = NULL; + n -> parent = par; + n -> element = element; + } + else { + if ( t->comperator (key, n -> element) < 0 ) { + n -> left = tree_nodeadd (t, n, n -> left, element, key); + } + else { + n -> right = tree_nodeadd (t, n, n -> right, element, key); + } + } + + return n; +} + +void tree_add (tree *t, void *element, void *key) +{ + t -> top = tree_nodeadd (t, NULL, t -> top, element, key); + t -> active = t -> top; +} + + +static treenode *tree_nodefind (tree *t, treenode *n, void *key) +{ + int way; + + if (!n) return NULL; + + way = t -> comperator (key, n->element); + if (way==0) return n; + if (way<0) return tree_nodefind (t, n -> left, key); + else return tree_nodefind (t, n -> right, key); +} + + +void *tree_find (tree *t, void *key) +{ + treenode *tn = tree_nodefind (t, t -> top, key); + if (!tn) return NULL; + + t -> active = tn; + return tn -> element; +} + + + +void *tree_this (tree *t) +{ + if (! t->active) return NULL; + return t->active->element; +} + + +static treenode *leftmostnode(treenode *t) +{ + while (t->left) t=t->left; + return t; +} + +void *tree_first (tree *t) +{ + treenode *a = t->top; + if (!a) return NULL; + + a = leftmostnode (a); + t->active = a; + return a->element; +} + +void *tree_next (tree *t) +{ + treenode *a = t->active; + treenode *comefrom = NULL; + + while (a) { + if (!a) return NULL; + + if (a->left && (a->left == comefrom)) { + t -> active = a; + return a->element; + } + + if (a->right && (a->right != comefrom) ) { + a = leftmostnode(a->right); + t -> active = a; + return a->element; + } + + comefrom=a; + a=a->parent; + } + t->active = NULL; + return NULL; +} diff --git a/src/toolbox/tree.h b/src/toolbox/tree.h new file mode 100644 index 000000000..fa974bbe0 --- /dev/null +++ b/src/toolbox/tree.h @@ -0,0 +1,45 @@ +/************************* toolbox/tree.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Verwaltung bin"arer B"aume + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef int (*treeelementcomperator) (void *key, void * element); + + +typedef struct treenode { + struct treenode *left,*right; + struct treenode *parent; + + void *element; + } treenode; + +typedef struct { + int usedump; + treeelementcomperator comperator; + + treenode *top; + treenode *active; + } tree; + + + +tree *tree_new (treeelementcomperator comperator); +tree *tree_dnew (treeelementcomperator comperator); +void tree_free (tree *t); + +void tree_add (tree *t, void *element, void *key); +void *tree_find (tree *t, void *key); + +void *tree_this (tree *t); +void *tree_first (tree *t); +void *tree_next (tree *t); + diff --git a/src/vm/builtin.c b/src/vm/builtin.c new file mode 100644 index 000000000..c1de52db7 --- /dev/null +++ b/src/vm/builtin.c @@ -0,0 +1,1621 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** builtin.c ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enthaelt die C-Funktionen fuer alle JavaVM-Befehle, die sich nicht direkt + auf Maschinencode "ubersetzen lassen. Im Code f"ur die Methoden steht + dann ein Funktionsaufruf (nat"urlich mit den Aufrufskonventionen von C). + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/12/03 + +*******************************************************************************/ + +#include +#include + +#include "global.h" +#include "builtin.h" + +#include "loader.h" +#include "tables.h" + +#include "threads/thread.h" +#include "threads/locks.h" /* schani */ + +#include "sysdep/native-math.h" + +builtin_descriptor builtin_desc[] = { + {(functionptr) builtin_instanceof, "instanceof"}, + {(functionptr) builtin_checkcast, "checkcast"}, + {(functionptr) new_builtin_checkcast, "checkcast"}, + {(functionptr) builtin_arrayinstanceof, "arrayinstanceof"}, + {(functionptr) builtin_checkarraycast, "checkarraycast"}, + {(functionptr) new_builtin_checkarraycast, "checkarraycast"}, + {(functionptr) new_builtin_aastore, "aastore"}, + {(functionptr) builtin_new, "new"}, + {(functionptr) builtin_anewarray, "anewarray"}, + {(functionptr) builtin_newarray_array, "newarray_array"}, + {(functionptr) builtin_newarray_boolean, "newarray_boolean"}, + {(functionptr) builtin_newarray_char, "newarray_char"}, + {(functionptr) builtin_newarray_float, "newarray_float"}, + {(functionptr) builtin_newarray_double, "newarray_double"}, + {(functionptr) builtin_newarray_byte, "newarray_byte"}, + {(functionptr) builtin_newarray_short, "newarray_short"}, + {(functionptr) builtin_newarray_int, "newarray_int"}, + {(functionptr) builtin_newarray_long, "newarray_long"}, + {(functionptr) builtin_displaymethodstart, "displaymethodstart"}, + {(functionptr) builtin_displaymethodstop, "displaymethodstop"}, + {(functionptr) builtin_monitorenter, "monitorenter"}, + {(functionptr) new_builtin_monitorenter, "monitorenter"}, + {(functionptr) builtin_monitorexit, "monitorexit"}, + {(functionptr) new_builtin_monitorexit, "monitorexit"}, + {(functionptr) builtin_idiv, "idiv"}, + {(functionptr) new_builtin_idiv, "idiv"}, + {(functionptr) builtin_irem, "irem"}, + {(functionptr) new_builtin_irem, "irem"}, + {(functionptr) builtin_ladd, "ladd"}, + {(functionptr) builtin_lsub, "lsub"}, + {(functionptr) builtin_lmul, "lmul"}, + {(functionptr) builtin_ldiv, "ldiv"}, + {(functionptr) new_builtin_ldiv, "ldiv"}, + {(functionptr) builtin_lrem, "lrem"}, + {(functionptr) new_builtin_lrem, "lrem"}, + {(functionptr) builtin_lshl, "lshl"}, + {(functionptr) builtin_lshr, "lshr"}, + {(functionptr) builtin_lushr, "lushr"}, + {(functionptr) builtin_land, "land"}, + {(functionptr) builtin_lor, "lor"}, + {(functionptr) builtin_lxor, "lxor"}, + {(functionptr) builtin_lneg, "lneg"}, + {(functionptr) builtin_lcmp, "lcmp"}, + {(functionptr) builtin_fadd, "fadd"}, + {(functionptr) builtin_fsub, "fsub"}, + {(functionptr) builtin_fmul, "fmul"}, + {(functionptr) builtin_fdiv, "fdiv"}, + {(functionptr) builtin_frem, "frem"}, + {(functionptr) builtin_fneg, "fneg"}, + {(functionptr) builtin_fcmpl, "fcmpl"}, + {(functionptr) builtin_fcmpg, "fcmpg"}, + {(functionptr) builtin_dadd, "dadd"}, + {(functionptr) builtin_dsub, "dsub"}, + {(functionptr) builtin_dmul, "dmul"}, + {(functionptr) builtin_ddiv, "ddiv"}, + {(functionptr) builtin_drem, "drem"}, + {(functionptr) builtin_dneg, "dneg"}, + {(functionptr) builtin_dcmpl, "dcmpl"}, + {(functionptr) builtin_dcmpg, "dcmpg"}, + {(functionptr) builtin_i2l, "i2l"}, + {(functionptr) builtin_i2f, "i2f"}, + {(functionptr) builtin_i2d, "i2d"}, + {(functionptr) builtin_l2i, "l2i"}, + {(functionptr) builtin_l2f, "l2f"}, + {(functionptr) builtin_l2d, "l2d"}, + {(functionptr) builtin_f2i, "f2i"}, + {(functionptr) builtin_f2l, "f2l"}, + {(functionptr) builtin_f2d, "f2d"}, + {(functionptr) builtin_d2i, "d2i"}, + {(functionptr) builtin_d2l, "d2l"}, + {(functionptr) builtin_d2f, "d2f"}, + {(functionptr) NULL, "unknown"} + }; + + +/***************************************************************************** + TYPCHECKS +*****************************************************************************/ + + + +/*************** interne Funktion: builtin_isanysubclass ********************* + + "uberpr"uft, ob eine Klasse eine Unterklasse einer anderen Klasse ist. + Dabei gelten auch Interfaces, die eine Klasse implementiert, als + deren Oberklassen. + R"uckgabewert: 1 ... es trifft zu + 0 ... es trifft nicht zu + +*****************************************************************************/ + +static s4 builtin_isanysubclass (classinfo *sub, classinfo *super) +{ + if (super->flags & ACC_INTERFACE) { + u4 index = super->index; +/* if (sub->vftbl == NULL) return 0; */ + if (index >= sub->vftbl->interfacetablelength) return 0; + return ( sub->vftbl->interfacevftbl[index] ) ? 1 : 0; + } + else { + while (sub) { + if (sub==super) return 1; + sub = sub->super; + } + return 0; + } +} + + +/****************** Funktion: builtin_instanceof ***************************** + + "Uberpr"uft, ob ein Objekt eine Instanz einer Klasse (oder einer davon + abgeleiteten Klasse) ist, oder ob die Klasse des Objekts ein Interface + implementiert. + Return: 1, wenn ja + 0, wenn nicht, oder wenn Objekt ein NULL-Zeiger + +*****************************************************************************/ + +s4 builtin_instanceof(java_objectheader *obj, classinfo *class) +{ +#ifdef DEBUG + log_text ("builtin_instanceof called"); +#endif + + if (!obj) return 0; + return builtin_isanysubclass (obj->vftbl->class, class); +} + + + +/**************** Funktion: builtin_checkcast ******************************* + + "Uberpr"uft, ob ein Objekt eine Instanz einer Klasse (oder einer davon + abgeleiteten Klasse ist). + Unterschied zu builtin_instanceof: Ein NULL-Zeiger ist immer richtig + Return: 1, wenn ja, oder wenn Objekt ein NULL-Zeiger + 0, wenn nicht + +****************************************************************************/ + +s4 builtin_checkcast(java_objectheader *obj, classinfo *class) +{ +#ifdef DEBUG + log_text ("builtin_checkcast called"); +#endif + + if (!obj) return 1; + if ( builtin_isanysubclass (obj->vftbl->class, class) ) { + return 1; + } +#if DEBUG + printf ("#### checkcast failed "); + unicode_display (obj->vftbl->class->name); + printf (" -> "); + unicode_display (class->name); + printf ("\n"); +#endif + + return 0; +} + + + +/*********** interne Funktion: builtin_descriptorscompatible ****************** + + "uberpr"uft, ob zwei Array-Typdescriptoren compartible sind, d.h., + ob ein Array vom Typ 'desc' gefahrlos einer Variblen vom Typ 'target' + zugewiesen werden kann. + Return: 1, wenn ja + 0, wenn nicht + +******************************************************************************/ + +static s4 builtin_descriptorscompatible + (constant_arraydescriptor *desc, constant_arraydescriptor *target) +{ + if (desc==target) return 1; + if (desc->arraytype != target->arraytype) return 0; + switch (target->arraytype) { + case ARRAYTYPE_OBJECT: + return builtin_isanysubclass (desc->objectclass, target->objectclass); + case ARRAYTYPE_ARRAY: + return builtin_descriptorscompatible + (desc->elementdescriptor, target->elementdescriptor); + default: return 1; + } +} + + + +/******************** Funktion: builtin_checkarraycast *********************** + + "uberpr"uft, ob ein gegebenes Objekt tats"achlich von einem + Untertyp des geforderten Arraytyps ist. + Dazu muss das Objekt auf jeden Fall ein Array sein. + Bei einfachen Arrays (int,short,double,etc.) muss der Typ genau + "ubereinstimmen. + Bei Arrays von Objekten muss der Elementtyp des tats"achlichen Arrays + ein Untertyp (oder der selbe Typ) vom geforderten Elementtyp sein. + Bei Arrays vom Arrays (die eventuell wieder Arrays von Arrays + sein k"onnen) m"ussen die untersten Elementtypen in der entsprechenden + Unterklassenrelation stehen. + + Return: 1, wenn Cast in Ordung ist + 0, wenn es nicht geht + + Achtung: ein Cast mit einem NULL-Zeiger geht immer gut. + +*****************************************************************************/ + +s4 builtin_checkarraycast(java_objectheader *o, constant_arraydescriptor *desc) +{ + java_arrayheader *a = (java_arrayheader*) o; + + if (!o) return 1; + if (o->vftbl->class != class_array) { + return 0; + } + + if (a->arraytype != desc->arraytype) { + return 0; + } + + switch (a->arraytype) { + case ARRAYTYPE_OBJECT: { + java_objectarray *oa = (java_objectarray*) o; + return builtin_isanysubclass (oa->elementtype, desc->objectclass); + } + case ARRAYTYPE_ARRAY: { + java_arrayarray *aa = (java_arrayarray*) o; + return builtin_descriptorscompatible + (aa->elementdescriptor, desc->elementdescriptor); + } + default: + return 1; + } +} + + +s4 builtin_arrayinstanceof + (java_objectheader *obj, constant_arraydescriptor *desc) +{ + if (!obj) return 1; + return builtin_checkarraycast (obj, desc); +} + + +/************************** exception functions ******************************* + +******************************************************************************/ + +java_objectheader *builtin_throw_exception (java_objectheader *exceptionptr) { + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + fflush (stdout); + return exceptionptr; +} + + +/******************* Funktion: builtin_canstore ******************************* + + "uberpr"uft, ob ein Objekt in einem Array gespeichert werden + darf. + Return: 1, wenn es geht + 0, wenn nicht + +******************************************************************************/ + + +s4 builtin_canstore (java_objectarray *a, java_objectheader *o) +{ + if (!o) return 1; + + switch (a->header.arraytype) { + case ARRAYTYPE_OBJECT: + if ( ! builtin_checkcast (o, a->elementtype) ) { + return 0; + } + return 1; + break; + + case ARRAYTYPE_ARRAY: + if ( ! builtin_checkarraycast + (o, ((java_arrayarray*)a)->elementdescriptor) ) { + return 0; + } + return 1; + break; + + default: + panic ("builtin_canstore called with invalid arraytype"); + return 0; + } +} + + + +/***************************************************************************** + ARRAYOPERATIONEN +*****************************************************************************/ + + + +/******************** Funktion: builtin_new ********************************** + + Legt ein neues Objekt einer Klasse am Heap an. + Return: Der Zeiger auf das Objekt, oder NULL, wenn kein Speicher + mehr frei ist. + +*****************************************************************************/ + +java_objectheader *builtin_new (classinfo *c) +{ + java_objectheader *o; + + o = heap_allocate ( c->instancesize, true, c->finalizer ); + if (!o) return NULL; + + memset (o, 0, c->instancesize); + + o -> vftbl = c -> vftbl; + return o; +} + + + +/******************** Funktion: builtin_anewarray **************************** + + Legt ein Array von Zeigern auf Objekte am Heap an. + Parameter: + size ......... Anzahl der Elemente + elementtype .. ein Zeiger auf die classinfo-Struktur des Typs + der Elemente + + Return: Zeiger auf das Array, oder NULL (wenn kein Speicher frei) + +*****************************************************************************/ + +java_objectarray *builtin_anewarray (s4 size, classinfo *elementtype) +{ + s4 i; + java_objectarray *a; + + a = heap_allocate ( sizeof(java_objectarray) + (size-1) * sizeof(void*), + true, 0 /* FALSE */ ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_OBJECT; + a -> elementtype = elementtype; + for (i=0; idata[i] = NULL; + return a; +} + + + +/******************** Funktion: builtin_newarray_array *********************** + + Legt ein Array von Zeigern auf Arrays am Heap an. + Paramter: size ......... Anzahl der Elemente + elementdesc .. Zeiger auf die Arraybeschreibungs-Struktur f"ur + die Element-Arrays. + + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_arrayarray *builtin_newarray_array + (s4 size, constant_arraydescriptor *elementdesc) +{ + s4 i; + java_arrayarray *a; + + a = heap_allocate ( sizeof(java_arrayarray) + (size-1) * sizeof(void*), + true, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_ARRAY; + a -> elementdescriptor = elementdesc; + for (i=0; idata[i] = NULL; + return a; +} + + +/******************** Funktion: builtin_newarray_boolean ************************ + + Legt ein Array von Bytes am Heap an, das allerdings als Boolean-Array + gekennzeichnet wird (wichtig bei Casts!) + + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_booleanarray *builtin_newarray_boolean (s4 size) +{ + java_booleanarray *a; + + a = heap_allocate ( sizeof(java_booleanarray) + (size-1) * sizeof(u1), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_BOOLEAN; + memset (a->data, 0, sizeof(u1) * size); + + return a; +} + +/******************** Funktion: builtin_newarray_char ************************ + + Legt ein Array von 16-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_chararray *builtin_newarray_char (s4 size) +{ + java_chararray *a; + + a = heap_allocate ( sizeof(java_chararray) + (size-1) * sizeof(u2), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_CHAR; + memset (a->data, 0, sizeof(u2) * size); + + return a; +} + + +/******************** Funktion: builtin_newarray_float *********************** + + Legt ein Array von 32-bit-IEEE-float am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_floatarray *builtin_newarray_float (s4 size) +{ + s4 i; + java_floatarray *a; + + a = heap_allocate ( sizeof(java_floatarray) + (size-1) * sizeof(float), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_FLOAT; + for (i=0; idata[i] = 0.0; + return a; +} + + +/******************** Funktion: builtin_newarray_double *********************** + + Legt ein Array von 64-bit-IEEE-float am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_doublearray *builtin_newarray_double (s4 size) +{ + s4 i; + java_doublearray *a; + + a = heap_allocate ( sizeof(java_doublearray) + (size-1) * sizeof(double), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_DOUBLE; + for (i=0; idata[i] = 0.0; + return a; +} + + + + +/******************** Funktion: builtin_newarray_byte *********************** + + Legt ein Array von 8-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_bytearray *builtin_newarray_byte (s4 size) +{ + java_bytearray *a; + + a = heap_allocate ( sizeof(java_bytearray) + (size-1) * sizeof(s1), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array->vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_BYTE; + memset (a->data, 0, sizeof(u1) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_short *********************** + + Legt ein Array von 16-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_shortarray *builtin_newarray_short (s4 size) +{ + java_shortarray *a; + + a = heap_allocate ( sizeof(java_shortarray) + (size-1) * sizeof(s2), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_SHORT; + memset (a->data, 0, sizeof(s2) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_int *********************** + + Legt ein Array von 32-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_intarray *builtin_newarray_int (s4 size) +{ + java_intarray *a; + + a = heap_allocate ( sizeof(java_intarray) + (size-1) * sizeof(s4), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_INT; + memset (a->data, 0, sizeof(s4) * size); + return a; +} + + +/******************** Funktion: builtin_newarray_long *********************** + + Legt ein Array von 64-bit-Integers am Heap an. + Return: Zeiger auf das Array, oder NULL + +*****************************************************************************/ + +java_longarray *builtin_newarray_long (s4 size) +{ + java_longarray *a; + + a = heap_allocate ( sizeof(java_longarray) + (size-1) * sizeof(s8), + false, NULL ); + if (!a) return NULL; + + a -> header.objheader.vftbl = class_array -> vftbl; + a -> header.size = size; + a -> header.arraytype = ARRAYTYPE_LONG; + memset (a->data, 0, sizeof(s8) * size); + return a; +} + + + +/***************** Funktion: builtin_multianewarray *************************** + + Legt ein mehrdimensionales Array am Heap an. + Die Gr"ossen der einzelnen Dimensionen werden in einem Integerarray + "ubergeben. Der Typ es zu erzeugenden Arrays wird als + Referenz auf eine constant_arraydescriptor - Struktur "ubergeben. + + Return: Ein Zeiger auf das Array, oder NULL, wenn kein Speicher mehr + vorhanden ist. + +******************************************************************************/ + + /* Hilfsfunktion */ + +static java_arrayheader *multianewarray_part (java_intarray *dims, int thisdim, + constant_arraydescriptor *desc) +{ + u4 size,i; + java_arrayarray *a; + + size = dims -> data[thisdim]; + + if (thisdim == (dims->header.size-1)) { + /* letzte Dimension schon erreicht */ + + switch (desc -> arraytype) { + case ARRAYTYPE_BOOLEAN: + return (java_arrayheader*) builtin_newarray_boolean (size); + case ARRAYTYPE_CHAR: + return (java_arrayheader*) builtin_newarray_char (size); + case ARRAYTYPE_FLOAT: + return (java_arrayheader*) builtin_newarray_float (size); + case ARRAYTYPE_DOUBLE: + return (java_arrayheader*) builtin_newarray_double (size); + case ARRAYTYPE_BYTE: + return (java_arrayheader*) builtin_newarray_byte (size); + case ARRAYTYPE_SHORT: + return (java_arrayheader*) builtin_newarray_short (size); + case ARRAYTYPE_INT: + return (java_arrayheader*) builtin_newarray_int (size); + case ARRAYTYPE_LONG: + return (java_arrayheader*) builtin_newarray_long (size); + case ARRAYTYPE_OBJECT: + return (java_arrayheader*) builtin_anewarray (size, desc->objectclass); + + case ARRAYTYPE_ARRAY: + return (java_arrayheader*) builtin_newarray_array (size, desc->elementdescriptor); + + default: panic ("Invalid arraytype in multianewarray"); + } + } + + /* wenn letzte Dimension noch nicht erreicht wurde */ + + if (desc->arraytype != ARRAYTYPE_ARRAY) + panic ("multianewarray with too many dimensions"); + + a = builtin_newarray_array (size, desc->elementdescriptor); + if (!a) return NULL; + + for (i=0; ielementdescriptor); + if (!ea) return NULL; + + a -> data[i] = ea; + } + + return (java_arrayheader*) a; +} + + +java_arrayheader *builtin_multianewarray (java_intarray *dims, + constant_arraydescriptor *desc) +{ + return multianewarray_part (dims, 0, desc); +} + + +static java_arrayheader *nmultianewarray_part (int n, long *dims, int thisdim, + constant_arraydescriptor *desc) +{ + int size, i; + java_arrayarray *a; + + size = (int) dims[thisdim]; + + if (thisdim == (n - 1)) { + /* letzte Dimension schon erreicht */ + + switch (desc -> arraytype) { + case ARRAYTYPE_BOOLEAN: + return (java_arrayheader*) builtin_newarray_boolean(size); + case ARRAYTYPE_CHAR: + return (java_arrayheader*) builtin_newarray_char(size); + case ARRAYTYPE_FLOAT: + return (java_arrayheader*) builtin_newarray_float(size); + case ARRAYTYPE_DOUBLE: + return (java_arrayheader*) builtin_newarray_double(size); + case ARRAYTYPE_BYTE: + return (java_arrayheader*) builtin_newarray_byte(size); + case ARRAYTYPE_SHORT: + return (java_arrayheader*) builtin_newarray_short(size); + case ARRAYTYPE_INT: + return (java_arrayheader*) builtin_newarray_int(size); + case ARRAYTYPE_LONG: + return (java_arrayheader*) builtin_newarray_long(size); + case ARRAYTYPE_OBJECT: + return (java_arrayheader*) builtin_anewarray(size, + desc->objectclass); + case ARRAYTYPE_ARRAY: + return (java_arrayheader*) builtin_newarray_array(size, + desc->elementdescriptor); + + default: panic ("Invalid arraytype in multianewarray"); + } + } + + /* wenn letzte Dimension noch nicht erreicht wurde */ + + if (desc->arraytype != ARRAYTYPE_ARRAY) + panic ("multianewarray with too many dimensions"); + + a = builtin_newarray_array(size, desc->elementdescriptor); + if (!a) return NULL; + + for (i = 0; i < size; i++) { + java_arrayheader *ea = + nmultianewarray_part(n, dims, thisdim + 1, desc->elementdescriptor); + if (!ea) return NULL; + + a -> data[i] = ea; + } + + return (java_arrayheader*) a; +} + + +java_arrayheader *builtin_nmultianewarray (int size, + constant_arraydescriptor *desc, long *dims) +{ + (void) builtin_newarray_int(size); /* for compatibility with -old */ + return nmultianewarray_part (size, dims, 0, desc); +} + + + + +/************************* Funktion: builtin_aastore ************************* + + speichert eine Referenz auf ein Objekt in einem Object-Array oder + in einem Array-Array. + Dabei wird allerdings vorher "uberpr"uft, ob diese Operation + zul"assig ist. + + Return: 1, wenn alles OK ist + 0, wenn dieses Objekt nicht in dieses Array gespeichert werden + darf + +*****************************************************************************/ + +s4 builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o) +{ + if (builtin_canstore(a,o)) { + a->data[index] = o; + return 1; + } + return 0; +} + + + + + + +/***************************************************************************** + METHODEN-PROTOKOLLIERUNG + + Verschiedene Funktionen, mit denen eine Meldung ausgegeben werden + kann, wann immer Methoden aufgerufen oder beendet werden. + (f"ur Debug-Zwecke) + +*****************************************************************************/ + + +u4 methodindent=0; + +java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr, + methodinfo *method, int *pos, int noindent) { + + if (!noindent) + methodindent--; + if (verbose || runverbose) { + printf("Exception "); + unicode_display (exceptionptr->vftbl->class->name); + printf(" thrown in "); + if (method) { + unicode_display (method->class->name); + printf("."); + unicode_display (method->name); + if (method->flags & ACC_SYNCHRONIZED) + printf("(SYNC)"); + else + printf("(NOSYNC)"); + printf("(%p) at position %p\n", method->entrypoint, pos); + } + else + printf("call_java_method\n"); + fflush (stdout); + } + return exceptionptr; +} + + +void builtin_trace_args(long a0, long a1, long a2, long a3, long a4, long a5, + methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "called: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + sprintf (logtext+strlen(logtext), "("); + switch (method->paramcount) { + case 6: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx, %lx, %lx", + a0, a1, a2, a3, a4, a5); + break; + case 5: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx, %lx", + a0, a1, a2, a3, a4); + break; + case 4: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx, %lx", + a0, a1, a2, a3); + break; + case 3: + sprintf(logtext+strlen(logtext), "%lx, %lx, %lx", a0, a1, a2); + break; + case 2: + sprintf(logtext+strlen(logtext), "%lx, %lx", a0, a1); + break; + case 1: + sprintf(logtext+strlen(logtext), "%lx", a0); + break; + } + sprintf (logtext+strlen(logtext), ")"); + + dolog (); + methodindent++; +} + +void builtin_displaymethodstart(methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "called: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + dolog (); + methodindent++; +} + +void builtin_displaymethodstop(methodinfo *method, long l, double d) +{ + methodindent--; + sprintf (logtext, " "); + sprintf (logtext+methodindent, "finished: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + switch (method->returntype) { + case TYPE_INT: + case TYPE_LONG: + sprintf (logtext+strlen(logtext), "->%ld", l); + break; + case TYPE_FLOAT: + case TYPE_DOUBLE: + sprintf (logtext+strlen(logtext), "->%g", d); + break; + case TYPE_ADDRESS: + sprintf (logtext+strlen(logtext), "->%p", (void*) l); + break; + } + dolog (); +} + +void builtin_displaymethodexception(methodinfo *method) +{ + sprintf (logtext, " "); + sprintf (logtext+methodindent, "exception abort: "); + unicode_sprint (logtext+strlen(logtext), method->class->name); + sprintf (logtext+strlen(logtext), "."); + unicode_sprint (logtext+strlen(logtext), method->name); + unicode_sprint (logtext+strlen(logtext), method->descriptor); + dolog (); +} + + +/**************************************************************************** + SYNCHRONIZATION FUNCTIONS +*****************************************************************************/ + +/* + * Lock the mutex of an object. + */ +#ifdef USE_THREADS +void +internal_lock_mutex_for_object (java_objectheader *object) +{ + mutexHashEntry *entry; + int hashValue; + + assert(object != 0); + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object != 0) + { + if (entry->mutex.count == 0 && entry->conditionCount == 0) + { + entry->object = 0; + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + else + { + while (entry->next != 0 && entry->object != object) + entry = entry->next; + + if (entry->object != object) + { + entry->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = firstFreeOverflowEntry->next; + + entry = entry->next; + entry->object = 0; + entry->next = 0; + assert(entry->conditionCount == 0); + } + } + } + else + { + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + + if (entry->object == 0) + entry->object = object; + + internal_lock_mutex(&entry->mutex); +} +#endif + + +/* + * Unlocks the mutex of an object. + */ +#ifdef USE_THREADS +void +internal_unlock_mutex_for_object (java_objectheader *object) +{ + int hashValue; + mutexHashEntry *entry; + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object == object) + internal_unlock_mutex(&entry->mutex); + else + { + while (entry->next != 0 && entry->next->object != object) + entry = entry->next; + + assert(entry->next != 0); + + internal_unlock_mutex(&entry->next->mutex); + + if (entry->next->mutex.count == 0 && entry->conditionCount == 0) + { + mutexHashEntry *unlinked = entry->next; + + entry->next = unlinked->next; + unlinked->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = unlinked; + } + } +} +#endif + +void +builtin_monitorenter (java_objectheader *o) +{ +#ifdef USE_THREADS + int hashValue; + + assert(blockInts == 0); + + ++blockInts; + + hashValue = MUTEX_HASH_VALUE(o); + if (mutexHashTable[hashValue].object == o + && mutexHashTable[hashValue].mutex.holder == currentThread) + ++mutexHashTable[hashValue].mutex.count; + else + internal_lock_mutex_for_object(o); + + --blockInts; + + assert(blockInts == 0); +#endif +} + +void builtin_monitorexit (java_objectheader *o) +{ +#ifdef USE_THREADS + int hashValue; + + assert(blockInts == 0); + + ++blockInts; + + hashValue = MUTEX_HASH_VALUE(o); + if (mutexHashTable[hashValue].object == o) + { + if (mutexHashTable[hashValue].mutex.count == 1 + && mutexHashTable[hashValue].mutex.muxWaiters != 0) + internal_unlock_mutex_for_object(o); + else + --mutexHashTable[hashValue].mutex.count; + } + else + internal_unlock_mutex_for_object(o); + + --blockInts; + + assert(blockInts == 0); +#endif +} + + +/***************************************************************************** + DIVERSE HILFSFUNKTIONEN +*****************************************************************************/ + + + +/*********** Funktionen f"ur die Integerdivision ***************************** + + Auf manchen Systemen (z.B. DEC ALPHA) wird durch die CPU keine Integer- + division unterst"utzt. + Daf"ur gibt es dann diese Hilfsfunktionen + +******************************************************************************/ + +s4 builtin_idiv (s4 a, s4 b) { return a/b; } +s4 builtin_irem (s4 a, s4 b) { return a%b; } + + +/************** Funktionen f"ur Long-Arithmetik ******************************* + + Auf Systemen, auf denen die CPU keine 64-Bit-Integers unterst"utzt, + werden diese Funktionen gebraucht + +******************************************************************************/ + + +s8 builtin_ladd (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a+b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lsub (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a-b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lmul (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a*b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_ldiv (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a/b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lrem (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a%b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lshl (s8 a, s4 b) +{ +#if U8_AVAILABLE + return a<<(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lshr (s8 a, s4 b) +{ +#if U8_AVAILABLE + return a>>(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lushr (s8 a, s4 b) +{ +#if U8_AVAILABLE + return ((u8)a)>>(b&63); +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_land (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a&b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lor (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a|b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lxor (s8 a, s8 b) +{ +#if U8_AVAILABLE + return a^b; +#else + return builtin_i2l(0); +#endif +} + +s8 builtin_lneg (s8 a) +{ +#if U8_AVAILABLE + return -a; +#else + return builtin_i2l(0); +#endif +} + +s4 builtin_lcmp (s8 a, s8 b) +{ +#if U8_AVAILABLE + if (ab) return 1; + return 0; +#else + return 0; +#endif +} + + + + + +/*********** Funktionen f"ur die Floating-Point-Operationen ******************/ + +float builtin_fadd (float a, float b) +{ + if (isnanf(a)) return FLT_NAN; + if (isnanf(b)) return FLT_NAN; + if (finitef(a)) { + if (finitef(b)) return a+b; + else return b; + } + else { + if (finitef(b)) return a; + else { + if (copysignf(1.0, a)==copysignf(1.0, b)) return a; + else return FLT_NAN; + } + } +} + +float builtin_fsub (float a, float b) +{ + return builtin_fadd (a, builtin_fneg(b)); +} + +float builtin_fmul (float a, float b) +{ + if (isnanf(a)) return FLT_NAN; + if (isnanf(b)) return FLT_NAN; + if (finitef(a)) { + if (finitef(b)) return a*b; + else { + if (a==0) return FLT_NAN; + else return copysignf(b, copysignf(1.0, b)*a); + } + } + else { + if (finitef(b)) { + if (b==0) return FLT_NAN; + else return copysignf(a, copysignf(1.0, a)*b); + } + else { + return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b)); + } + } +} + +float builtin_fdiv (float a, float b) +{ + if (finitef(a) && finitef(b)) { + if (b != 0) + return a / b; + else { + if (a > 0) + return FLT_POSINF; + else if (a < 0) + return FLT_NEGINF; + } + } + return FLT_NAN; +} + +float builtin_frem (float a, float b) +{ + +/* return (float) builtin_drem((double) a, (double) b); */ + + float f; + + if (finite((double) a) && finite((double) b)) { + f = a / b; + if (finite((double) f)) + return fmodf(a, b); + return FLT_NAN; + } + if (isnan((double) b)) + return FLT_NAN; + if (finite((double) a)) + return a; + return FLT_NAN; + +/* float f; + + if (finitef(a) && finitef(b)) { + f = a / b; + if (finitef(f)) + return a - floorf(f) * b; + return FLT_NAN; + } + if (isnanf(b)) + return FLT_NAN; + if (finitef(a)) + return a; + return FLT_NAN; */ +} + + +float builtin_fneg (float a) +{ + if (isnanf(a)) return a; + else { + if (finitef(a)) return -a; + else return copysignf(a,-copysignf(1.0, a)); + } +} + +s4 builtin_fcmpl (float a, float b) +{ + if (isnanf(a)) return -1; + if (isnanf(b)) return -1; + if (!finitef(a) || !finitef(b)) { + a = finitef(a) ? 0 : copysignf(1.0, a); + b = finitef(b) ? 0 : copysignf(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + +s4 builtin_fcmpg (float a, float b) +{ + if (isnanf(a)) return 1; + if (isnanf(b)) return 1; + if (!finitef(a) || !finitef(b)) { + a = finitef(a) ? 0 : copysignf(1.0, a); + b = finitef(b) ? 0 : copysignf(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + + + +/*********** Funktionen f"ur doppelt genaue Fliesskommazahlen ***************/ + +double builtin_dadd (double a, double b) +{ + if (isnan(a)) return DBL_NAN; + if (isnan(b)) return DBL_NAN; + if (finite(a)) { + if (finite(b)) return a+b; + else return b; + } + else { + if (finite(b)) return a; + else { + if (copysign(1.0, a)==copysign(1.0, b)) return a; + else return DBL_NAN; + } + } +} + +double builtin_dsub (double a, double b) +{ + return builtin_dadd (a, builtin_dneg(b)); +} + +double builtin_dmul (double a, double b) +{ + if (isnan(a)) return DBL_NAN; + if (isnan(b)) return DBL_NAN; + if (finite(a)) { + if (finite(b)) return a*b; + else { + if (a==0) return DBL_NAN; + else return copysign(b, copysign(1.0, b)*a); + } + } + else { + if (finite(b)) { + if (b==0) return DBL_NAN; + else return copysign(a, copysign(1.0, a)*b); + } + else { + return copysign(a, copysign(1.0, a)*copysign(1.0, b)); + } + } +} + +double builtin_ddiv (double a, double b) +{ + if (finite(a) && finite(b)) { + if (b != 0) + return a / b; + else { + if (a > 0) + return DBL_POSINF; + else if (a < 0) + return DBL_NEGINF; + } + } + return DBL_NAN; +} + +double builtin_drem (double a, double b) +{ + double d; + + if (finite(a) && finite(b)) { + d = a / b; + if (finite(d)) { + if ((d < 1.0) && (d > 0.0)) + return a; + return fmod(a, b); + } + return DBL_NAN; + } + if (isnan(b)) + return DBL_NAN; + if (finite(a)) + return a; + return DBL_NAN; +} + +double builtin_dneg (double a) +{ + if (isnan(a)) return a; + else { + if (finite(a)) return -a; + else return copysign(a,-copysign(1.0, a)); + } +} + +s4 builtin_dcmpl (double a, double b) +{ + if (isnan(a)) return -1; + if (isnan(b)) return -1; + if (!finite(a) || !finite(b)) { + a = finite(a) ? 0 : copysign(1.0, a); + b = finite(b) ? 0 : copysign(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + +s4 builtin_dcmpg (double a, double b) +{ + if (isnan(a)) return 1; + if (isnan(b)) return 1; + if (!finite(a) || !finite(b)) { + a = finite(a) ? 0 : copysign(1.0, a); + b = finite(b) ? 0 : copysign(1.0, b); + } + if (a>b) return 1; + if (a==b) return 0; + return -1; +} + + +/*********************** Umwandlungsoperationen ****************************/ + +s8 builtin_i2l (s4 i) +{ +#if U8_AVAILABLE + return i; +#else + s8 v; v.high = 0; v.low=i; return v; +#endif +} + +float builtin_i2f (s4 a) +{ +float f = (float) a; +return f; +} + +double builtin_i2d (s4 a) +{ +double d = (double) a; +return d; +} + + +s4 builtin_l2i (s8 l) +{ +#if U8_AVAILABLE + return (s4) l; +#else + return l.low; +#endif +} + +float builtin_l2f (s8 a) +{ +#if U8_AVAILABLE + float f = (float) a; + return f; +#else + return 0.0; +#endif +} + +double builtin_l2d (s8 a) +{ +#if U8_AVAILABLE + double d = (double) a; + return d; +#else + return 0.0; +#endif +} + + +s4 builtin_f2i(float a) +{ + +return builtin_d2i((double) a); + +/* float f; + + if (isnanf(a)) + return 0; + if (finitef(a)) { + if (a > 2147483647) + return 2147483647; + if (a < (-2147483648)) + return (-2147483648); + return (s4) a; + } + f = copysignf((float) 1.0, a); + if (f > 0) + return 2147483647; + return (-2147483648); */ +} + + +s8 builtin_f2l (float a) +{ + +return builtin_d2l((double) a); + +/* float f; + + if (finitef(a)) { + if (a > 9223372036854775807L) + return 9223372036854775807L; + if (a < (-9223372036854775808L)) + return (-9223372036854775808L); + return (s8) a; + } + if (isnanf(a)) + return 0; + f = copysignf((float) 1.0, a); + if (f > 0) + return 9223372036854775807L; + return (-9223372036854775808L); */ +} + + +double builtin_f2d (float a) +{ + if (finitef(a)) return (double) a; + else { + if (isnanf(a)) return DBL_NAN; + else return copysign(DBL_POSINF, (double) copysignf(1.0, a) ); + } +} + + +s4 builtin_d2i (double a) +{ + double d; + + if (finite(a)) { + if (a >= 2147483647) + return 2147483647; + if (a <= (-2147483648)) + return (-2147483648); + return (s4) a; + } + if (isnan(a)) + return 0; + d = copysign(1.0, a); + if (d > 0) + return 2147483647; + return (-2147483648); +} + + +s8 builtin_d2l (double a) +{ + double d; + + if (finite(a)) { + if (a >= 9223372036854775807L) + return 9223372036854775807L; + if (a <= (-9223372036854775807L-1)) + return (-9223372036854775807L-1); + return (s8) a; + } + if (isnan(a)) + return 0; + d = copysign(1.0, a); + if (d > 0) + return 9223372036854775807L; + return (-9223372036854775807L-1); +} + + +float builtin_d2f (double a) +{ + if (finite(a)) return (float) a; + else { + if (isnan(a)) return FLT_NAN; + else return copysignf (FLT_POSINF, (float) copysign(1.0, a)); + } +} + diff --git a/src/vm/builtin.h b/src/vm/builtin.h new file mode 100644 index 000000000..b52afb437 --- /dev/null +++ b/src/vm/builtin.h @@ -0,0 +1,125 @@ +/****************************** builtin.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the prototypes for the functions of file builtin.c which has + a more detailed description. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/14 + +*******************************************************************************/ + + +/***************************** Prototypes *************************************/ + +typedef struct builtin_descriptor { + functionptr bptr; + char *name; + } builtin_descriptor; + +extern builtin_descriptor builtin_desc[]; + +s4 builtin_instanceof(java_objectheader *obj, classinfo *class); +s4 builtin_checkcast(java_objectheader *obj, classinfo *class); +s4 new_builtin_checkcast(java_objectheader *obj, classinfo *class); +s4 builtin_arrayinstanceof + (java_objectheader *obj, constant_arraydescriptor *desc); +s4 builtin_checkarraycast + (java_objectheader *obj, constant_arraydescriptor *desc); +s4 new_builtin_checkarraycast + (java_objectheader *obj, constant_arraydescriptor *desc); + +java_objectheader *builtin_throw_exception (java_objectheader *exception); +java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr, + methodinfo *method, int *pos, int noindent); + +java_objectheader *builtin_new (classinfo *c); + + +java_objectarray *builtin_anewarray (s4 size, classinfo *elementtype); +java_arrayarray *builtin_newarray_array + (s4 size, constant_arraydescriptor *elementdesc); +java_booleanarray *builtin_newarray_boolean (s4 size); +java_chararray *builtin_newarray_char (s4 size); +java_floatarray *builtin_newarray_float (s4 size); +java_doublearray *builtin_newarray_double (s4 size); +java_bytearray *builtin_newarray_byte (s4 size); +java_shortarray *builtin_newarray_short (s4 size); +java_intarray *builtin_newarray_int (s4 size); +java_longarray *builtin_newarray_long (s4 size); +java_arrayheader *builtin_multianewarray (java_intarray *dims, + constant_arraydescriptor *desc); +java_arrayheader *builtin_nmultianewarray (int size, + constant_arraydescriptor *desc, long *dims); + +s4 builtin_canstore (java_objectarray *a, java_objectheader *o); +s4 builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o); +void new_builtin_aastore (java_objectarray *a, s4 index, java_objectheader *o); + +void builtin_trace_args(long a0, long a1, long a2, long a3, long a4, long a5, methodinfo *method); +void builtin_displaymethodstart(methodinfo *method); +void builtin_displaymethodstop(methodinfo *method, long l, double d); +/* void builtin_displaymethodstop(methodinfo *method); */ +void builtin_displaymethodexception(methodinfo *method); + +void builtin_monitorenter (java_objectheader *o); +void new_builtin_monitorenter (java_objectheader *o); +void builtin_monitorexit (java_objectheader *o); +void new_builtin_monitorexit (java_objectheader *o); + +s4 builtin_idiv (s4 a, s4 b); +s4 new_builtin_idiv (s4 a, s4 b); +s4 builtin_irem (s4 a, s4 b); +s4 new_builtin_irem (s4 a, s4 b); + +s8 builtin_ladd (s8 a, s8 b); +s8 builtin_lsub (s8 a, s8 b); +s8 builtin_lmul (s8 a, s8 b); +s8 builtin_ldiv (s8 a, s8 b); +s8 new_builtin_ldiv (s8 a, s8 b); +s8 builtin_lrem (s8 a, s8 b); +s8 new_builtin_lrem (s8 a, s8 b); +s8 builtin_lshl (s8 a, s4 b); +s8 builtin_lshr (s8 a, s4 b); +s8 builtin_lushr (s8 a, s4 b); +s8 builtin_land (s8 a, s8 b); +s8 builtin_lor (s8 a, s8 b); +s8 builtin_lxor (s8 a, s8 b); +s8 builtin_lneg (s8 a); +s4 builtin_lcmp (s8 a, s8 b); + +float builtin_fadd (float a, float b); +float builtin_fsub (float a, float b); +float builtin_fmul (float a, float b); +float builtin_fdiv (float a, float b); +float builtin_frem (float a, float b); +float builtin_fneg (float a); +s4 builtin_fcmpl (float a, float b); +s4 builtin_fcmpg (float a, float b); + +double builtin_dadd (double a, double b); +double builtin_dsub (double a, double b); +double builtin_dmul (double a, double b); +double builtin_ddiv (double a, double b); +double builtin_drem (double a, double b); +double builtin_dneg (double a); +s4 builtin_dcmpl (double a, double b); +s4 builtin_dcmpg (double a, double b); + +s8 builtin_i2l (s4 i); +float builtin_i2f (s4 i); +double builtin_i2d (s4 i); +s4 builtin_l2i (s8 l); +float builtin_l2f (s8 l); +double builtin_l2d (s8 l); +s4 builtin_f2i (float a); +s8 builtin_f2l (float a); +double builtin_f2d (float a); +s4 builtin_d2i (double a); +s8 builtin_d2l (double a); +float builtin_d2f (double a); + diff --git a/src/vm/global.h b/src/vm/global.h new file mode 100644 index 000000000..e92f7f116 --- /dev/null +++ b/src/vm/global.h @@ -0,0 +1,542 @@ +/****************************** global.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains global definitions which are used in the whole program, includes + some files and contains global used macros. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Chages: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/28 + +*******************************************************************************/ + +#ifndef __global_h_ +#define __global_h_ /* schani */ + +#define STATISTICS /* andi */ + +/***************************** standard includes ******************************/ + +#include +#include +#include +#include + +#include "toolbox/memory.h" +#include "toolbox/chain.h" +#include "toolbox/list.h" +#include "toolbox/loging.h" + + +/**************************** system dependent types **************************/ + +#include "sysdep/types.h" + + +/**************************** additional data types ***************************/ + +typedef void *voidptr; /* generic pointer */ + + +typedef u1 bool; /* boolean data type */ + +#define true 1 +#define false 0 + +typedef void (*functionptr) (); /* generic function pointer */ + + +#define MAX_ALIGN 8 /* most generic alignment for JavaVM values */ + + +/**************************** shutdown function *******************************/ + +void cacao_shutdown(s4 status); + + +/**************************** basic data types ********************************/ + +#define TYPE_INT 0 /* the JavaVM types must numbered in the */ +#define TYPE_LONG 1 /* same order as the ICMD_Ixxx to ICMD_Axxx */ +#define TYPE_FLOAT 2 /* instructions (LOAD and STORE) */ +#define TYPE_DOUBLE 3 /* integer, long, float, double, address */ +#define TYPE_ADDRESS 4 /* all other types can be numbered arbitrarily*/ + +#define TYPE_VOID 10 + + +/**************************** Java class file constants ***********************/ + +#define MAGIC 0xcafebabe +#define MINOR_VERSION 3 +#define MAJOR_VERSION 45 + +#define CONSTANT_Class 7 +#define CONSTANT_Fieldref 9 +#define CONSTANT_Methodref 10 +#define CONSTANT_InterfaceMethodref 11 +#define CONSTANT_String 8 +#define CONSTANT_Integer 3 +#define CONSTANT_Float 4 +#define CONSTANT_Long 5 +#define CONSTANT_Double 6 +#define CONSTANT_NameAndType 12 +#define CONSTANT_Utf8 1 + +#define CONSTANT_Arraydescriptor 13 +#define CONSTANT_UNUSED 0 + + +#define ACC_PUBLIC 0x0001 +#define ACC_PRIVATE 0x0002 +#define ACC_PROTECTED 0x0004 +#define ACC_STATIC 0x0008 +#define ACC_FINAL 0x0010 +#define ACC_SYNCHRONIZED 0x0020 +#define ACC_VOLATILE 0x0040 +#define ACC_TRANSIENT 0x0080 +#define ACC_NATIVE 0x0100 +#define ACC_INTERFACE 0x0200 +#define ACC_ABSTRACT 0x0400 + + + +/**************************** resolve typedef-cycles **************************/ + +typedef struct unicode unicode; +typedef struct classinfo classinfo; +typedef struct vftbl vftbl; +typedef u1* methodptr; + + +/********************** data structures of UNICODE symbol *********************/ + +struct unicode { + unicode *hashlink; /* externe Verkettung f"ur die unicode-Hashtabelle */ + u4 key; /* Hash-Schl"ussel (h"angt nur vom Text ab) */ + int length; /* L"ange des Textes */ + u2 *text; /* Zeiger auf den Text (jeder Buchstabe 16 Bit) */ + classinfo *class; /* gegebenenfalls Referenz auf die Klasse dieses + Namens (oder NULL, wenn es keine solche gibt) */ + struct java_objectheader *string; + /* gegebenenfalls Referenz auf einen konstanten + String mit dem entsprechenden Wert */ + }; + + /* Alle Unicode-Symbole werden in einer einzigen globalen Tabelle + (Hashtabelle) verwaltet, jedes Symbol wird nur einmal angelegt. + -> Speicherersparnis, und "Uberpr"ufung auf Gleichheit durch einfachen + Zeigervergleich */ + + +/************ data structures of remaining constant pool entries **************/ + + +typedef struct { + classinfo *class; + unicode *name; + unicode *descriptor; + } constant_FMIref; + + +typedef struct { + s4 value; + } constant_integer; + +typedef struct { + float value; + } constant_float; + +typedef struct { + s8 value; + } constant_long; + +typedef struct { + double value; + } constant_double; + + +typedef struct { + unicode *name; + unicode *descriptor; + } constant_nameandtype; + + +typedef struct constant_arraydescriptor { + int arraytype; + classinfo *objectclass; + struct constant_arraydescriptor *elementdescriptor; + } constant_arraydescriptor; + + /* Mit einem Arraydescriptor kann ein Array-Typ dargestellt werden. + Bei normalen Arrays (z.B. Array von Bytes,...) gen"ugt dazu, + dass das Feld arraytype die entsprechende Kennzahl enth"alt + (z.B. ARRAYTYPE_BYTE). + Bei Arrays von Objekten (arraytype=ARRAYTYPE_OBJECT) muss das + Feld objectclass auf die Klassenstruktur der m"oglichen + Element-Objekte zeigen. + Bei Arrays von Arrays (arraytype=ARRAYTYPE_ARRAY) muss das + Feld elementdescriptor auf eine weiter arraydescriptor-Struktur + zeigen, die die Element-Typen beschreibt. + */ + + + +/********* Anmerkungen zum Constant-Pool: + + Die Typen der Eintr"age in den Constant-Pool werden durch die oben + definierten CONSTANT_.. Werte angegeben. + Bei allen Typen muss zus"atzlich noch eine Datenstruktur hinzugef"ugt + werden, die den wirklichen Wert angibt. + Bei manchen Typen reicht es, einen Verweis auf eine schon bereits + existierende Struktur (z.B. unicode-Texte) einzutragen, bei anderen + muss diese Struktur erst extra erzeugt werden. + Ich habe folgende Datenstrukturen f"ur diese Typen verwendet: + + Typ Struktur extra erzeugt? + ---------------------------------------------------------------------- + CONSTANT_Class classinfo nein + CONSTANT_Fieldref constant_FMIref ja + CONSTANT_Methodref constant_FMIref ja + CONSTANT_InterfaceMethodref constant_FMIref ja + CONSTANT_String unicode nein + CONSTANT_Integer constant_integer ja + CONSTANT_Float constant_float ja + CONSTANT_Long constant_long ja + CONSTANT_Double constant_double ja + CONSTANT_NameAndType constant_nameandtype ja + CONSTANT_Utf8 unicode nein + CONSTANT_Arraydescriptor constant_arraydescriptor ja + CONSTANT_UNUSED - + +*******************************/ + + + +/***************** Die Datenstrukturen fuer das Laufzeitsystem ***************/ + + + /********* Objekte ********** + + Alle Objekte (und Arrays), die am Heap gespeichert werden, m"ussen eine + folgende spezielle Datenstruktur ganz vorne stehen haben: + + */ + +typedef struct java_objectheader { /* Der Header f"ur alle Objekte */ + vftbl *vftbl; /* Zeiger auf die Function Table */ +} java_objectheader; + + + + /********* Arrays *********** + + Alle Arrays in Java sind auch gleichzeitig Objekte (d.h. sie haben auch + den obligatorischen Object-Header und darin einen Verweis auf eine Klasse) + Es gibt aber (der Einfachheit halber) nur eine einzige Klasse f"ur alle + m"oglichen Typen von Arrays, deshalb wird der tats"achliche Typ in einem + Feld im Array-Objekt selbst gespeichert. + Die Typen sind: */ + +#define ARRAYTYPE_INT 0 +#define ARRAYTYPE_LONG 1 +#define ARRAYTYPE_FLOAT 2 +#define ARRAYTYPE_DOUBLE 3 +#define ARRAYTYPE_BYTE 4 +#define ARRAYTYPE_CHAR 5 +#define ARRAYTYPE_SHORT 6 +#define ARRAYTYPE_BOOLEAN 7 +#define ARRAYTYPE_OBJECT 8 +#define ARRAYTYPE_ARRAY 9 + + + /** Der Header f"ur ein Java-Array **/ + +typedef struct java_arrayheader { /* Der Arrayheader f"ur alle Arrays */ + java_objectheader objheader; /* Der Object-Header */ + s4 size; /* Gr"osse des Arrays */ + s4 arraytype; /* Typ der Elemente */ +} java_arrayheader; + + + + /** Die Unterschiedlichen Strukturen f"ur alle Typen von Arrays **/ + +typedef struct java_chararray { + java_arrayheader header; + u2 data[1]; +} java_chararray; + +typedef struct java_floatheader { + java_arrayheader header; + float data[1]; +} java_floatarray; + +typedef struct java_doublearray { + java_arrayheader header; + double data[1]; +} java_doublearray; + + + /* achtung: die beiden Stukturen booleanarray und bytearray m"ussen + identisches memory-layout haben, weil mit den selben Funktionen + darauf zugegriffen wird */ + +typedef struct java_booleanarray { + java_arrayheader header; + u1 data[1]; +} java_booleanarray; + +typedef struct java_bytearray { + java_arrayheader header; + s1 data[1]; +} java_bytearray; + +typedef struct java_shortarray { + java_arrayheader header; + s2 data[1]; +} java_shortarray; + +typedef struct java_intarray { + java_arrayheader header; + s4 data[1]; +} java_intarray; + +typedef struct java_longarray { + java_arrayheader header; + s8 data[1]; +} java_longarray; + + + /* ACHTUNG: die beiden folgenden Strukturen m"ussen unbedingt gleiches + Memory-Layout haben, weil mit ein und der selben Funktion auf die + data-Eintr"age beider Typen zugegriffen wird !!!! */ + +typedef struct java_objectarray { + java_arrayheader header; + classinfo *elementtype; + java_objectheader *data[1]; +} java_objectarray; + +typedef struct java_arrayarray { + java_arrayheader header; + constant_arraydescriptor *elementdescriptor; + java_arrayheader *data[1]; +} java_arrayarray; + + + + +/************** Strukturen f"ur Klassen, Felder & Methoden *****************/ + + + /*** Struktur: fieldinfo ***/ + +typedef struct fieldinfo { /* Struktur f"ur ein Feld einer Klasse */ + s4 flags; /* die ACC-Flags */ + s4 type; /* Grunddatentyp */ + unicode *name; /* Name des Felds */ + unicode *descriptor; /* Typedescriptor in JavaVM-Form */ + + s4 offset; /* Offset vom Anfang des Objektes */ + /* (bei Instanzvariablen) */ + + union { /* Speicher f"ur den Wert */ + s4 i; /* (bei Klassenvariablen) */ + s8 l; + float f; + double d; + void *a; + } value; + + } fieldinfo; + + + /*** Struktur: exceptiontable ***/ + +typedef struct exceptiontable { /* Exceptionhandler-Eintrag in einer Methode */ + s4 startpc; /* Anfang des G"ultigkeitsbereichs */ + s4 endpc; /* Ende des Bereichs (exklusive) */ + s4 handlerpc; /* JavaVM-Position des Handlers */ + classinfo *catchtype; /* Typ der behandelten Exceptions (oder + NULL, wenn alle behandelt werden sollen) */ + } exceptiontable; + + + + /*** Struktur: methodinfo ***/ + +typedef struct methodinfo { /* Struktur f"ur eine Methode einer Klasse */ + s4 flags; /* die ACC-Flags */ + unicode *name; /* Name der Methode */ + unicode *descriptor; /* der JavaVM-Descriptorstring f"ur Methoden */ + s4 returntype; /* only temporary valid, return type */ + s4 paramcount; /* only temporary valid, number of parameters */ + u1 *paramtypes; /* only temporary valid, parameter types */ + classinfo *class; /* Die Klasse, der die Methode geh"ort */ + u4 vftblindex; /* Index dieser Methode f"ur die Virtual + Function Table (wenn es keine statische + Methode ist) */ + + s4 maxstack; /* maximale Stacktiefe des JavaVM-Codes */ + s4 maxlocals; /* maximale Anzahl der JavaVM-Variablen */ + u4 jcodelength; /* L"ange des JavaVM-Codes */ + u1 *jcode; /* und Zeiger auf den JavaVM-Code */ + + s4 exceptiontablelength; /* L"ange der Exceptintable */ + exceptiontable *exceptiontable; /* Die Exceptiontable selber */ + + u1 *stubroutine; /* STUB-Routine for compiling or calling + natives */ + u4 mcodelength; /* L"ange des generierten Maschinencodes */ + u1 *mcode; /* Zeiger auf den Maschinencode */ + u1 *entrypoint; /* Entrypoint to the Maschine-Code */ + + + } methodinfo; + + + /*** Struktur: classinfo ***/ + +struct classinfo { /* Datenstruktur f"ur eine Klasse */ + java_objectheader header; /* Weil auch Klassen als Objekte angesprochen + werden */ + + s4 flags; /* Die ACC-Flags */ + unicode *name; /* Name der Klasse */ + + s4 cpcount; /* Anzahl der Eintr"age im Constant-Pool */ + u1 *cptags; /* Die TAGs f"ur den Constant-Pool */ + voidptr *cpinfos; /* Die Zeiger auf die Info-Strukturen */ + + classinfo *super; /* Zeiger auf die "ubergeordnete Klasse */ + + s4 interfacescount; /* Anzahl der Interfaces */ + classinfo **interfaces; /* Zeiger auf die Interfaces */ + + s4 fieldscount; /* Anzahl der Felder */ + fieldinfo *fields; /* Die Tabelle der Felder */ + + s4 methodscount; /* Anzahl der Methoden */ + methodinfo *methods; /* Die Tabelle der Methoden */ + + + listnode listnode; /* Verkettungsstruktur (f"ur Listen) */ + + bool initialized; /* true, wenn Klasse bereits Initialisiert */ + bool linked; /* wird von `class_link` auf true gesetzt */ + s4 index; /* Hierarchietiefe (bei normalen Klassen) + oder fortlaufende Nummer (bei Interfaces)*/ + u4 instancesize; /* Gr"osse eines Objektes dieser Klasse */ + + vftbl *vftbl; + + methodinfo *finalizer; /* Finalizer-Methode f"ur die Klasse */ + }; + + +struct vftbl { + classinfo *class; /* Class, the function table belongs to */ + + s4 vftbllength; /* L"aenge der Virtual Function Table */ + + s4 interfacetablelength; /* L"ange der Interfacetable */ + u4 *interfacevftbllength; /* -> siehe unten */ + methodptr **interfacevftbl; + + methodptr table[1]; + }; + +/*********** Anmerkungen zur Interfacetable: + + "Ahnlich wie die 'normalen' virtuellen Methoden k"onnen auch die + Interface-Methoden mit Hilfe einer Art Virtual Function Table + aufgerufen werden. + Dazu werden alle Interfaces im System fortlaufend nummeriert (beginnend + bei 0), und f"ur jede Klasse wird eine ganze Tabelle von + Virtual Function Tables erzeugt, n"amlich zu jedem Interface, das die + Klasse implementiert, eine. + + z.B. Nehmen wir an, eine Klasse implementiert zwei Interfaces (die durch + die Nummerierung die Indizes 0 und 3 bekommen haben) + + Das sieht dann ungef"ahr so aus: + -------------- ------------- + interfacevftbl ---> | Eintrag 0 |---------> | Methode 0 |---> Methode X + | Eintrag 1 |--> NULL | Methode 1 |---> Methode Y + | Eintrag 2 |--> NULL | Methode 2 |---> Methode Z + | Eintrag 3 |-----+ ------------- + -------------- | + +---> ------------- + | Methode 0 |---> Methode X + | Methode 1 |---> Methode A + ------------- + --------------- + interfacevftlblength ---> | Wert 0 = 3 | + | Wert 1 = 0 | + | Wert 2 = 0 | + | Wert 3 = 2 | + --------------- + + Der Aufruf einer Interface-Methode geht dann so vor sich: + Zur Compilezeit steht der Index (i) des Interfaces und die Stelle (s), wo + in der entsprechenden Untertabelle die Methode eingetragen ist, schon fest. + Also muss zur Laufzeit nur mehr der n-te Eintrag aus der Interfacetable + gelesen werden, von dieser Tabelle aus wird der s-te Eintrag geholt, + und diese Methode wird angesprungen. + +****************/ + + + +/************************* Referenzen auf die wichtigen Systemklassen ********************/ + +extern classinfo *class_java_lang_Object; +extern classinfo *class_java_lang_String; +extern classinfo *class_java_lang_ClassCastException; +extern classinfo *class_java_lang_NullPointerException; +extern classinfo *class_java_lang_ArrayIndexOutOfBoundsException; +extern classinfo *class_java_lang_NegativeArraySizeException; +extern classinfo *class_java_lang_OutOfMemoryError; +extern classinfo *class_java_lang_ArithmeticException; +extern classinfo *class_java_lang_ArrayStoreException; +extern classinfo *class_java_lang_ThreadDeath; /* schani */ + +extern classinfo *class_array; + + +/********************** Vorgefertigte Instanzen einiger Systemklassen ********************/ + +extern java_objectheader *proto_java_lang_ClassCastException; +extern java_objectheader *proto_java_lang_NullPointerException; +extern java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException; +extern java_objectheader *proto_java_lang_NegativeArraySizeException; +extern java_objectheader *proto_java_lang_OutOfMemoryError; +extern java_objectheader *proto_java_lang_ArithmeticException; +extern java_objectheader *proto_java_lang_ArrayStoreException; +extern java_objectheader *proto_java_lang_ThreadDeath; /* schani */ + + +/********************** flag variables *********************/ + +extern bool compileall; +extern bool runverbose; +extern bool verbose; + + +/********************** trace variables ********************/ + +extern int count_class_infos; +extern int count_const_pool_len; +extern int count_vftbl_len; +extern int count_unicode_len; +extern int count_all_methods; +extern int count_vmcode_len; +extern int count_extable_len; + +#endif diff --git a/src/vm/jit/asmpart.h b/src/vm/jit/asmpart.h new file mode 100644 index 000000000..927ccd161 --- /dev/null +++ b/src/vm/jit/asmpart.h @@ -0,0 +1,41 @@ +/****************************** asmpart.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Headerfile for asmpart.S. asmpart.S contains the machine dependent + Java - C interface functions. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/10/15 + +*******************************************************************************/ + +int has_no_x_instr_set(); + /* determines if the byte support instruction set (21164a and higher) + is available. */ + +void synchronize_caches(); + + +void asm_call_jit_compiler (); + /* invokes the compiler for untranslated JavaVM methods. + Register R0 contains a pointer to the method info structure + (prepared by createcompilerstub). */ + +java_objectheader *asm_calljavamethod (methodinfo *m, void *arg1, void*arg2, + void*arg3, void*arg4); + /* This function calls a Java-method (which possibly needs compilation) + with up to 4 parameters. This function calls a Java-method (which + possibly needs compilation) with up to 4 parameters. */ + + +void asm_dumpregistersandcall ( functionptr f); + /* This funtion saves all callee saved registers and calls the function + which is passed as parameter. + This function is needed by the garbage collector, which needs to access + all registers which are stored on the stack. Unused registers are + cleared to avoid interferances with the GC. */ diff --git a/src/vm/loader.c b/src/vm/loader.c new file mode 100644 index 000000000..c94327c4e --- /dev/null +++ b/src/vm/loader.c @@ -0,0 +1,1994 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** loader.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the functions of the class loader. + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/06/03 + +*******************************************************************************/ + + +#include + +#include "global.h" +#include "loader.h" + +#include "tables.h" +#include "native.h" +#include "builtin.h" +#include "compiler.h" +#include "asmpart.h" + +#include "threads/thread.h" /* schani */ + + +/*************************** globale Variablen *******************************/ + +extern bool newcompiler; + +int count_class_infos = 0; +int count_const_pool_len = 0; +int count_vftbl_len = 0; +int count_all_methods = 0; +int count_vmcode_len = 0; +int count_extable_len = 0; + +bool loadverbose = false; /* Switches f"ur mehr Debug-Meldungen */ +bool linkverbose = false; +bool initverbose = false; + +bool makeinitializations = true; + +bool getloadingtime = false; +long int loadingtime = 0; + + +static u4 interfaceindex; /* fortlaufende Nummer f"ur Interfaces */ + +static list unloadedclasses; /* Liste alle referenzierten, aber noch nicht + geladenen Klassen */ +static list unlinkedclasses; /* Liste aller geladenen, aber noch nicht + gelinkten Klassen */ + list linkedclasses; /* Liste aller fertig gelinkten Klassen */ + + + +/***************** die Referenzen auf die wichtigen Systemklassen ************/ + +classinfo *class_java_lang_Object; +classinfo *class_java_lang_String; +classinfo *class_java_lang_ClassCastException; +classinfo *class_java_lang_NullPointerException; +classinfo *class_java_lang_ArrayIndexOutOfBoundsException; +classinfo *class_java_lang_NegativeArraySizeException; +classinfo *class_java_lang_OutOfMemoryError; +classinfo *class_java_lang_ArithmeticException; +classinfo *class_java_lang_ArrayStoreException; +classinfo *class_java_lang_ThreadDeath; /* schani */ + +classinfo *class_array; + + +/************ einige vorgefertigte Instanzen wichtiger Systemklassen *********/ + +java_objectheader *proto_java_lang_ClassCastException; +java_objectheader *proto_java_lang_NullPointerException; +java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException; +java_objectheader *proto_java_lang_NegativeArraySizeException; +java_objectheader *proto_java_lang_OutOfMemoryError; +java_objectheader *proto_java_lang_ArithmeticException; +java_objectheader *proto_java_lang_ArrayStoreException; +java_objectheader *proto_java_lang_ThreadDeath; /* schani */ + + + + +/****************************************************************************/ +/******************* Einige Support-Funkionen *******************************/ +/****************************************************************************/ + + +/********** interne Funktion: printflags (nur zu Debug-Zwecken) ************/ + +static void printflags (u2 f) +{ + if ( f & ACC_PUBLIC ) printf (" PUBLIC"); + if ( f & ACC_PRIVATE ) printf (" PRIVATE"); + if ( f & ACC_PROTECTED ) printf (" PROTECTED"); + if ( f & ACC_STATIC ) printf (" STATIC"); + if ( f & ACC_FINAL ) printf (" FINAL"); + if ( f & ACC_SYNCHRONIZED ) printf (" SYNCHRONIZED"); + if ( f & ACC_VOLATILE ) printf (" VOLATILE"); + if ( f & ACC_TRANSIENT ) printf (" TRANSIENT"); + if ( f & ACC_NATIVE ) printf (" NATIVE"); + if ( f & ACC_INTERFACE ) printf (" INTERFACE"); + if ( f & ACC_ABSTRACT ) printf (" ABSTRACT"); +} + + +/************************* Funktion: skipattribute **************************** + + "uberliest im ClassFile eine (1) 'attribute'-Struktur + +******************************************************************************/ + +static void skipattribute () +{ + u4 len; + + suck_u2 (); + len = suck_u4 (); + skip_nbytes (len); +} + +/********************** Funktion: skipattributebody *************************** + + "uberliest im Classfile ein attribut, wobei die 16-bit - attribute_name - + Referenz schon gelesen worden ist. + +******************************************************************************/ + +static void skipattributebody () +{ + u4 len = suck_u4 (); + skip_nbytes (len); +} + + +/************************* Funktion: skipattributes *************************** + + "uberliest im ClassFile eine gew"unschte Anzahl von attribute-Strukturen + +******************************************************************************/ + +static void skipattributes (u4 num) +{ + u4 i; + for (i=0; i 0) { + b1 = suck_u1 (); + utflen --; + if (b1<0x80) letter = b1; + else { + b2 = suck_u1 (); + utflen --; + if (b1<0xe0) letter = ((b1 & 0x1f) << 6) | (b2 & 0x3f); + else { + b3 = suck_u1 (); + utflen --; + letter = ((b1 & 0x0f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f); + } + } + + + if (unicodelen >= MAXUNICODELEN) { + panic ("String constant too long"); + } + + unicodebuffer[unicodelen++] = letter; + } + + + return unicode_new_u2 (unicodebuffer, unicodelen); +} + + + +/******************** interne Funktion: checkfieldtype ***********************/ + +static void checkfieldtype (u2 *text, u4 *count, u4 length) +{ + u4 l; + + if (*count >= length) panic ("Type-descriptor exceeds unicode length"); + + l = text[(*count)++]; + + switch (l) { + default: panic ("Invalid symbol in type descriptor"); + return; + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': return; + + case '[': checkfieldtype (text, count, length); + return; + + case 'L': + { + u4 tlen,tstart = *count; + + if (*count >= length) + panic ("Objecttype descriptor of length zero"); + + while ( text[*count] != ';' ) { + (*count)++; + if (*count >= length) + panic ("Missing ';' in objecttype-descriptor"); + } + + tlen = (*count) - tstart; + (*count)++; + + if (tlen == 0) panic ("Objecttype descriptor with empty name"); + + class_get ( unicode_new_u2 (text+tstart, tlen) ); + } + } +} + + +/******************* Funktion: checkfielddescriptor *************************** + + "uberpr"uft, ob ein Field-Descriptor ein g"ultiges Format hat. + Wenn nicht, dann wird das System angehalten. + Au"serdem werden alle Klassen, die hier referenziert werden, + in die Liste zu ladender Klassen eingetragen. + +******************************************************************************/ + +void checkfielddescriptor (unicode *d) +{ + u4 count=0; + checkfieldtype (d->text, &count, d->length); + if (count != d->length) panic ("Invalid type-descritor encountered"); +} + + +/******************* Funktion: checkmethoddescriptor ************************** + + "uberpr"uft, ob ein Method-Descriptor ein g"ultiges Format hat. + Wenn nicht, dann wird das System angehalten. + Au"serdem werden alle Klassen, die hier referenziert werden, + in die Liste zu ladender Klassen eingetragen. + +******************************************************************************/ + +void checkmethoddescriptor (unicode *d) +{ + u2 *text=d->text; + u4 length=d->length; + u4 count=0; + + if (length<2) panic ("Method descriptor too short"); + if (text[0] != '(') panic ("Missing '(' in method descriptor"); + count=1; + + while (text[count] != ')') { + checkfieldtype (text,&count,length); + if ( count > length-2 ) panic ("Unexpected end of descriptor"); + } + + count++; + if (text[count] == 'V') count++; + else checkfieldtype (text, &count,length); + + if (count != length) panic ("Method-descriptor has exceeding chars"); +} + + +/******************** Funktion: buildarraydescriptor **************************** + + erzeugt zu einem namentlich als u2-String vorliegenden Arraytyp eine + entsprechende constant_arraydescriptor - Struktur + +********************************************************************************/ + +static constant_arraydescriptor * buildarraydescriptor(u2 *name, u4 namelen) +{ + constant_arraydescriptor *d; + + if (name[0]!='[') panic ("Attempt to build arraydescriptor for non-array"); + d = NEW (constant_arraydescriptor); + d -> objectclass = NULL; + d -> elementdescriptor = NULL; + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_arraydescriptor); +#endif + + switch (name[1]) { + case 'Z': d -> arraytype = ARRAYTYPE_BOOLEAN; break; + case 'B': d -> arraytype = ARRAYTYPE_BYTE; break; + case 'C': d -> arraytype = ARRAYTYPE_CHAR; break; + case 'D': d -> arraytype = ARRAYTYPE_DOUBLE; break; + case 'F': d -> arraytype = ARRAYTYPE_FLOAT; break; + case 'I': d -> arraytype = ARRAYTYPE_INT; break; + case 'J': d -> arraytype = ARRAYTYPE_LONG; break; + case 'S': d -> arraytype = ARRAYTYPE_SHORT; break; + + case '[': + d -> arraytype = ARRAYTYPE_ARRAY; + d -> elementdescriptor = buildarraydescriptor (name+1, namelen-1); + break; + + case 'L': + d -> arraytype = ARRAYTYPE_OBJECT; + d -> objectclass = class_get ( unicode_new_u2 (name+2, namelen-3) ); + break; + } + return d; +} + + +/******************* Funktion: freearraydescriptor **************************** + + entfernt eine mit buildarraydescriptor erzeugte Struktur wieder + aus dem Speicher + +*******************************************************************************/ + +static void freearraydescriptor (constant_arraydescriptor *d) +{ + while (d) { + constant_arraydescriptor *n = d->elementdescriptor; + FREE (d, constant_arraydescriptor); + d = n; + } +} + +/*********************** Funktion: displayarraydescriptor *********************/ + +static void displayarraydescriptor (constant_arraydescriptor *d) +{ + switch (d->arraytype) { + case ARRAYTYPE_BOOLEAN: printf ("boolean[]"); break; + case ARRAYTYPE_BYTE: printf ("byte[]"); break; + case ARRAYTYPE_CHAR: printf ("char[]"); break; + case ARRAYTYPE_DOUBLE: printf ("double[]"); break; + case ARRAYTYPE_FLOAT: printf ("float[]"); break; + case ARRAYTYPE_INT: printf ("int[]"); break; + case ARRAYTYPE_LONG: printf ("long[]"); break; + case ARRAYTYPE_SHORT: printf ("short[]"); break; + case ARRAYTYPE_ARRAY: displayarraydescriptor(d->elementdescriptor); printf("[]"); break; + case ARRAYTYPE_OBJECT: unicode_display(d->objectclass->name); printf("[]"); break; + } +} + + + +/*****************************************************************************/ +/******************** Funktionen fuer Fields *********************************/ +/*****************************************************************************/ + + +/************************ Funktion: field_load ******************************** + + l"adt alle Informationen f"ur eine Feld einer Methode aus dem ClassFile, + und f"ullt mit diesen Infos eine schon existierende 'fieldinfo'-Struktur. + Bei 'static'-Fields wird auch noch ein Platz auf dem Datensegment + reserviert. + +******************************************************************************/ + +static void field_load (fieldinfo *f, classinfo *c) +{ + u4 attrnum,i; + u4 jtype; + + f -> flags = suck_u2 (); + f -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + f -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + f -> type = jtype = desc_to_type (f->descriptor); + f -> offset = 0; + + switch (f->type) { + case TYPE_INT: f->value.i = 0; break; + case TYPE_FLOAT: f->value.f = 0.0; break; + case TYPE_DOUBLE: f->value.d = 0.0; break; + case TYPE_ADDRESS: f->value.a = NULL; + heap_addreference (&(f->value.a)); + break; + case TYPE_LONG: +#if U8_AVAILABLE + f->value.l = 0; break; +#else + f->value.l.low = 0; f->value.l.high = 0; break; +#endif + } + + attrnum = suck_u2(); + for (i=0; ivalue.i = ci -> value; + } + break; + + case TYPE_LONG: { + constant_long *cl = + class_getconstant(c, pindex, CONSTANT_Long); + + f->value.l = cl -> value; + } + break; + + case TYPE_FLOAT: { + constant_float *cf = + class_getconstant(c, pindex, CONSTANT_Float); + + f->value.f = cf->value; + } + break; + + case TYPE_DOUBLE: { + constant_double *cd = + class_getconstant(c, pindex, CONSTANT_Double); + + f->value.d = cd->value; + } + break; + + case TYPE_ADDRESS: { + unicode *u = + class_getconstant(c, pindex, CONSTANT_String); + f->value.a = literalstring_new(u); + } + break; + + default: + log_text ("Invalid Constant - Type"); + + } + + } + } + +} + + +/********************** Funktion: field_free *********************************/ + +static void field_free (fieldinfo *f) +{ +} + + +/************** Funktion: field_display (nur zu Debug-Zwecken) ***************/ + +static void field_display (fieldinfo *f) +{ + printf (" "); + printflags (f -> flags); + printf (" "); + unicode_display (f -> name); + printf (" "); + unicode_display (f -> descriptor); + printf (" offset: %ld\n", (long int) (f -> offset) ); +} + + + + +/*****************************************************************************/ +/************************* Funktionen f"ur Methods ***************************/ +/*****************************************************************************/ + + +/*********************** Funktion: method_load ******************************** + + l"adt die Infos f"ur eine Methode aus dem ClassFile und f"ullt damit + eine schon existierende 'methodinfo'-Struktur aus. + Bei allen native-Methoden wird au"serdem gleich der richtige + Funktionszeiger eingetragen, bei JavaVM-Methoden einstweilen ein + Zeiger auf den Compiler + +******************************************************************************/ + +static void method_load (methodinfo *m, classinfo *c) +{ + u4 attrnum,i,e; + +#ifdef STATISTICS + count_all_methods++; +#endif + + m -> class = c; + + m -> flags = suck_u2 (); + m -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + m -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + + m -> jcode = NULL; + m -> exceptiontable = NULL; + m -> entrypoint = NULL; + m -> mcode = NULL; + m -> stubroutine = NULL; + + if (! (m->flags & ACC_NATIVE) ) { + m -> stubroutine = createcompilerstub (m); + } + else { + functionptr f = native_findfunction + (c->name, m->name, m->descriptor, (m->flags & ACC_STATIC) != 0); + if (f) { + if (newcompiler) + m -> stubroutine = ncreatenativestub (f, m); + else + m -> stubroutine = createnativestub (f, m); + } + } + + + attrnum = suck_u2(); + for (i=0; i jcode) panic ("Two code-attributes for one method!"); + + suck_u4(); + m -> maxstack = suck_u2(); + m -> maxlocals = suck_u2(); + m -> jcodelength = suck_u4(); + m -> jcode = MNEW (u1, m->jcodelength); + suck_nbytes (m->jcode, m->jcodelength); + m -> exceptiontablelength = suck_u2 (); + m -> exceptiontable = + MNEW (exceptiontable, m->exceptiontablelength); + +#ifdef STATISTICS + count_vmcode_len += m->jcodelength + 18; + count_extable_len += 8 * m->exceptiontablelength; +#endif + + for (e=0; e < m->exceptiontablelength; e++) { + u4 idx; + m -> exceptiontable[e].startpc = suck_u2(); + m -> exceptiontable[e].endpc = suck_u2(); + m -> exceptiontable[e].handlerpc = suck_u2(); + + idx = suck_u2(); + if (!idx) m -> exceptiontable[e].catchtype = NULL; + else { + m -> exceptiontable[e].catchtype = + class_getconstant (c, idx, CONSTANT_Class); + } + } + + skipattributes ( suck_u2() ); + } + + } + + +} + + +/********************* Funktion: method_free ********************************** + + gibt allen Speicher, der extra f"ur eine Methode angefordert wurde, + wieder frei + +******************************************************************************/ + +static void method_free (methodinfo *m) +{ + if (m->jcode) MFREE (m->jcode, u1, m->jcodelength); + if (m->exceptiontable) + MFREE (m->exceptiontable, exceptiontable, m->exceptiontablelength); + if (m->mcode) CFREE (m->mcode, m->mcodelength); + if (m->stubroutine) { + if (m->flags & ACC_NATIVE) removenativestub (m->stubroutine); + else removecompilerstub (m->stubroutine); + } +} + + +/************** Funktion: method_display (nur zu Debug-Zwecken) *************/ + +void method_display (methodinfo *m) +{ + printf (" "); + printflags (m -> flags); + printf (" "); + unicode_display (m -> name); + printf (" "); + unicode_display (m -> descriptor); + printf ("\n"); +} + + +/******************** Funktion: method_canoverwrite *************************** + + "uberpr"ft, ob eine Methode mit einer anderen typ- und namensidentisch + ist (also mit einer Methodendefinition eine andere "uberschrieben + werden kann). + +******************************************************************************/ + +static bool method_canoverwrite (methodinfo *m, methodinfo *old) +{ + if (m->name != old->name) return false; + if (m->descriptor != old->descriptor) return false; + if (m->flags & ACC_STATIC) return false; + return true; +} + + + + +/*****************************************************************************/ +/************************ Funktionen fuer Class ******************************/ +/*****************************************************************************/ + + +/******************** Funktion: class_get ************************************* + + Sucht im System die Klasse mit dem gew"unschten Namen, oder erzeugt + eine neue 'classinfo'-Struktur (und h"angt sie in die Liste der zu + ladenen Klassen ein). + +******************************************************************************/ + +classinfo *class_get (unicode *u) +{ + classinfo *c; + + if (u->class) return u->class; + +#ifdef STATISTICS + count_class_infos += sizeof(classinfo); +#endif + + c = NEW (classinfo); + c -> flags = 0; + c -> name = u; + c -> cpcount = 0; + c -> cptags = NULL; + c -> cpinfos = NULL; + c -> super = NULL; + c -> interfacescount = 0; + c -> interfaces = NULL; + c -> fieldscount = 0; + c -> fields = NULL; + c -> methodscount = 0; + c -> methods = NULL; + c -> linked = false; + c -> index = 0; + c -> instancesize = 0; + c -> vftbl = NULL; + c -> initialized = false; + + unicode_setclasslink (u,c); + list_addlast (&unloadedclasses, c); + + return c; +} + + + +/******************** Funktion: class_getconstant ***************************** + + holt aus dem ConstantPool einer Klasse den Wert an der Stelle 'pos'. + Der Wert mu"s vom Typ 'ctype' sein, sonst wird das System angehalten. + +******************************************************************************/ + +voidptr class_getconstant (classinfo *c, u4 pos, u4 ctype) +{ + if (pos >= c->cpcount) + panic ("Attempt to access constant outside range"); + if (c->cptags[pos] != ctype) { + sprintf (logtext, "Type mismatch on constant: %d requested, %d here", + (int) ctype, (int) c->cptags[pos] ); + error(); + } + + return c->cpinfos[pos]; +} + + +/********************* Funktion: class_constanttype *************************** + + Findet heraus, welchen Typ ein Eintrag in den ConstantPool einer + Klasse hat. + +******************************************************************************/ + +u4 class_constanttype (classinfo *c, u4 pos) +{ + if (pos >= c->cpcount) + panic ("Attempt to access constant outside range"); + return c->cptags[pos]; +} + + +/******************** Funktion: class_loadcpool ******************************* + + l"adt den gesammten ConstantPool einer Klasse. + + Dabei werden die einzelnen Eintr"age in ein wesentlich einfachers + Format gebracht (Klassenreferenzen werden aufgel"ost, ...) + F"ur eine genaue "Ubersicht "uber das kompakte Format siehe: 'global.h' + +******************************************************************************/ + +static void class_loadcpool (classinfo *c) +{ + + typedef struct forward_class { /* Diese Strukturen dienen dazu, */ + struct forward_class *next; /* die Infos, die beim ersten */ + u2 thisindex; /* Durchgang durch den ConstantPool */ + u2 name_index; /* gelesen werden, aufzunehmen. */ + } forward_class; /* Erst nachdem der ganze Pool */ + /* gelesen wurde, k"onnen alle */ + typedef struct forward_string { /* Felder kompletiert werden */ + struct forward_string *next; /* (und das auch nur in der richtigen */ + u2 thisindex; /* Reihenfolge) */ + u2 string_index; + } forward_string; + + typedef struct forward_nameandtype { + struct forward_nameandtype *next; + u2 thisindex; + u2 name_index; + u2 sig_index; + } forward_nameandtype; + + typedef struct forward_fieldmethint { + struct forward_fieldmethint *next; + u2 thisindex; + u1 tag; + u2 class_index; + u2 nameandtype_index; + } forward_fieldmethint; + + + + u4 idx; + long int dumpsize = dump_size (); + + forward_class *forward_classes = NULL; + forward_string *forward_strings = NULL; + forward_nameandtype *forward_nameandtypes = NULL; + forward_fieldmethint *forward_fieldmethints = NULL; + + u4 cpcount = c -> cpcount = suck_u2(); + u1 *cptags = c -> cptags = MNEW (u1, cpcount); + voidptr *cpinfos = c -> cpinfos = MNEW (voidptr, cpcount); + +#ifdef STATISTICS + count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; +#endif + + + for (idx=0; idx next = forward_classes; + forward_classes = nfc; + + nfc -> thisindex = idx; + nfc -> name_index = suck_u2 (); + + idx++; + break; + } + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + forward_fieldmethint *nff = DNEW (forward_fieldmethint); + + nff -> next = forward_fieldmethints; + forward_fieldmethints = nff; + + nff -> thisindex = idx; + nff -> tag = t; + nff -> class_index = suck_u2 (); + nff -> nameandtype_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_String: { + forward_string *nfs = DNEW (forward_string); + + nfs -> next = forward_strings; + forward_strings = nfs; + + nfs -> thisindex = idx; + nfs -> string_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_NameAndType: { + forward_nameandtype *nfn = DNEW (forward_nameandtype); + + nfn -> next = forward_nameandtypes; + forward_nameandtypes = nfn; + + nfn -> thisindex = idx; + nfn -> name_index = suck_u2 (); + nfn -> sig_index = suck_u2 (); + + idx ++; + break; + } + + case CONSTANT_Integer: { + constant_integer *ci = NEW (constant_integer); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_integer); +#endif + + ci -> value = suck_s4 (); + cptags [idx] = CONSTANT_Integer; + cpinfos [idx] = ci; + idx ++; + + break; + } + + case CONSTANT_Float: { + constant_float *cf = NEW (constant_float); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_float); +#endif + + cf -> value = suck_float (); + cptags [idx] = CONSTANT_Float; + cpinfos[idx] = cf; + idx ++; + break; + } + + case CONSTANT_Long: { + constant_long *cl = NEW(constant_long); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_long); +#endif + + cl -> value = suck_s8 (); + cptags [idx] = CONSTANT_Long; + cpinfos [idx] = cl; + idx += 2; + break; + } + + case CONSTANT_Double: { + constant_double *cd = NEW(constant_double); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_double); +#endif + + cd -> value = suck_double (); + cptags [idx] = CONSTANT_Double; + cpinfos [idx] = cd; + idx += 2; + break; + } + + case CONSTANT_Utf8: { + unicode *u; + + u = loadUtf8 (); + + cptags [idx] = CONSTANT_Utf8; + cpinfos [idx] = u; + idx++; + break; + } + + default: + sprintf (logtext, "Unkown constant type: %d",(int) t); + error (); + + } /* end switch */ + + } /* end while */ + + + + /* Aufl"osen der noch unfertigen Eintr"age */ + + while (forward_classes) { + unicode *name = + class_getconstant (c, forward_classes -> name_index, CONSTANT_Utf8); + + if ( (name->length>0) && (name->text[0]=='[') ) { + checkfielddescriptor (name); + + cptags [forward_classes -> thisindex] = CONSTANT_Arraydescriptor; + cpinfos [forward_classes -> thisindex] = + buildarraydescriptor(name->text, name->length); + + } + else { + cptags [forward_classes -> thisindex] = CONSTANT_Class; + cpinfos [forward_classes -> thisindex] = class_get (name); + } + forward_classes = forward_classes -> next; + + } + + while (forward_strings) { + unicode *text = + class_getconstant (c, forward_strings -> string_index, CONSTANT_Utf8); + + cptags [forward_strings -> thisindex] = CONSTANT_String; + cpinfos [forward_strings -> thisindex] = text; + + forward_strings = forward_strings -> next; + } + + while (forward_nameandtypes) { + constant_nameandtype *cn = NEW (constant_nameandtype); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_nameandtype); +#endif + + cn -> name = class_getconstant + (c, forward_nameandtypes -> name_index, CONSTANT_Utf8); + cn -> descriptor = class_getconstant + (c, forward_nameandtypes -> sig_index, CONSTANT_Utf8); + + cptags [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType; + cpinfos [forward_nameandtypes -> thisindex] = cn; + + forward_nameandtypes = forward_nameandtypes -> next; + } + + + while (forward_fieldmethints) { + constant_nameandtype *nat; + constant_FMIref *fmi = NEW (constant_FMIref); + +#ifdef STATISTICS + count_const_pool_len += sizeof(constant_FMIref); +#endif + + nat = class_getconstant + (c, forward_fieldmethints -> nameandtype_index, CONSTANT_NameAndType); + + fmi -> class = class_getconstant + (c, forward_fieldmethints -> class_index, CONSTANT_Class); + fmi -> name = nat -> name; + fmi -> descriptor = nat -> descriptor; + + cptags [forward_fieldmethints -> thisindex] = forward_fieldmethints -> tag; + cpinfos [forward_fieldmethints -> thisindex] = fmi; + + switch (forward_fieldmethints -> tag) { + case CONSTANT_Fieldref: checkfielddescriptor (fmi->descriptor); + break; + case CONSTANT_InterfaceMethodref: + case CONSTANT_Methodref: checkmethoddescriptor (fmi->descriptor); + break; + } + + forward_fieldmethints = forward_fieldmethints -> next; + + } + + + dump_release (dumpsize); +} + + +/********************** Funktion: class_load ********************************** + + l"adt alle Infos f"ur eine ganze Klasse aus einem ClassFile. Die + 'classinfo'-Struktur mu"s bereits angelegt worden sein. + + Die Superklasse und die Interfaces, die diese Klasse implementiert, + m"ussen zu diesem Zeitpunkt noch nicht geladen sein, die + Verbindung dazu wird sp"ater in der Funktion 'class_link' hergestellt. + + Die gelesene Klasse wird dann aus der Liste 'unloadedclasses' ausgetragen + und in die Liste 'unlinkedclasses' eingh"angt. + +******************************************************************************/ + +static void class_load (classinfo *c) +{ + u4 i; + u4 mi,ma; + + + if (loadverbose) { + sprintf (logtext, "Loading class: "); + unicode_sprint (logtext+strlen(logtext), c->name ); + dolog(); + } + + + suck_start (c->name); + + if (suck_u4() != MAGIC) panic("Can not find class-file signature"); + mi = suck_u2(); + ma = suck_u2(); + if (ma != MAJOR_VERSION) { + sprintf (logtext, "Can only support major version %d, but not %d", + MAJOR_VERSION, (int) ma); + error(); + } + if (mi > MINOR_VERSION) { + sprintf (logtext, "Minor version %d is not yet supported.", (int) mi); + error(); + } + + + class_loadcpool (c); + + c -> flags = suck_u2 (); + suck_u2 (); /* this */ + + if ( (i = suck_u2 () ) ) { + c -> super = class_getconstant (c, i, CONSTANT_Class); + } + else { + c -> super = NULL; + } + + c -> interfacescount = suck_u2 (); + c -> interfaces = MNEW (classinfo*, c -> interfacescount); + for (i=0; i < c -> interfacescount; i++) { + c -> interfaces [i] = + class_getconstant (c, suck_u2(), CONSTANT_Class); + } + + c -> fieldscount = suck_u2 (); + c -> fields = MNEW (fieldinfo, c -> fieldscount); + for (i=0; i < c -> fieldscount; i++) { + field_load (&(c->fields[i]), c); + } + + c -> methodscount = suck_u2 (); + c -> methods = MNEW (methodinfo, c -> methodscount); + for (i=0; i < c -> methodscount; i++) { + method_load (&(c -> methods [i]), c); + } + +#ifdef STATISTICS + count_class_infos += sizeof(classinfo*) * c -> interfacescount; + count_class_infos += sizeof(fieldinfo) * c -> fieldscount; + count_class_infos += sizeof(methodinfo) * c -> methodscount; +#endif + + + skipattributes ( suck_u2() ); + + + suck_stop (); + + list_remove (&unloadedclasses, c); + list_addlast (&unlinkedclasses, c); +} + + + +/************** interne Funktion: class_highestinterface ********************** + + wird von der Funktion class_link ben"otigt, um festzustellen, wie gro"s + die Interfacetable einer Klasse sein mu"s. + +******************************************************************************/ + +static s4 class_highestinterface (classinfo *c) +{ + s4 h; + s4 i; + + if ( ! (c->flags & ACC_INTERFACE) ) { + sprintf (logtext, "Interface-methods count requested for non-interface: "); + unicode_sprint (logtext+strlen(logtext), c->name); + error(); + } + + h = c->index; + for (i=0; iinterfacescount; i++) { + s4 h2 = class_highestinterface (c->interfaces[i]); + if (h2>h) h=h2; + } + return h; +} + + +/**************** Funktion: class_addinterface ******************************** + + wird von der Funktion class_link ben"otigt, um eine Virtual Function + Table f"ur ein Interface (und alle weiteren von diesem Interface + implementierten Interfaces) in eine Klasse einzutragen. + +******************************************************************************/ + +static void class_addinterface (classinfo *c, classinfo *ic) +{ + u4 i = ic->index; + u4 j,m; + vftbl *vftbl = c->vftbl; + + if (i>=vftbl->interfacetablelength) panic ("Interfacetable-Overflow"); + if (vftbl->interfacevftbl[i]) return; + + if (ic->methodscount==0) { /* wenn interface keine Methoden hat, dann + trotzdem eine Tabelle mit L"ange 1 anlegen, + wegen Subclass-Tests */ + vftbl -> interfacevftbllength[i] = 1; + vftbl -> interfacevftbl[i] = MNEW(methodptr, 1); + vftbl -> interfacevftbl[i][0] = NULL; + } + else { + vftbl -> interfacevftbllength[i] = ic -> methodscount; + vftbl -> interfacevftbl[i] = MNEW(methodptr, ic -> methodscount); + +#ifdef STATISTICS + count_vftbl_len += sizeof(methodptr) * ic -> methodscount; +#endif + + for (j=0; jmethodscount; j++) { + classinfo *sc = c; + while (sc) { + for (m=0; mmethodscount; m++) { + methodinfo *mi = &(sc->methods[m]); + if (method_canoverwrite (mi, &(ic->methods[j])) ) { + vftbl->interfacevftbl[i][j] = + vftbl->table[mi->vftblindex]; + goto foundmethod; + } + } + sc = sc->super; + } + foundmethod: ; + } + } + + for (j=0; jinterfacescount; j++) + class_addinterface(c, ic->interfaces[j]); +} + + +/********************** Funktion: class_link ********************************** + + versucht, eine Klasse in das System voll zu integrieren (linken). Dazu + m"ussen sowol die Superklasse, als auch alle implementierten + Interfaces schon gelinkt sein. + Diese Funktion berechnet sowohl die L"ange (in Bytes) einer Instanz + dieser Klasse, als auch die Virtual Function Tables f"ur normale + Methoden als auch Interface-Methoden. + + Wenn die Klasse erfolgreich gelinkt werden kann, dann wird sie aus + der Liste 'unlinkedclasses' ausgeh"angt, und in die Klasse 'linkedclasses' + eingetragen. + Wenn nicht, dann wird sie ans Ende der Liste 'unlinkedclasses' gestellt. + + Achtung: Bei zyklischen Klassendefinitionen ger"at das Programm hier in + eine Endlosschleife!! (Da muss ich mir noch was einfallen lassen) + +******************************************************************************/ + +static void class_link (classinfo *c) +{ + u4 supervftbllength; /* L"ange der VFTBL der Superklasse */ + u4 vftbllength; /* L"ange der VFTBL dieser Klasse */ + classinfo *super = c->super; + classinfo *ic,*c2; /* Hilfsvariablen */ + vftbl *v; + u4 i; + + + /* schauen, ob alle "ubergeordneten Klassen schon fertig sind, + und richtiges Initialisieren der lokalen Variablen */ + + for ( i=0; iinterfacescount; i++) { + ic = c->interfaces[i]; + if ( !ic -> linked) { + list_remove (&unlinkedclasses,c ); + list_addlast (&unlinkedclasses,c ); + return; + } + } + + if (! super) { + c -> index = 0; + c -> instancesize = sizeof (java_objectheader); + + vftbllength = supervftbllength = 0; + + c -> finalizer = NULL; + } + else { + if ( !super -> linked ) { + list_remove (&unlinkedclasses,c ); + list_addlast (&unlinkedclasses,c ); + return; + } + + if ( c->flags & ACC_INTERFACE) c -> index = interfaceindex++; + else c -> index = super -> index + 1; + + c -> instancesize = super -> instancesize; + + vftbllength = supervftbllength = super -> vftbl -> vftbllength; + + c -> finalizer = super -> finalizer; + } + + + if (linkverbose) { + sprintf (logtext, "Linking Class: "); + unicode_sprint (logtext+strlen(logtext), c->name ); + dolog (); + } + + /* Erstellen der Virtual Function Table */ + + for (i=0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (! (m->flags & ACC_STATIC) ) { + classinfo *sc = super; + while (sc) { + int j; + for (j=0; j < sc->methodscount; j++) { + if ( method_canoverwrite (m, &(sc->methods[j])) ) { + m -> vftblindex = sc->methods[j].vftblindex; + goto foundvftblindex; + } + } + sc = sc->super; + } + m -> vftblindex = (vftbllength++); + foundvftblindex: ; + } + } + +#ifdef STATISTICS + count_vftbl_len += sizeof(vftbl) + sizeof(methodptr)*(vftbllength-1); +#endif + + c -> vftbl = v = (vftbl*) + mem_alloc (sizeof(vftbl) + sizeof(methodptr)*(vftbllength-1)); + v -> class = c; + v -> vftbllength = vftbllength; + v -> interfacetablelength = 0; + + for (i=0; i < supervftbllength; i++) + v -> table[i] = super -> vftbl -> table[i]; + + for (i=0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + if ( ! (m->flags & ACC_STATIC) ) { + v -> table[m->vftblindex] = m -> stubroutine; + } + } + + + /* Berechnen der Instanzengr"o"se und der Offsets der einzelnen + Felder */ + + for (i=0; i < c->fieldscount; i++) { + u4 dsize; + fieldinfo *f = &(c -> fields[i]); + + if ( ! (f->flags & ACC_STATIC) ) { + dsize = desc_typesize (f->descriptor); + c -> instancesize = ALIGN ( c->instancesize, dsize); + f -> offset = c -> instancesize; + c -> instancesize += dsize; + } + + } + + + /* Berechnen der Virtual Function Tables f"ur alle Interfaces */ + + c2 = c; + while (c2) { + for (i=0; iinterfacescount; i++) { + s4 h = class_highestinterface (c2->interfaces[i]) + 1; + if ( h > v->interfacetablelength) v->interfacetablelength = h; + } + c2 = c2->super; + } + v -> interfacevftbllength = MNEW (u4, v->interfacetablelength); + v -> interfacevftbl = MNEW (methodptr *, v->interfacetablelength); + +#ifdef STATISTICS + count_vftbl_len += (4 + sizeof(methodptr*)) * v->interfacetablelength; +#endif + + for (i=0; i < v->interfacetablelength; i++) { + v -> interfacevftbllength[i] = 0; + v -> interfacevftbl[i] = NULL; + } + + c2 = c; + while (c2) { + for (i=0; iinterfacescount; i++) { + class_addinterface (c, c2->interfaces[i]); + } + c2 = c2->super; + } + + + + /* Die finalizer-Methode suchen und eintragen (wenn vorhanden), + aber nur bei Objekten ausser java.lang.Object */ + + if (super) { + methodinfo *fi; + static unicode *finame=NULL,*fidesc=NULL; + + if (!finame) finame = unicode_new_char ("finalize"); + if (!fidesc) fidesc = unicode_new_char ("()V"); + + fi = class_findmethod (c, finame, fidesc); + if (fi) { + if (! (fi->flags & ACC_STATIC) ) { + c -> finalizer = fi; + } + } + } + + + /* Abschlie"sende Aktionen */ + + c -> linked = true; + + list_remove (&unlinkedclasses, c); + list_addlast (&linkedclasses, c); +} + + +/******************* Funktion: class_freepool ********************************* + + Gibt alle Resourcen, die der ConstantPool einer Klasse ben"otigt, + wieder frei. + +******************************************************************************/ + +static void class_freecpool (classinfo *c) +{ + u4 idx; + u4 tag; + voidptr info; + + for (idx=0; idx < c->cpcount; idx++) { + tag = c->cptags[idx]; + info = c->cpinfos[idx]; + + if (info != NULL) { + switch (tag) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + FREE (info, constant_FMIref); + break; + case CONSTANT_Integer: + FREE (info, constant_integer); + break; + case CONSTANT_Float: + FREE (info, constant_float); + break; + case CONSTANT_Long: + FREE (info, constant_long); + break; + case CONSTANT_Double: + FREE (info, constant_double); + break; + case CONSTANT_NameAndType: + FREE (info, constant_nameandtype); + break; + case CONSTANT_Arraydescriptor: + freearraydescriptor (info); + break; + } + } + } + + MFREE (c -> cptags, u1, c -> cpcount); + MFREE (c -> cpinfos, voidptr, c -> cpcount); +} + + +/*********************** Funktion: class_free ********************************* + + Gibt alle Resourcen, die eine ganze Klasse ben"otigt, frei + +******************************************************************************/ + +static void class_free (classinfo *c) +{ + u4 i; + vftbl *v; + + unicode_unlinkclass (c->name); + + class_freecpool (c); + + MFREE (c->interfaces, classinfo*, c->interfacescount); + + for (i=0; i < c->fieldscount; i++) field_free ( &(c->fields[i]) ); + MFREE (c->fields, fieldinfo, c->fieldscount); + + for (i=0; i < c->methodscount; i++) method_free ( &(c->methods[i]) ); + MFREE (c->methods, methodinfo, c->methodscount); + + if ( (v = c->vftbl) ) { + for (i=0; iinterfacetablelength; i++) { + MFREE (v->interfacevftbl[i], methodptr, v->interfacevftbllength[i]); + } + MFREE (v->interfacevftbllength, u4, v->interfacetablelength); + MFREE (v->interfacevftbl, methodptr*, v->interfacetablelength); + + mem_free (v, sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1)); + } + + FREE (c, classinfo); +} + + +/************************* Funktion: class_findfield ************************* + + sucht in einer 'classinfo'-Struktur nach einem Feld mit gew"unschtem + Namen und Typ. + +*****************************************************************************/ + +fieldinfo *class_findfield (classinfo *c, unicode *name, unicode *desc) +{ + u4 i; + for (i=0; i < c->fieldscount; i++) { + if ( (c->fields[i].name == name) && (c->fields[i].descriptor == desc) ) + return &(c->fields[i]); + } + panic ("Can not find field given in CONSTANT_Fieldref"); + return NULL; +} + + +/************************* Funktion: class_findmethod ************************* + + sucht in einer 'classinfo'-Struktur nach einer Methode mit gew"unschtem + Namen und Typ. + Wenn als Typ NULL angegeben wird, dann ist der Typ egal. + +*****************************************************************************/ + +methodinfo *class_findmethod (classinfo *c, unicode *name, unicode *desc) +{ + u4 i; + for (i=0; i < c->methodscount; i++) { + if ( (c->methods[i].name == name) + && ( (desc == NULL) + || (c->methods[i].descriptor == desc) + ) + ) + return &(c->methods[i]); + } + return NULL; +} + + +/************************* Funktion: class_resolvemethod ************************* + + sucht eine Klasse und alle Superklassen ab, um eine Methode zu finden. + +*****************************************************************************/ + + +methodinfo *class_resolvemethod (classinfo *c, unicode *name, unicode *desc) +{ + while (c) { + methodinfo *m = class_findmethod (c, name, desc); + if (m) return m; + c = c->super; + } + return NULL; +} + + + +/************************* Funktion: class_issubclass ************************ + + "uberpr"uft, ob eine Klasse von einer anderen Klasse abgeleitet ist. + +*****************************************************************************/ + +bool class_issubclass (classinfo *sub, classinfo *super) +{ + for (;;) { + if (!sub) return false; + if (sub==super) return true; + sub = sub -> super; + } +} + + + +/****************** Initialisierungsfunktion f"ur eine Klasse **************** + + In Java kann jede Klasse ein statische Initialisierungsfunktion haben. + Diese Funktion mu"s aufgerufen werden, BEVOR irgendwelche Methoden der + Klasse aufgerufen werden, oder auf statische Variablen zugegriffen + wird. + +******************************************************************************/ + +#ifdef USE_THREADS +extern int blockInts; +#endif + +void class_init (classinfo *c) +{ + methodinfo *m; + java_objectheader *exceptionptr; + s4 i; + int b; + + if (!makeinitializations) return; + if (c->initialized) return; + c -> initialized = true; + + if (c->super) class_init (c->super); + for (i=0; i < c->interfacescount; i++) class_init(c->interfaces[i]); + + m = class_findmethod (c, + unicode_new_char (""), + unicode_new_char ("()V")); + if (!m) { + if (initverbose) { + sprintf (logtext, "Class "); + unicode_sprint (logtext+strlen(logtext), c->name); + sprintf (logtext+strlen(logtext), " has no initializer"); + dolog (); + } + return; + } + + if (! (m->flags & ACC_STATIC)) panic ("Class initializer is not static!"); + + if (initverbose) { + sprintf (logtext, "Starting initializer for class: "); + unicode_sprint (logtext+strlen(logtext), c->name); + dolog (); + } + +#ifdef USE_THREADS + b = blockInts; + blockInts = 0; +#endif + + exceptionptr = asm_calljavamethod (m, NULL,NULL,NULL,NULL); + +#ifdef USE_THREADS + assert(blockInts == 0); + blockInts = b; +#endif + + if (exceptionptr) { + printf ("#### Initializer has thrown: "); + unicode_display (exceptionptr->vftbl->class->name); + printf ("\n"); + fflush (stdout); + } + + if (initverbose) { + sprintf (logtext, "Finished initializer for class: "); + unicode_sprint (logtext+strlen(logtext), c->name); + dolog (); + } + +} + + + + +/********* Funktion: class_showconstantpool (nur f"ur Debug-Zwecke) ********/ + +void class_showconstantpool (classinfo *c) +{ + u4 i; + voidptr e; + + printf ("---- dump of constant pool ----\n"); + + for (i=0; icpcount; i++) { + printf ("#%d: ", (int) i); + + e = c -> cpinfos [i]; + if (e) { + + switch (c -> cptags [i]) { + case CONSTANT_Class: + printf ("Classreference -> "); + unicode_display ( ((classinfo*)e) -> name ); + break; + + case CONSTANT_Fieldref: + printf ("Fieldref -> "); goto displayFMI; + case CONSTANT_Methodref: + printf ("Methodref -> "); goto displayFMI; + case CONSTANT_InterfaceMethodref: + printf ("InterfaceMethod -> "); goto displayFMI; + displayFMI: + { + constant_FMIref *fmi = e; + unicode_display ( fmi->class->name ); + printf ("."); + unicode_display ( fmi->name); + printf (" "); + unicode_display ( fmi->descriptor ); + } + break; + + case CONSTANT_String: + printf ("String -> "); + unicode_display (e); + break; + case CONSTANT_Integer: + printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); + break; + case CONSTANT_Float: + printf ("Float -> %f", ((constant_float*)e) -> value); + break; + case CONSTANT_Double: + printf ("Double -> %f", ((constant_double*)e) -> value); + break; + case CONSTANT_Long: + { + u8 v = ((constant_long*)e) -> value; +#if U8_AVAILABLE + printf ("Long -> %ld", (long int) v); +#else + printf ("Long -> HI: %ld, LO: %ld\n", + (long int) v.high, (long int) v.low); +#endif + } + break; + case CONSTANT_NameAndType: + { constant_nameandtype *cnt = e; + printf ("NameAndType: "); + unicode_display (cnt->name); + printf (" "); + unicode_display (cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf ("Utf8 -> "); + unicode_display (e); + break; + case CONSTANT_Arraydescriptor: { + printf ("Arraydescriptor: "); + displayarraydescriptor (e); + } + break; + default: + panic ("Invalid type of ConstantPool-Entry"); + } + + } + + printf ("\n"); + } + +} + + + +/********** Funktion: class_showmethods (nur f"ur Debug-Zwecke) ************/ + +void class_showmethods (classinfo *c) +{ + u4 i; + + printf ("--------- Fields and Methods ----------------\n"); + printf ("Flags: "); printflags (c->flags); printf ("\n"); + + printf ("This: "); unicode_display (c->name); printf ("\n"); + if (c->super) { + printf ("Super: "); unicode_display (c->super->name); printf ("\n"); + } + printf ("Index: %d\n", c->index); + + printf ("interfaces:\n"); + for (i=0; i < c-> interfacescount; i++) { + printf (" "); + unicode_display (c -> interfaces[i] -> name); + printf (" (%d)\n", c->interfaces[i] -> index); + } + + printf ("fields:\n"); + for (i=0; i < c -> fieldscount; i++) { + field_display (&(c -> fields[i])); + } + + printf ("methods:\n"); + for (i=0; i < c -> methodscount; i++) { + methodinfo *m = &(c->methods[i]); + if ( !(m->flags & ACC_STATIC)) + printf ("vftblindex: %d ", m->vftblindex); + + method_display ( m ); + + } + + printf ("Virtual function table:\n"); + for (i=0; ivftbl->vftbllength; i++) { + printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]) ); + } + +} + + + +/*****************************************************************************/ +/******************* Funktionen fuer den Class-loader generell ***************/ +/*****************************************************************************/ + + +/********************* Funktion: loader_load ********************************** + + l"adt und linkt die ge"unschte Klasse und alle davon + referenzierten Klassen und Interfaces + Return: Einen Zeiger auf diese Klasse + +******************************************************************************/ + +classinfo *loader_load (unicode *topname) +{ + classinfo *top; + classinfo *c; + long int starttime=0,stoptime=0; + + intsDisable(); /* schani */ + + if (getloadingtime) starttime = getcputime(); + + + top = class_get (topname); + + while ( (c = list_first(&unloadedclasses)) ) { + class_load (c); + } + + while ( (c = list_first(&unlinkedclasses)) ) { + class_link (c); + } + + + synchronize_caches (); + + + + if (getloadingtime) { + stoptime = getcputime(); + loadingtime += (stoptime-starttime); + } + + intsRestore(); /* schani */ + + return top; +} + + +/******************* interne Funktion: loader_createarrayclass **************** + + Erzeugt (und linkt) eine Klasse f"ur die Arrays. + +******************************************************************************/ + +static classinfo *loader_createarrayclass () +{ + classinfo *c; + c = class_get ( unicode_new_char ("The_Array_Class") ); + + list_remove (&unloadedclasses, c); + list_addlast (&unlinkedclasses, c); + c -> super = class_java_lang_Object; + + class_link (c); + return c; +} + + + +/********************** Funktion: loader_init ********************************* + + Initialisiert alle Listen und l"adt alle Klassen, die vom System + und vom Compiler direkt ben"otigt werden. + +******************************************************************************/ + +void loader_init () +{ + interfaceindex = 0; + + list_init (&unloadedclasses, OFFSET(classinfo, listnode) ); + list_init (&unlinkedclasses, OFFSET(classinfo, listnode) ); + list_init (&linkedclasses, OFFSET(classinfo, listnode) ); + + + class_java_lang_Object = + loader_load ( unicode_new_char ("java/lang/Object") ); + class_java_lang_String = + loader_load ( unicode_new_char ("java/lang/String") ); + class_java_lang_ClassCastException = + loader_load ( unicode_new_char ("java/lang/ClassCastException") ); + class_java_lang_NullPointerException = + loader_load ( unicode_new_char ("java/lang/NullPointerException") ); + class_java_lang_ArrayIndexOutOfBoundsException = loader_load ( + unicode_new_char ("java/lang/ArrayIndexOutOfBoundsException") ); + class_java_lang_NegativeArraySizeException = loader_load ( + unicode_new_char ("java/lang/NegativeArraySizeException") ); + class_java_lang_OutOfMemoryError = loader_load ( + unicode_new_char ("java/lang/OutOfMemoryError") ); + class_java_lang_ArrayStoreException = + loader_load ( unicode_new_char ("java/lang/ArrayStoreException") ); + class_java_lang_ArithmeticException = + loader_load ( unicode_new_char ("java/lang/ArithmeticException") ); + class_java_lang_ThreadDeath = /* schani */ + loader_load ( unicode_new_char ("java/lang/ThreadDeath") ); + + class_array = loader_createarrayclass (); + + + proto_java_lang_ClassCastException = + builtin_new(class_java_lang_ClassCastException); + heap_addreference ( (void**) &proto_java_lang_ClassCastException); + + proto_java_lang_NullPointerException = + builtin_new(class_java_lang_NullPointerException); + heap_addreference ( (void**) &proto_java_lang_NullPointerException); + + proto_java_lang_ArrayIndexOutOfBoundsException = + builtin_new(class_java_lang_ArrayIndexOutOfBoundsException); + heap_addreference ( (void**) &proto_java_lang_ArrayIndexOutOfBoundsException); + + proto_java_lang_NegativeArraySizeException = + builtin_new(class_java_lang_NegativeArraySizeException); + heap_addreference ( (void**) &proto_java_lang_NegativeArraySizeException); + + proto_java_lang_OutOfMemoryError = + builtin_new(class_java_lang_OutOfMemoryError); + heap_addreference ( (void**) &proto_java_lang_OutOfMemoryError); + + proto_java_lang_ArithmeticException = + builtin_new(class_java_lang_ArithmeticException); + heap_addreference ( (void**) &proto_java_lang_ArithmeticException); + + proto_java_lang_ArrayStoreException = + builtin_new(class_java_lang_ArrayStoreException); + heap_addreference ( (void**) &proto_java_lang_ArrayStoreException); + + proto_java_lang_ThreadDeath = /* schani */ + builtin_new(class_java_lang_ThreadDeath); + heap_addreference ( (void**) &proto_java_lang_ThreadDeath); +} + + + + +/********************* Funktion: loader_initclasses **************************** + + initialisiert alle geladenen aber noch nicht initialisierten Klassen + +******************************************************************************/ + +void loader_initclasses () +{ + classinfo *c; + + intsDisable(); /* schani */ + + if (makeinitializations) { + c = list_first (&linkedclasses); + while (c) { + class_init (c); + c = list_next (&linkedclasses, c); + } + } + + intsRestore(); /* schani */ +} + + + +/******************** Funktion: loader_close ********************************** + + gibt alle Resourcen wieder frei + +******************************************************************************/ + +void loader_close () +{ + classinfo *c; + + while ( (c=list_first(&unloadedclasses)) ) { + list_remove (&unloadedclasses,c); + class_free (c); + } + while ( (c=list_first(&unlinkedclasses)) ) { + list_remove (&unlinkedclasses,c); + class_free (c); + } + while ( (c=list_first(&linkedclasses)) ) { + list_remove (&linkedclasses,c); + class_free (c); + } +} + diff --git a/src/vm/loader.h b/src/vm/loader.h new file mode 100644 index 000000000..190a6458a --- /dev/null +++ b/src/vm/loader.h @@ -0,0 +1,53 @@ +/******************************* loader.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the prototypes for the class loader. + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1997/11/14 + +*******************************************************************************/ + + +/************************* program switches ***********************************/ + +extern bool loadverbose; /* Debug-Meldungen beim Laden ausgeben */ +extern bool linkverbose; +extern bool initverbose; /* Meldungen ausgeben, wenn Klasse + initialisiert wird */ +extern bool makeinitializations; /* Klassen automatisch initialisieren */ + +extern bool getloadingtime; +extern long int loadingtime; /* CPU-Zeit f"urs Laden der Klassen */ + +extern list linkedclasses; /* Liste aller fertig gelinkten Klassen */ + + +/************************ prototypes ******************************************/ + +void loader_init (); +void loader_close (); + +classinfo *loader_load (unicode *topname); +void loader_initclasses (); + +classinfo *class_get (unicode *name); +voidptr class_getconstant (classinfo *class, u4 pos, u4 ctype); +u4 class_constanttype (classinfo *class, u4 pos); + +fieldinfo *class_findfield (classinfo *c, unicode *name, unicode *desc); +methodinfo *class_findmethod (classinfo *c, unicode *name, unicode *desc); + +methodinfo *class_resolvemethod (classinfo *c, unicode *name, unicode *dest); + +bool class_issubclass (classinfo *sub, classinfo *super); + +void class_init (classinfo *c); + +void class_showmethods (classinfo *c); +void class_showconstantpool (classinfo *c); + diff --git a/src/vm/tables.c b/src/vm/tables.c new file mode 100644 index 000000000..fd979fd6d --- /dev/null +++ b/src/vm/tables.c @@ -0,0 +1,1558 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** tables.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt Supportfunktionen f"ur: + - Lesen von JavaClass-Files + - unicode-Symbole + - den Heap + - zus"atzliche Support-Funktionen + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/03/24 + +*******************************************************************************/ + +#include +#include +#include +#include "global.h" +#include "tables.h" +#include "asmpart.h" +#include "callargs.h" + +#include "threads/thread.h" /* schani */ +#include "threads/locks.h" + + +bool runverbose = false; + +int count_unicode_len = 0; + + +/****************************************************************************** +************************* Der Dateien-Sauger ********************************** +******************************************************************************* + + dient zum Behandeln von Java-ClassFiles ("offnen, schlie"sen, + einlesen von 8-, 16-, 32-, 64-bit Integers und 32-, 64- bit Floats) + +******************************************************************************/ + +static FILE *classfile = NULL; /* File-handle der gerade gelesenen Datei */ +static char *classpath = ""; /* Suchpfad f"ur die ClassFiles */ + + + +/************************** Funktion: suck_init ****************************** + + Wird zu Programmstart einmal aufgerufen und setzt den Suchpfad f"ur + Klassenfiles + +******************************************************************************/ + +void suck_init (char *cpath) +{ + classfile = NULL; + classpath = cpath; +} + + +/************************** Funktion: suck_start ****************************** + + "Offnet die Datei f"ur die Klasse des gegebenen Namens zum Lesen. + Dabei werden alle im Suchpfad angegebenen Verzeichnisse durchsucht, + bis eine entsprechende Datei ( .class) gefunden wird. + +******************************************************************************/ + +bool suck_start (unicode *classname) +{ +#define MAXFILENAME 1000 /* Maximale Langes des Dateinamens plus Pfad */ + + char filename[MAXFILENAME+10]; /* Platz fuer '.class' */ + u2 filenamelen; + char *pathpos; + u2 i,c; + + + pathpos = classpath; + + while (*pathpos) { + while ( *pathpos == ':' ) pathpos++; + + filenamelen=0; + while ( (*pathpos) && (*pathpos!=':') ) { + PANICIF (filenamelen >= MAXFILENAME, "Filename too long") ; + + filename[filenamelen++] = *(pathpos++); + } + + filename[filenamelen++] = '/'; + + for (i=0; i < classname -> length; i++) { + PANICIF (filenamelen >= MAXFILENAME, "Filename too long"); + + c = classname -> text [i]; + if (c=='/') c = '/'; /* Slashes im Namen passen zu UNIX */ + else { + if ( c<=' ' || c>'z') { + c = '?'; + } + } + + filename[filenamelen++] = c; + } + + strcpy (filename+filenamelen, ".class"); + + classfile = fopen(filename, "r"); + if (classfile) { + return true; + } + + + } + + sprintf (logtext,"Can not open class file '%s'", filename); + error(); + return false; +} + + +/************************** Funktion: suck_stop ******************************* + + Schlie"st die offene Datei wieder. + +******************************************************************************/ + +void suck_stop () +{ + u4 rest=0; + u1 dummy; + + while ( fread (&dummy, 1,1, classfile) > 0) rest++; + if (rest) { + sprintf (logtext,"There are %d access bytes at end of classfile", + (int) rest); + dolog(); + } + + fclose (classfile); + classfile = NULL; +} + + + +/************************** Lesefunktionen *********************************** + + Lesen von der Datei in verschieden grossen Paketen + (8,16,32,64-bit Integer oder Float) + +*****************************************************************************/ + +void suck_nbytes (u1 *buffer, u4 len) +{ + if ( fread (buffer, 1, len, classfile) != len) panic ("Unexpected EOF"); +} + + +void skip_nbytes (u4 len) +{ + u4 i; + for (i=0; ihashlink; + + if (u->string) del (u->string); + + MFREE (u->text, u2, u->length); + FREE (u, unicode); + u = nextu; + } + } + MFREE (unicodehash, unicode*, unicodehashsize); +} + + +/********************* Funktion: unicode_display ****************************** + + Gibt ein unicode-Symbol auf stdout aus (zu Debugzwecken) + +******************************************************************************/ + +void unicode_display (unicode *u) +{ + u2 i,c; + for (i=0; i < u->length; i++) { + c = u->text[i]; + if (c>=32 && c<=127) printf ("%c",c); + else printf ("?"); + } + fflush (stdout); +} + + +/********************* Funktion: unicode_sprint ****************************** + + Schreibt ein unicode-Symbol in einen C-String + +******************************************************************************/ + +void unicode_sprint (char *buffer, unicode *u) +{ + u2 i; + for (i=0; i < u->length; i++) buffer[i] = u->text[i]; + buffer[i] = '\0'; +} + + +/********************* Funktion: unicode_fprint ****************************** + + Schreibt ein unicode-Symbol auf eine Datei aus + +******************************************************************************/ + +void unicode_fprint (FILE *file, unicode *u) +{ + u2 i; + for (i=0; i < u->length; i++) putc (u->text[i], file); +} + + +/****************** interne Funktion: u_hashkey ******************************/ + +static u4 u_hashkey (u2 *text, u2 length) +{ + u4 k = 0; + u2 i,sh=0; + + for (i=0; i hashlink; + u4 slot = (u->key) % newhashsize; + + u->hashlink = newhash[slot]; + newhash[slot] = u; + + u = nextu; + } + } + + MFREE (unicodehash, unicode*, unicodehashsize); + unicodehash = newhash; + unicodehashsize = newhashsize; +} + + +/****************** Funktion: unicode_new_u2 ********************************** + + Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser + Funktion als u2-Array "ubergeben + +******************************************************************************/ + +unicode *unicode_new_u2 (u2 *text, u2 length) +{ + u4 key = u_hashkey (text, length); + u4 slot = key % unicodehashsize; + unicode *u = unicodehash[slot]; + u2 i; + + while (u) { + if (u->key == key) { + if (u->length == length) { + for (i=0; itext[i]) goto nomatch; + } + return u; + } + } + nomatch: + u = u->hashlink; + } + +#ifdef STATISTICS + count_unicode_len += sizeof(unicode) + 2 * length; +#endif + + u = NEW (unicode); + u->key = key; + u->length = length; + u->text = MNEW (u2, length); + u->class = NULL; + u->string = NULL; + u->hashlink = unicodehash[slot]; + unicodehash[slot] = u; + for (i=0; itext[i] = text[i]; + + unicodeentries++; + + if ( unicodeentries > (unicodehashsize/2)) u_reorganizehash(); + + return u; +} + + +/********************* Funktion: unicode_new_char ***************************** + + Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser + Funktion als C-String ( = char* ) "ubergeben + +******************************************************************************/ + +unicode *unicode_new_char (char *text) +{ +#define MAXNEWCHAR 500 + u2 buffer[MAXNEWCHAR]; + u2 length = 0; + u1 c; + + while ( (c = *text) != '\0' ) { + if (length>=MAXNEWCHAR) panic ("Text too long in unicode_new_char"); + buffer[length++] = c; + text ++; + } + return unicode_new_u2 (buffer, length); +} + + +/********************** Funktion: unicode_setclasslink ************************ + + H"angt einen Verweis auf eine Klasse an ein unicode-Symbol an. + +******************************************************************************/ + +void unicode_setclasslink (unicode *u, classinfo *class) +{ + PANICIF (u->class, "Attempt to attach class to already attached symbol"); + u->class = class; +} + +/********************** Funktion: unicode_getclasslink ************************ + + Sucht den Verweis von einem unicode-Symbol auf eine Klasse. + Wenn keine solche Klasse existiert, dann wird ein Fehler + ausgegeben. + +******************************************************************************/ + +classinfo *unicode_getclasslink (unicode *u) +{ + PANICIF (!u->class, "Attempt to get unknown class-reference"); + return u->class; +} + + + +/********************* Funktion: unicode_unlinkclass ************************* + + Entfernt den Verweis auf eine Klasse wieder von einem Symbol + +******************************************************************************/ + +void unicode_unlinkclass (unicode *u) +{ + PANICIF (!u->class, "Attempt to unlink not yet linked symbol"); + u -> class = NULL; +} + + + +/******************* Funktion> unicode_setstringlink ********************* + + H"angt einen Verweis auf einen konstanten String an ein + Unicode-Symbol + +*************************************************************************/ + +void unicode_setstringlink (unicode *u, java_objectheader *str) +{ + PANICIF (u->string, "Attempt to attach string to already attached symbol"); + u->string = str; +} + + +/********************* Funktion: unicode_unlinkstring ************************* + + Entfernt den Verweis auf einen String wieder von einem Symbol + +******************************************************************************/ + +void unicode_unlinkstring (unicode *u) +{ + PANICIF (!u->class, "Attempt to unlink not yet linked symbol"); + u -> string = NULL; +} + + + +/*********************** Funktion: unicode_show ****************************** + + gibt eine Aufstellung aller Symbol im unicode-hash auf stdout aus. + (nur f"ur Debug-Zwecke) + +*****************************************************************************/ + +void unicode_show () +{ + unicode *u; + u4 i; + + printf ("UNICODE-HASH: %d slots for %d entries\n", + (int) unicodehashsize, (int) unicodeentries ); + + for (i=0; istring) printf ("(string) "); + u = u->hashlink; + } + printf ("\n"); + } + + } +} + + + +/****************************************************************************** +*********************** Diverse Support-Funktionen **************************** +******************************************************************************/ + + +/******************** Funktion: desc_to_type ********************************** + + Findet zu einem gegebenen Typdescriptor den entsprechenden + Java-Grunddatentyp. + +******************************************************************************/ + +u2 desc_to_type (unicode *descriptor) +{ + if (descriptor->length < 1) panic ("Type-Descriptor is empty string"); + + switch (descriptor->text[0]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': return TYPE_INT; + case 'D': return TYPE_DOUBLE; + case 'F': return TYPE_FLOAT; + case 'J': return TYPE_LONG; + case 'L': + case '[': return TYPE_ADDRESS; + } + + sprintf (logtext, "Invalid Type-Descriptor: "); + unicode_sprint (logtext+strlen(logtext), descriptor); + error (); + return 0; +} + + +/********************** Funktion: desc_typesize ******************************* + + Berechnet die L"ange (in Byte) eines Datenelements gegebenen Typs, + der durch den Typdescriptor gegeben ist. + +******************************************************************************/ + +u2 desc_typesize (unicode *descriptor) +{ + switch (desc_to_type(descriptor)) { + case TYPE_INT: return 4; + case TYPE_LONG: return 8; + case TYPE_FLOAT: return 4; + case TYPE_DOUBLE: return 8; + case TYPE_ADDRESS: return sizeof(voidptr); + default: return 0; + } +} + + + + + +/****************************************************************************** +********************* Der garbage-collected Heap ****************************** +******************************************************************************* + + verwaltet einen Heap mit automatischer Speicherfreigabe. + + (eine ausf"uhrliche Dokumentation findet sich in der Datei: + collect.doc) + +******************************************************************************/ + + +bool collectverbose = false; /* soll Meldung beim GC ausgegeben werden? */ + + +#define BLOCKSIZE 8 /* Gr"osse eines Speicherblockes */ +typedef u8 heapblock; /* Datentyp mit der Gr"osse eines Speicherblocks */ + +#if U8_AVAILABLE && SUPPORT_LONG +#define bitfieldtype u8 +#define BITFIELDBITS 64 +#else +#define bitfieldtype u4 +#define BITFIELDBITS 32 +#endif + +u4 heapsize; /* Gr"osse des Heap in Blocks */ +u4 topofheap; /* Bisherige Obergrenze Heaps */ +heapblock *heap; /* Speicher f"ur den Heap selbst */ + +bitfieldtype *startbits; /* Bitfeld f"ur Bereichsstartkennung */ +bitfieldtype *markbits; /* Bitfeld f"ur Markierung */ +bitfieldtype *referencebits; /* Bitfeld f"ur Folgereferenzenkennung */ + +u4 heapfillgrade; /* Menge der Daten im Heap */ +u4 collectthreashold; /* Schwellwert f"ur n"achstes GC */ + +void **bottom_of_stack; /* Zeiger auf Untergrenze des C-Stacks */ +chain *allglobalreferences; /* Liste f"ur alle globalen Zeiger */ + +typedef struct finalizernode { + struct finalizernode *next; + u4 objstart; + methodinfo *finalizer; + } finalizernode; + +finalizernode *livefinalizees; +finalizernode *deadfinalizees; + + +typedef struct memarea { /* Datenstruktur f"ur einen Freispeicherbereich */ + struct memarea *next; + } memarea; + +typedef struct bigmemarea { /* Datenstruktur f"ur einen */ + struct bigmemarea *next; /* Freispeicherbereich variabler L"ange */ + u4 size; + } bigmemarea; + +#define DIFFERENTSIZES 128 /* Anzahl der 'kleinen' Freispeicherlisten */ +memarea *memlist[DIFFERENTSIZES]; /* Die 'kleinen' Freispeicherlisten */ +bitfieldtype memlistbits[DIFFERENTSIZES/BITFIELDBITS]; + /* Bitfeld, in dem jeweils ein Bit gesetzt */ + /* ist, wenn eine Liste noch etwas enth"alt */ + +bigmemarea *bigmemlist; /* Liste der gr"osseren Freispeicherbereiche */ + + + + +/**************** Hilfsfunktion: lowest ************************************** + +liefert als Ergebnis die Nummer des niederwertigsten Bits einer +Zahl vom Typ bitfieldtype, das 1 ist. +Wenn die ganze Zahl keine 1en enth"alt, dann ist egal, was f"ur einen +Wert die Funktion l"iefert. +z.B.: lowest(1) = 0, lowest(12) = 2, lowest(1024) = 10 + +*****************************************************************************/ + +static u1 lowesttable[256] = { + 255, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; + +static int lowest(bitfieldtype i) +{ +#if BITFIELDBITS==64 + u8 i1 = i<<32; + if (i1) { + u8 i11 = i1<<16; + if (i11) { + u8 i111 = i11<<8; + if (i111) return lowesttable[i111>>56]; + else return 8+lowesttable[i11>>56]; + } + else { + u8 i112 = i1<<8; + if (i112) return 16+lowesttable[i112>>56]; + else return 24+lowesttable[i1>>56]; + } + } + else { + u8 i12 = i<<16; + if (i12) { + u8 i121 = i12<<8; + if (i121) return 32+lowesttable[i121>>56]; + else return 40+lowesttable[i12>>56]; + } + else { + u8 i122 = i<<8; + if (i122) return 48+lowesttable[i122>>56]; + else return 56+lowesttable[i>>56]; + } + } +#else + u4 i1 = i<<16; + if (i1) { + u4 i11 = i1<<8; + if (i11) return lowesttable[i11>>24]; + else return 8+lowesttable[i1>>24]; + } + else { + u4 i12 = i<<8; + if (i12) return 16+lowesttable[i12>>24]; + else return 24+lowesttable[i>>24]; + } +#endif +} + + +/******** Funktionen zum Setzen und L"oschen von Bits in Bitfeldern ***********/ + +static void setbit(bitfieldtype *bitfield, u4 bitnumber) +{ + bitfield[bitnumber/BITFIELDBITS] |= + ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS); +} + +static void clearbit(bitfieldtype *bitfield, u4 bitnumber) +{ + bitfield[bitnumber/BITFIELDBITS] &= + ~((bitfieldtype) 1) << (bitnumber%BITFIELDBITS); +} + +static bool isbitset(bitfieldtype *bitfield, u4 bitnumber) +{ + return ( bitfield[bitnumber/BITFIELDBITS] & + ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) != 0; +} + +static bool isbitclear(bitfieldtype *bitfield, u4 bitnumber) +{ + return ( bitfield[bitnumber/BITFIELDBITS] & + ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) == 0; +} + + +/***************** Funktion: clearbitfield ************************************ + + l"oscht ein ganzes Bitfeld + +******************************************************************************/ + +static void clearbitfield(bitfieldtype *bitfield, u4 fieldsize) +{ + u4 i,t; + t = ALIGN(fieldsize, BITFIELDBITS) / BITFIELDBITS; + for (i=0; i= fieldsize) return fieldsize; + + pattern = bitfield[bitnumber/BITFIELDBITS]; + pattern >>= (bitnumber%BITFIELDBITS); + if (pattern) return bitnumber + lowest(pattern); + + bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS; + } +} + + +/************ Funktion: findnextcombination_set_unset ************************* + + funktioniert wie findnextsetbit, allerdings sucht diese Funktion + nach einer Stelle, an der gleichzeitig ein Bit im ersten + Bitfeld gesetzt ist und im zweiten Bitfeld das entsprechende + Bit nicht gesetzt ist. + +******************************************************************************/ + +static u4 findnextcombination_set_unset + (bitfieldtype *bitfield1, bitfieldtype* bitfield2, u4 fieldsize, u4 bitnumber) +{ + bitfieldtype pattern; + + for (;;) { + if (bitnumber >= fieldsize) return fieldsize; + + pattern = bitfield1[bitnumber/BITFIELDBITS] + & (~bitfield2[bitnumber/BITFIELDBITS]); + pattern >>= (bitnumber%BITFIELDBITS); + if (pattern) return bitnumber + lowest(pattern); + + bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS; + } +} + + + +/************** Funktion: memlist_init **************************************** + + initialisiert die Freispeicherlisten (zum nachfolgenden Eintragen + mit memlist_addrange). + +******************************************************************************/ + +static void memlist_init () +{ + u4 i; + for (i=0; i=DIFFERENTSIZES) { + bigmemarea *m = (bigmemarea*) (heap+freestart); + m -> next = bigmemlist; + m -> size = freesize; + bigmemlist = m; + } + else { + if (freesize*BLOCKSIZE>=sizeof(memarea)) { + memarea *m = (memarea*) (heap+freestart); + m -> next = memlist[freesize]; + memlist[freesize] = m; + setbit (memlistbits, freesize); + } + } +} + + +/************** Funktion: memlist_getsuitable ********************************* + + sucht in der Freispeicherliste einen Speicherbereich, der m"oglichst + genau die gew"unschte L"ange hat. + Der Bereich wird dabei auf jeden Fall aus der Liste ausgetragen. + (Wenn der Bereich zu lang sein sollte, dann kann der Aufrufer den + Rest wieder mit 'memlist_addrange' in die Liste einh"angen) + + Return (in Referenzparametern): + *freestart: Anfang des freien Speichers + *freelength: L"ange dieses Speicherbereiches + + Wenn kein passender Speicherblock mehr gefunden werden kann, dann + wird in '*freelength' 0 hineingeschrieben. + +******************************************************************************/ + +static void memlist_getsuitable (u4 *freestart, u4 *freelength, u4 length) +{ + bigmemarea *m; + bigmemarea *prevm = NULL; + + if (lengthnext; + if (!m->next) clearbit (memlistbits, firstfreelength); + *freestart = ((heapblock*) m) - heap; + *freelength = firstfreelength; + return; + } + } + + m = bigmemlist; + while (m) { + if (m->size >= length) { + if (prevm) prevm->next = m->next; + else bigmemlist = m->next; + + *freestart = ((heapblock*) m) - heap; + *freelength = m->size; + return ; + } + + prevm = m; + m = m->next; + } + + *freelength=0; +} + + + + + +/******************* Funktion: mark ******************************************* + + Markiert ein m"oglicherweise g"ultiges Objekt. + Sollte sich herausstellen, dass der Zeiger gar nicht auf ein Objekt + am Heap zeigt, dann wird eben gar nichts markiert. + +******************************************************************************/ + +static void markreferences (void **rstart, void **rend); + +static void mark (heapblock *obj) +{ + u4 blocknum,objectend; + + if ((long) obj & (BLOCKSIZE-1)) return; + + if (obj=(heap+topofheap) ) return; + + blocknum = obj-heap; + if ( isbitclear(startbits, blocknum) ) return; + if ( isbitset(markbits, blocknum) ) return; + + setbit (markbits, blocknum); + + if ( isbitclear(referencebits, blocknum) ) return; + + objectend = findnextsetbit (startbits, topofheap, blocknum+1); + markreferences ((void**)obj, (void**) (heap+objectend) ); +} + + +/******************** Funktion: markreferences ******************************** + + Geht einen Speicherbereich durch, und markiert alle Objekte, auf + die von diesem Bereich aus irgendeine Referenz existiert. + +******************************************************************************/ + +static void markreferences (void **rstart, void **rend) +{ + void **ptr; + + for (ptr=rstart; ptr (void**)CONTEXT(aThread).stackEnd) + markreferences ((void**)CONTEXT(aThread).stackEnd, top_of_stack); + else + markreferences (top_of_stack, (void**)CONTEXT(aThread).stackEnd); + } + else { + if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd) + markreferences ((void**)CONTEXT(aThread).stackEnd, + (void**)CONTEXT(aThread).usedStackTop + 16); + else + markreferences ((void**)CONTEXT(aThread).usedStackTop - 16, + (void**)CONTEXT(aThread).stackEnd); + } + } + + markreferences((void**)&threadQhead[0], (void**)&threadQhead[MAX_THREAD_PRIO]); +#else + if (top_of_stack > bottom_of_stack) + markreferences(bottom_of_stack, top_of_stack); + else + markreferences(top_of_stack, bottom_of_stack); +#endif +} + + + +/**************** Funktion: searchlivefinalizees ***************************** + + geht die Liste aller Objekte durch, die noch finalisiert werden m"ussen + (livefinalizees), und tr"agt alle nicht mehr markierten in die + Liste deadfinalizess ein (allerdings werden sie vorher noch als + erreicht markiert, damit sie nicht jetzt gleich gel"oscht werden). + +*****************************************************************************/ + +static void searchlivefinalizees () +{ + finalizernode *fn = livefinalizees; + finalizernode *lastlive = NULL; + + while (fn) { + + /* alle zu finalisierenden Objekte, die nicht mehr markiert sind: */ + if (isbitclear (markbits, fn->objstart)) { + finalizernode *nextfn = fn->next; + + mark (heap + fn->objstart); + + if (lastlive) lastlive -> next = nextfn; + else livefinalizees = nextfn; + + fn -> next = deadfinalizees; + deadfinalizees = fn; + + fn = nextfn; + } + else { + lastlive = fn; + fn = fn->next; + } + } +} + + + +/********************** Funktion: finalizedead ******************************* + + ruft die 'finalize'-Methode aller Objekte in der 'deadfinalizees'- + Liste auf. + Achtung: Es kann hier eventuell zu neuerlichen Speicheranforderungen + (mit potentiell notwendigem GC) kommen, deshalb m"ussen manche + globalen Variablen in lokale Variblen kopiert werden + (Reentrant-F"ahigkeit!!!) + +******************************************************************************/ + +static void finalizedead() +{ + finalizernode *fn = deadfinalizees; + deadfinalizees = NULL; + + while (fn) { + finalizernode *nextfn = fn->next; + + asm_calljavamethod (fn->finalizer, heap+fn->objstart, NULL,NULL,NULL); + FREE (fn, finalizernode); + + fn = nextfn; + } + +} + + + +/****************** Funktion: heap_docollect ********************************** + + F"uhrt eine vollst"andige Garbage Collection durch + +******************************************************************************/ + +static void heap_docollect () +{ + u4 freestart,freeend; + void **p; + bitfieldtype *dummy; + u4 heapfreemem; + u4 oldfillgrade; + + + if (runverbose) { + fprintf(stderr, "doing garbage collection\n"); + } + /* alle Markierungsbits l"oschen */ + clearbitfield (markbits, topofheap); + + /* Alle vom Stack referenzierten Objekte markieren */ + asm_dumpregistersandcall (markstack); + + /* Alle von globalen Variablen erreichbaren Objekte markieren */ + p = chain_first (allglobalreferences); + while (p) { + mark (*p); + p = chain_next (allglobalreferences); + } + + /* alle Objekte durchsehen, die eine finalizer-Methode haben */ + searchlivefinalizees(); + + /* alle Reference-Bits l"oschen, deren Objekte nicht */ + /* mehr erreichbar sind */ + maskfieldwithfield (referencebits, markbits, topofheap); + + + /* Freispeicherliste initialisieren */ + memlist_init (); + + + /* Heap schrittweise durchgehen, und alle freien Bl"ocke merken */ + + heapfreemem = 0; + freeend=0; + for (;;) { + /* Anfang des n"achsten freien Bereiches suchen */ + freestart = findnextcombination_set_unset + (startbits, markbits, topofheap, freeend); + + /* Wenn es keinen freien Bereich mehr gibt -> fertig */ + if (freestart>=topofheap) goto freememfinished; + + /* Anfang des freien Bereiches markieren */ + setbit (markbits, freestart); + + /* Ende des freien Bereiches suchen */ + freeend = findnextsetbit (markbits, topofheap, freestart+1); + + /* Freien Bereich in Freispeicherliste einh"angen */ + memlist_addrange (freestart, freeend-freestart); + + /* Menge des freien Speichers mitnotieren */ + heapfreemem += (freeend-freestart); + } + + freememfinished: + + /* Die Rollen von markbits und startbits vertauschen */ + dummy = markbits; + markbits = startbits; + startbits = dummy; + + + /* Threashold-Wert f"ur n"achstes Collect */ + oldfillgrade = heapfillgrade; + heapfillgrade = topofheap - heapfreemem; + collectthreashold = heapfillgrade*3; /* eine nette Heuristik */ + + /* Eventuell eine Meldung ausgeben */ + if (collectverbose) { + sprintf (logtext, "Garbage Collection: previous/now = %d / %d ", + (int) (oldfillgrade * BLOCKSIZE), + (int) (heapfillgrade * BLOCKSIZE) ); + dolog (); + } + + + + /* alle gerade unerreichbar gewordenen Objekte mit + finalize-Methoden jetzt finalisieren. + Achtung: Diese Funktion kann zu neuerlichem GC f"uhren!! */ + finalizedead (); + +} + +/************************* Function: gc_init ********************************** + + Initializes the garbage collection thread mechanism. + +******************************************************************************/ + +#ifdef USE_THREADS +iMux gcStartMutex; +iMux gcThreadMutex; +iCv gcConditionStart; +iCv gcConditionDone; + +void +gc_init (void) +{ + gcStartMutex.holder = 0; + gcStartMutex.count = 0; + gcStartMutex.muxWaiters = 0; + + gcThreadMutex.holder = 0; + gcThreadMutex.count = 0; + gcThreadMutex.muxWaiters = 0; + + gcConditionStart.cvWaiters = 0; + gcConditionStart.mux = 0; + + gcConditionDone.cvWaiters = 0; + gcConditionDone.mux = 0; +} +#else +void +gc_init (void) +{ +} +#endif + +/************************* Function: gc_thread ******************************** + + In an endless loop waits for a condition to be posted, then + garbage collects the heap. + +******************************************************************************/ + +#ifdef USE_THREADS +void +gc_thread (void) +{ + intsRestore(); /* all threads start with interrupts disabled */ + + assert(blockInts == 0); + + lock_mutex(&gcThreadMutex); + + for (;;) + { + wait_cond(&gcThreadMutex, &gcConditionStart, 0); + + intsDisable(); + heap_docollect(); + intsRestore(); + + signal_cond(&gcConditionDone); + } +} +#endif + +void +gc_call (void) +{ +#ifdef USE_THREADS + lock_mutex(&gcThreadMutex); + + signal_cond(&gcConditionStart); + wait_cond(&gcThreadMutex, &gcConditionDone, 0); + + unlock_mutex(&gcThreadMutex); +#else + heap_docollect(); +#endif +} + + +/************************* Funktion: heap_init ******************************** + + Initialisiert den Garbage Collector. + Parameter: + heapbytesize: Maximale Gr"osse des Heap (in Bytes) + heapbytestartsize: Gr"osse des Heaps, bei dem zum ersten mal eine + GC durchgef"uhrt werden soll. + stackbottom: Ein Zeiger auf die Untergrenze des Stacks, im dem + Referenzen auf Objekte stehen k"onnen. + +******************************************************************************/ + +void heap_init (u4 heapbytesize, u4 heapbytestartsize, void **stackbottom) +{ + +#ifdef TRACECALLARGS + + heapsize = ALIGN (heapbytesize, getpagesize()); + heapsize = heapsize/BLOCKSIZE; + heap = (void*) mmap ((void*) 0x10000000, (size_t) (heapsize * BLOCKSIZE), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, (off_t) 0); + if (heap != (void *) 0x10000000) { + perror("mmap"); + printf("address = %p\n", heap); + panic("mmap failed\n"); + } + +#else + + heapsize = ALIGN (heapbytesize, 1024); + heapsize = heapsize/BLOCKSIZE; + heap = MNEW (heapblock, heapsize); + +#endif + + topofheap = 0; + startbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + markbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + referencebits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + clearbitfield (startbits, heapsize); + clearbitfield (markbits, heapsize); + clearbitfield (referencebits, heapsize); + + heapfillgrade = 0; + collectthreashold = heapbytestartsize/BLOCKSIZE; + allglobalreferences = chain_new (); + bottom_of_stack = stackbottom; + + livefinalizees = NULL; + deadfinalizees = NULL; +} + + +/****************** Funktion: heap_close ************************************** + + Gibt allen ben"otigten Speicher frei + +******************************************************************************/ + +void heap_close () +{ +#ifndef TRACECALLARGS + MFREE (heap, heapblock, heapsize); */ +#endif + MFREE (startbits, bitfieldtype, heapsize/BITFIELDBITS); + MFREE (markbits, bitfieldtype, heapsize/BITFIELDBITS); + MFREE (referencebits, bitfieldtype, heapsize/BITFIELDBITS); + chain_free (allglobalreferences); + + while (livefinalizees) { + finalizernode *n = livefinalizees->next; + FREE (livefinalizees, finalizernode); + livefinalizees = n; + } +} + + +/***************** Funktion: heap_addreference ******************************** + + Teilt dem GC eine Speicherstelle mit, an der eine globale Referenz + auf Objekte gespeichert sein kann. + +******************************************************************************/ + +void heap_addreference (void **reflocation) +{ + intsDisable(); /* schani */ + + chain_addlast (allglobalreferences, reflocation); + + intsRestore(); /* schani */ +} + + + +/***************** Funktion: heap_allocate ************************************ + + Fordert einen Speicher vom Heap an, der eine gew"unschte Gr"osse + (in Byte angegeben) haben muss. + Wenn kein Speicher mehr vorhanden ist (auch nicht nach einem + Garbage Collection-Durchlauf), dann wird NULL zur"uckgegeben. + Zus"atzlich wird durch den Parameter 'references' angegeben, ob + in das angelegte Objekt Referenzen auf andere Objekte eingetragen + werden k"onnten. + (Wichtig wegen Beschleunigung des Mark&Sweep-Durchlauf) + Im Zweifelsfalle immer references=true verwenden. + +******************************************************************************/ + +void *heap_allocate (u4 bytelength, bool references, methodinfo *finalizer) +{ + u4 freestart,freelength; + u4 length = ALIGN(bytelength, BLOCKSIZE) / BLOCKSIZE; + + intsDisable(); /* schani */ + + memlist_getsuitable (&freestart, &freelength, length); + +onemoretry: + if (!freelength) { + if ( (topofheap+length > collectthreashold) + || (topofheap+length > heapsize) ) { + + intsRestore(); + gc_call(); + intsDisable(); + + memlist_getsuitable (&freestart, &freelength, length); + if (freelength) goto onemoretry; + } + + if (topofheap+length > heapsize) { + sprintf (logtext, "Heap-Allocation failed for %d bytes", + (int) bytelength); + dolog(); + intsRestore(); /* schani */ + return NULL; + } + + freestart = topofheap; + freelength = length; + setbit (startbits, topofheap); + topofheap += length; + } + else { + if (freelength>length) { + setbit (startbits, freestart+length); + memlist_addrange (freestart+length, freelength-length); + } + } + + if (references) setbit (referencebits, freestart); + + heapfillgrade += length; + + if (finalizer) { + finalizernode *n = NEW(finalizernode); + n -> next = livefinalizees; + n -> objstart = freestart; + n -> finalizer = finalizer; + livefinalizees = n; + } + + intsRestore(); /* schani */ + + if (runverbose) { + sprintf (logtext, "new returns: %lx", (long) (heap + freestart)); + dolog (); + } + + return (void*) (heap + freestart); +} + + + + diff --git a/src/vm/tables.h b/src/vm/tables.h new file mode 100644 index 000000000..80f789328 --- /dev/null +++ b/src/vm/tables.h @@ -0,0 +1,63 @@ +/****************************** tables.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/20 + +*******************************************************************************/ + +extern bool collectverbose; + + +#define CLASS(name) (unicode_getclasslink(unicode_new_char(name))) + +typedef void (*stringdeleter) ( java_objectheader *string ); + + +void suck_init (char *classpath); +bool suck_start (unicode *name); +void suck_stop (); +void suck_nbytes (u1 *buffer, u4 len); +void skip_nbytes (u4 len); +u1 suck_u1 (); +s1 suck_s1 (); +u2 suck_u2 (); +s2 suck_s2 (); +u4 suck_u4 (); +s4 suck_s4 (); +u8 suck_u8 (); +s8 suck_s8 (); +float suck_float (); +double suck_double (); + + +void unicode_init (); +void unicode_close (stringdeleter del); +void unicode_display (unicode *u); +void unicode_sprint (char *buffer, unicode *u); +void unicode_fprint (FILE *file, unicode *u); +unicode *unicode_new_u2 (u2 *text, u2 length); +unicode *unicode_new_char (char *text); +void unicode_setclasslink (unicode *u, classinfo *class); +classinfo *unicode_getclasslink (unicode *u); +void unicode_unlinkclass (unicode *u); +void unicode_setstringlink (unicode *u, java_objectheader *str); +void unicode_unlinkstring (unicode *u); +void unicode_show (); + +u2 desc_to_type (unicode *descriptor); +u2 desc_typesize (unicode *descriptor); + + +void heap_init (u4 size, u4 startsize, void **stackbottom); +void heap_close (); +void *heap_allocate (u4 bytelength, bool references, methodinfo *finalizer); +void heap_addreference (void **reflocation); + +void gc_init (void); +void gc_thread (void); +void gc_call (void); diff --git a/tables.c b/tables.c new file mode 100644 index 000000000..fd979fd6d --- /dev/null +++ b/tables.c @@ -0,0 +1,1558 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/****************************** tables.c *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Enth"alt Supportfunktionen f"ur: + - Lesen von JavaClass-Files + - unicode-Symbole + - den Heap + - zus"atzliche Support-Funktionen + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at + Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/03/24 + +*******************************************************************************/ + +#include +#include +#include +#include "global.h" +#include "tables.h" +#include "asmpart.h" +#include "callargs.h" + +#include "threads/thread.h" /* schani */ +#include "threads/locks.h" + + +bool runverbose = false; + +int count_unicode_len = 0; + + +/****************************************************************************** +************************* Der Dateien-Sauger ********************************** +******************************************************************************* + + dient zum Behandeln von Java-ClassFiles ("offnen, schlie"sen, + einlesen von 8-, 16-, 32-, 64-bit Integers und 32-, 64- bit Floats) + +******************************************************************************/ + +static FILE *classfile = NULL; /* File-handle der gerade gelesenen Datei */ +static char *classpath = ""; /* Suchpfad f"ur die ClassFiles */ + + + +/************************** Funktion: suck_init ****************************** + + Wird zu Programmstart einmal aufgerufen und setzt den Suchpfad f"ur + Klassenfiles + +******************************************************************************/ + +void suck_init (char *cpath) +{ + classfile = NULL; + classpath = cpath; +} + + +/************************** Funktion: suck_start ****************************** + + "Offnet die Datei f"ur die Klasse des gegebenen Namens zum Lesen. + Dabei werden alle im Suchpfad angegebenen Verzeichnisse durchsucht, + bis eine entsprechende Datei ( .class) gefunden wird. + +******************************************************************************/ + +bool suck_start (unicode *classname) +{ +#define MAXFILENAME 1000 /* Maximale Langes des Dateinamens plus Pfad */ + + char filename[MAXFILENAME+10]; /* Platz fuer '.class' */ + u2 filenamelen; + char *pathpos; + u2 i,c; + + + pathpos = classpath; + + while (*pathpos) { + while ( *pathpos == ':' ) pathpos++; + + filenamelen=0; + while ( (*pathpos) && (*pathpos!=':') ) { + PANICIF (filenamelen >= MAXFILENAME, "Filename too long") ; + + filename[filenamelen++] = *(pathpos++); + } + + filename[filenamelen++] = '/'; + + for (i=0; i < classname -> length; i++) { + PANICIF (filenamelen >= MAXFILENAME, "Filename too long"); + + c = classname -> text [i]; + if (c=='/') c = '/'; /* Slashes im Namen passen zu UNIX */ + else { + if ( c<=' ' || c>'z') { + c = '?'; + } + } + + filename[filenamelen++] = c; + } + + strcpy (filename+filenamelen, ".class"); + + classfile = fopen(filename, "r"); + if (classfile) { + return true; + } + + + } + + sprintf (logtext,"Can not open class file '%s'", filename); + error(); + return false; +} + + +/************************** Funktion: suck_stop ******************************* + + Schlie"st die offene Datei wieder. + +******************************************************************************/ + +void suck_stop () +{ + u4 rest=0; + u1 dummy; + + while ( fread (&dummy, 1,1, classfile) > 0) rest++; + if (rest) { + sprintf (logtext,"There are %d access bytes at end of classfile", + (int) rest); + dolog(); + } + + fclose (classfile); + classfile = NULL; +} + + + +/************************** Lesefunktionen *********************************** + + Lesen von der Datei in verschieden grossen Paketen + (8,16,32,64-bit Integer oder Float) + +*****************************************************************************/ + +void suck_nbytes (u1 *buffer, u4 len) +{ + if ( fread (buffer, 1, len, classfile) != len) panic ("Unexpected EOF"); +} + + +void skip_nbytes (u4 len) +{ + u4 i; + for (i=0; ihashlink; + + if (u->string) del (u->string); + + MFREE (u->text, u2, u->length); + FREE (u, unicode); + u = nextu; + } + } + MFREE (unicodehash, unicode*, unicodehashsize); +} + + +/********************* Funktion: unicode_display ****************************** + + Gibt ein unicode-Symbol auf stdout aus (zu Debugzwecken) + +******************************************************************************/ + +void unicode_display (unicode *u) +{ + u2 i,c; + for (i=0; i < u->length; i++) { + c = u->text[i]; + if (c>=32 && c<=127) printf ("%c",c); + else printf ("?"); + } + fflush (stdout); +} + + +/********************* Funktion: unicode_sprint ****************************** + + Schreibt ein unicode-Symbol in einen C-String + +******************************************************************************/ + +void unicode_sprint (char *buffer, unicode *u) +{ + u2 i; + for (i=0; i < u->length; i++) buffer[i] = u->text[i]; + buffer[i] = '\0'; +} + + +/********************* Funktion: unicode_fprint ****************************** + + Schreibt ein unicode-Symbol auf eine Datei aus + +******************************************************************************/ + +void unicode_fprint (FILE *file, unicode *u) +{ + u2 i; + for (i=0; i < u->length; i++) putc (u->text[i], file); +} + + +/****************** interne Funktion: u_hashkey ******************************/ + +static u4 u_hashkey (u2 *text, u2 length) +{ + u4 k = 0; + u2 i,sh=0; + + for (i=0; i hashlink; + u4 slot = (u->key) % newhashsize; + + u->hashlink = newhash[slot]; + newhash[slot] = u; + + u = nextu; + } + } + + MFREE (unicodehash, unicode*, unicodehashsize); + unicodehash = newhash; + unicodehashsize = newhashsize; +} + + +/****************** Funktion: unicode_new_u2 ********************************** + + Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser + Funktion als u2-Array "ubergeben + +******************************************************************************/ + +unicode *unicode_new_u2 (u2 *text, u2 length) +{ + u4 key = u_hashkey (text, length); + u4 slot = key % unicodehashsize; + unicode *u = unicodehash[slot]; + u2 i; + + while (u) { + if (u->key == key) { + if (u->length == length) { + for (i=0; itext[i]) goto nomatch; + } + return u; + } + } + nomatch: + u = u->hashlink; + } + +#ifdef STATISTICS + count_unicode_len += sizeof(unicode) + 2 * length; +#endif + + u = NEW (unicode); + u->key = key; + u->length = length; + u->text = MNEW (u2, length); + u->class = NULL; + u->string = NULL; + u->hashlink = unicodehash[slot]; + unicodehash[slot] = u; + for (i=0; itext[i] = text[i]; + + unicodeentries++; + + if ( unicodeentries > (unicodehashsize/2)) u_reorganizehash(); + + return u; +} + + +/********************* Funktion: unicode_new_char ***************************** + + Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser + Funktion als C-String ( = char* ) "ubergeben + +******************************************************************************/ + +unicode *unicode_new_char (char *text) +{ +#define MAXNEWCHAR 500 + u2 buffer[MAXNEWCHAR]; + u2 length = 0; + u1 c; + + while ( (c = *text) != '\0' ) { + if (length>=MAXNEWCHAR) panic ("Text too long in unicode_new_char"); + buffer[length++] = c; + text ++; + } + return unicode_new_u2 (buffer, length); +} + + +/********************** Funktion: unicode_setclasslink ************************ + + H"angt einen Verweis auf eine Klasse an ein unicode-Symbol an. + +******************************************************************************/ + +void unicode_setclasslink (unicode *u, classinfo *class) +{ + PANICIF (u->class, "Attempt to attach class to already attached symbol"); + u->class = class; +} + +/********************** Funktion: unicode_getclasslink ************************ + + Sucht den Verweis von einem unicode-Symbol auf eine Klasse. + Wenn keine solche Klasse existiert, dann wird ein Fehler + ausgegeben. + +******************************************************************************/ + +classinfo *unicode_getclasslink (unicode *u) +{ + PANICIF (!u->class, "Attempt to get unknown class-reference"); + return u->class; +} + + + +/********************* Funktion: unicode_unlinkclass ************************* + + Entfernt den Verweis auf eine Klasse wieder von einem Symbol + +******************************************************************************/ + +void unicode_unlinkclass (unicode *u) +{ + PANICIF (!u->class, "Attempt to unlink not yet linked symbol"); + u -> class = NULL; +} + + + +/******************* Funktion> unicode_setstringlink ********************* + + H"angt einen Verweis auf einen konstanten String an ein + Unicode-Symbol + +*************************************************************************/ + +void unicode_setstringlink (unicode *u, java_objectheader *str) +{ + PANICIF (u->string, "Attempt to attach string to already attached symbol"); + u->string = str; +} + + +/********************* Funktion: unicode_unlinkstring ************************* + + Entfernt den Verweis auf einen String wieder von einem Symbol + +******************************************************************************/ + +void unicode_unlinkstring (unicode *u) +{ + PANICIF (!u->class, "Attempt to unlink not yet linked symbol"); + u -> string = NULL; +} + + + +/*********************** Funktion: unicode_show ****************************** + + gibt eine Aufstellung aller Symbol im unicode-hash auf stdout aus. + (nur f"ur Debug-Zwecke) + +*****************************************************************************/ + +void unicode_show () +{ + unicode *u; + u4 i; + + printf ("UNICODE-HASH: %d slots for %d entries\n", + (int) unicodehashsize, (int) unicodeentries ); + + for (i=0; istring) printf ("(string) "); + u = u->hashlink; + } + printf ("\n"); + } + + } +} + + + +/****************************************************************************** +*********************** Diverse Support-Funktionen **************************** +******************************************************************************/ + + +/******************** Funktion: desc_to_type ********************************** + + Findet zu einem gegebenen Typdescriptor den entsprechenden + Java-Grunddatentyp. + +******************************************************************************/ + +u2 desc_to_type (unicode *descriptor) +{ + if (descriptor->length < 1) panic ("Type-Descriptor is empty string"); + + switch (descriptor->text[0]) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': return TYPE_INT; + case 'D': return TYPE_DOUBLE; + case 'F': return TYPE_FLOAT; + case 'J': return TYPE_LONG; + case 'L': + case '[': return TYPE_ADDRESS; + } + + sprintf (logtext, "Invalid Type-Descriptor: "); + unicode_sprint (logtext+strlen(logtext), descriptor); + error (); + return 0; +} + + +/********************** Funktion: desc_typesize ******************************* + + Berechnet die L"ange (in Byte) eines Datenelements gegebenen Typs, + der durch den Typdescriptor gegeben ist. + +******************************************************************************/ + +u2 desc_typesize (unicode *descriptor) +{ + switch (desc_to_type(descriptor)) { + case TYPE_INT: return 4; + case TYPE_LONG: return 8; + case TYPE_FLOAT: return 4; + case TYPE_DOUBLE: return 8; + case TYPE_ADDRESS: return sizeof(voidptr); + default: return 0; + } +} + + + + + +/****************************************************************************** +********************* Der garbage-collected Heap ****************************** +******************************************************************************* + + verwaltet einen Heap mit automatischer Speicherfreigabe. + + (eine ausf"uhrliche Dokumentation findet sich in der Datei: + collect.doc) + +******************************************************************************/ + + +bool collectverbose = false; /* soll Meldung beim GC ausgegeben werden? */ + + +#define BLOCKSIZE 8 /* Gr"osse eines Speicherblockes */ +typedef u8 heapblock; /* Datentyp mit der Gr"osse eines Speicherblocks */ + +#if U8_AVAILABLE && SUPPORT_LONG +#define bitfieldtype u8 +#define BITFIELDBITS 64 +#else +#define bitfieldtype u4 +#define BITFIELDBITS 32 +#endif + +u4 heapsize; /* Gr"osse des Heap in Blocks */ +u4 topofheap; /* Bisherige Obergrenze Heaps */ +heapblock *heap; /* Speicher f"ur den Heap selbst */ + +bitfieldtype *startbits; /* Bitfeld f"ur Bereichsstartkennung */ +bitfieldtype *markbits; /* Bitfeld f"ur Markierung */ +bitfieldtype *referencebits; /* Bitfeld f"ur Folgereferenzenkennung */ + +u4 heapfillgrade; /* Menge der Daten im Heap */ +u4 collectthreashold; /* Schwellwert f"ur n"achstes GC */ + +void **bottom_of_stack; /* Zeiger auf Untergrenze des C-Stacks */ +chain *allglobalreferences; /* Liste f"ur alle globalen Zeiger */ + +typedef struct finalizernode { + struct finalizernode *next; + u4 objstart; + methodinfo *finalizer; + } finalizernode; + +finalizernode *livefinalizees; +finalizernode *deadfinalizees; + + +typedef struct memarea { /* Datenstruktur f"ur einen Freispeicherbereich */ + struct memarea *next; + } memarea; + +typedef struct bigmemarea { /* Datenstruktur f"ur einen */ + struct bigmemarea *next; /* Freispeicherbereich variabler L"ange */ + u4 size; + } bigmemarea; + +#define DIFFERENTSIZES 128 /* Anzahl der 'kleinen' Freispeicherlisten */ +memarea *memlist[DIFFERENTSIZES]; /* Die 'kleinen' Freispeicherlisten */ +bitfieldtype memlistbits[DIFFERENTSIZES/BITFIELDBITS]; + /* Bitfeld, in dem jeweils ein Bit gesetzt */ + /* ist, wenn eine Liste noch etwas enth"alt */ + +bigmemarea *bigmemlist; /* Liste der gr"osseren Freispeicherbereiche */ + + + + +/**************** Hilfsfunktion: lowest ************************************** + +liefert als Ergebnis die Nummer des niederwertigsten Bits einer +Zahl vom Typ bitfieldtype, das 1 ist. +Wenn die ganze Zahl keine 1en enth"alt, dann ist egal, was f"ur einen +Wert die Funktion l"iefert. +z.B.: lowest(1) = 0, lowest(12) = 2, lowest(1024) = 10 + +*****************************************************************************/ + +static u1 lowesttable[256] = { + 255, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; + +static int lowest(bitfieldtype i) +{ +#if BITFIELDBITS==64 + u8 i1 = i<<32; + if (i1) { + u8 i11 = i1<<16; + if (i11) { + u8 i111 = i11<<8; + if (i111) return lowesttable[i111>>56]; + else return 8+lowesttable[i11>>56]; + } + else { + u8 i112 = i1<<8; + if (i112) return 16+lowesttable[i112>>56]; + else return 24+lowesttable[i1>>56]; + } + } + else { + u8 i12 = i<<16; + if (i12) { + u8 i121 = i12<<8; + if (i121) return 32+lowesttable[i121>>56]; + else return 40+lowesttable[i12>>56]; + } + else { + u8 i122 = i<<8; + if (i122) return 48+lowesttable[i122>>56]; + else return 56+lowesttable[i>>56]; + } + } +#else + u4 i1 = i<<16; + if (i1) { + u4 i11 = i1<<8; + if (i11) return lowesttable[i11>>24]; + else return 8+lowesttable[i1>>24]; + } + else { + u4 i12 = i<<8; + if (i12) return 16+lowesttable[i12>>24]; + else return 24+lowesttable[i>>24]; + } +#endif +} + + +/******** Funktionen zum Setzen und L"oschen von Bits in Bitfeldern ***********/ + +static void setbit(bitfieldtype *bitfield, u4 bitnumber) +{ + bitfield[bitnumber/BITFIELDBITS] |= + ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS); +} + +static void clearbit(bitfieldtype *bitfield, u4 bitnumber) +{ + bitfield[bitnumber/BITFIELDBITS] &= + ~((bitfieldtype) 1) << (bitnumber%BITFIELDBITS); +} + +static bool isbitset(bitfieldtype *bitfield, u4 bitnumber) +{ + return ( bitfield[bitnumber/BITFIELDBITS] & + ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) != 0; +} + +static bool isbitclear(bitfieldtype *bitfield, u4 bitnumber) +{ + return ( bitfield[bitnumber/BITFIELDBITS] & + ( ((bitfieldtype) 1) << (bitnumber%BITFIELDBITS) ) ) == 0; +} + + +/***************** Funktion: clearbitfield ************************************ + + l"oscht ein ganzes Bitfeld + +******************************************************************************/ + +static void clearbitfield(bitfieldtype *bitfield, u4 fieldsize) +{ + u4 i,t; + t = ALIGN(fieldsize, BITFIELDBITS) / BITFIELDBITS; + for (i=0; i= fieldsize) return fieldsize; + + pattern = bitfield[bitnumber/BITFIELDBITS]; + pattern >>= (bitnumber%BITFIELDBITS); + if (pattern) return bitnumber + lowest(pattern); + + bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS; + } +} + + +/************ Funktion: findnextcombination_set_unset ************************* + + funktioniert wie findnextsetbit, allerdings sucht diese Funktion + nach einer Stelle, an der gleichzeitig ein Bit im ersten + Bitfeld gesetzt ist und im zweiten Bitfeld das entsprechende + Bit nicht gesetzt ist. + +******************************************************************************/ + +static u4 findnextcombination_set_unset + (bitfieldtype *bitfield1, bitfieldtype* bitfield2, u4 fieldsize, u4 bitnumber) +{ + bitfieldtype pattern; + + for (;;) { + if (bitnumber >= fieldsize) return fieldsize; + + pattern = bitfield1[bitnumber/BITFIELDBITS] + & (~bitfield2[bitnumber/BITFIELDBITS]); + pattern >>= (bitnumber%BITFIELDBITS); + if (pattern) return bitnumber + lowest(pattern); + + bitnumber = ((bitnumber + BITFIELDBITS) / BITFIELDBITS) * BITFIELDBITS; + } +} + + + +/************** Funktion: memlist_init **************************************** + + initialisiert die Freispeicherlisten (zum nachfolgenden Eintragen + mit memlist_addrange). + +******************************************************************************/ + +static void memlist_init () +{ + u4 i; + for (i=0; i=DIFFERENTSIZES) { + bigmemarea *m = (bigmemarea*) (heap+freestart); + m -> next = bigmemlist; + m -> size = freesize; + bigmemlist = m; + } + else { + if (freesize*BLOCKSIZE>=sizeof(memarea)) { + memarea *m = (memarea*) (heap+freestart); + m -> next = memlist[freesize]; + memlist[freesize] = m; + setbit (memlistbits, freesize); + } + } +} + + +/************** Funktion: memlist_getsuitable ********************************* + + sucht in der Freispeicherliste einen Speicherbereich, der m"oglichst + genau die gew"unschte L"ange hat. + Der Bereich wird dabei auf jeden Fall aus der Liste ausgetragen. + (Wenn der Bereich zu lang sein sollte, dann kann der Aufrufer den + Rest wieder mit 'memlist_addrange' in die Liste einh"angen) + + Return (in Referenzparametern): + *freestart: Anfang des freien Speichers + *freelength: L"ange dieses Speicherbereiches + + Wenn kein passender Speicherblock mehr gefunden werden kann, dann + wird in '*freelength' 0 hineingeschrieben. + +******************************************************************************/ + +static void memlist_getsuitable (u4 *freestart, u4 *freelength, u4 length) +{ + bigmemarea *m; + bigmemarea *prevm = NULL; + + if (lengthnext; + if (!m->next) clearbit (memlistbits, firstfreelength); + *freestart = ((heapblock*) m) - heap; + *freelength = firstfreelength; + return; + } + } + + m = bigmemlist; + while (m) { + if (m->size >= length) { + if (prevm) prevm->next = m->next; + else bigmemlist = m->next; + + *freestart = ((heapblock*) m) - heap; + *freelength = m->size; + return ; + } + + prevm = m; + m = m->next; + } + + *freelength=0; +} + + + + + +/******************* Funktion: mark ******************************************* + + Markiert ein m"oglicherweise g"ultiges Objekt. + Sollte sich herausstellen, dass der Zeiger gar nicht auf ein Objekt + am Heap zeigt, dann wird eben gar nichts markiert. + +******************************************************************************/ + +static void markreferences (void **rstart, void **rend); + +static void mark (heapblock *obj) +{ + u4 blocknum,objectend; + + if ((long) obj & (BLOCKSIZE-1)) return; + + if (obj=(heap+topofheap) ) return; + + blocknum = obj-heap; + if ( isbitclear(startbits, blocknum) ) return; + if ( isbitset(markbits, blocknum) ) return; + + setbit (markbits, blocknum); + + if ( isbitclear(referencebits, blocknum) ) return; + + objectend = findnextsetbit (startbits, topofheap, blocknum+1); + markreferences ((void**)obj, (void**) (heap+objectend) ); +} + + +/******************** Funktion: markreferences ******************************** + + Geht einen Speicherbereich durch, und markiert alle Objekte, auf + die von diesem Bereich aus irgendeine Referenz existiert. + +******************************************************************************/ + +static void markreferences (void **rstart, void **rend) +{ + void **ptr; + + for (ptr=rstart; ptr (void**)CONTEXT(aThread).stackEnd) + markreferences ((void**)CONTEXT(aThread).stackEnd, top_of_stack); + else + markreferences (top_of_stack, (void**)CONTEXT(aThread).stackEnd); + } + else { + if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd) + markreferences ((void**)CONTEXT(aThread).stackEnd, + (void**)CONTEXT(aThread).usedStackTop + 16); + else + markreferences ((void**)CONTEXT(aThread).usedStackTop - 16, + (void**)CONTEXT(aThread).stackEnd); + } + } + + markreferences((void**)&threadQhead[0], (void**)&threadQhead[MAX_THREAD_PRIO]); +#else + if (top_of_stack > bottom_of_stack) + markreferences(bottom_of_stack, top_of_stack); + else + markreferences(top_of_stack, bottom_of_stack); +#endif +} + + + +/**************** Funktion: searchlivefinalizees ***************************** + + geht die Liste aller Objekte durch, die noch finalisiert werden m"ussen + (livefinalizees), und tr"agt alle nicht mehr markierten in die + Liste deadfinalizess ein (allerdings werden sie vorher noch als + erreicht markiert, damit sie nicht jetzt gleich gel"oscht werden). + +*****************************************************************************/ + +static void searchlivefinalizees () +{ + finalizernode *fn = livefinalizees; + finalizernode *lastlive = NULL; + + while (fn) { + + /* alle zu finalisierenden Objekte, die nicht mehr markiert sind: */ + if (isbitclear (markbits, fn->objstart)) { + finalizernode *nextfn = fn->next; + + mark (heap + fn->objstart); + + if (lastlive) lastlive -> next = nextfn; + else livefinalizees = nextfn; + + fn -> next = deadfinalizees; + deadfinalizees = fn; + + fn = nextfn; + } + else { + lastlive = fn; + fn = fn->next; + } + } +} + + + +/********************** Funktion: finalizedead ******************************* + + ruft die 'finalize'-Methode aller Objekte in der 'deadfinalizees'- + Liste auf. + Achtung: Es kann hier eventuell zu neuerlichen Speicheranforderungen + (mit potentiell notwendigem GC) kommen, deshalb m"ussen manche + globalen Variablen in lokale Variblen kopiert werden + (Reentrant-F"ahigkeit!!!) + +******************************************************************************/ + +static void finalizedead() +{ + finalizernode *fn = deadfinalizees; + deadfinalizees = NULL; + + while (fn) { + finalizernode *nextfn = fn->next; + + asm_calljavamethod (fn->finalizer, heap+fn->objstart, NULL,NULL,NULL); + FREE (fn, finalizernode); + + fn = nextfn; + } + +} + + + +/****************** Funktion: heap_docollect ********************************** + + F"uhrt eine vollst"andige Garbage Collection durch + +******************************************************************************/ + +static void heap_docollect () +{ + u4 freestart,freeend; + void **p; + bitfieldtype *dummy; + u4 heapfreemem; + u4 oldfillgrade; + + + if (runverbose) { + fprintf(stderr, "doing garbage collection\n"); + } + /* alle Markierungsbits l"oschen */ + clearbitfield (markbits, topofheap); + + /* Alle vom Stack referenzierten Objekte markieren */ + asm_dumpregistersandcall (markstack); + + /* Alle von globalen Variablen erreichbaren Objekte markieren */ + p = chain_first (allglobalreferences); + while (p) { + mark (*p); + p = chain_next (allglobalreferences); + } + + /* alle Objekte durchsehen, die eine finalizer-Methode haben */ + searchlivefinalizees(); + + /* alle Reference-Bits l"oschen, deren Objekte nicht */ + /* mehr erreichbar sind */ + maskfieldwithfield (referencebits, markbits, topofheap); + + + /* Freispeicherliste initialisieren */ + memlist_init (); + + + /* Heap schrittweise durchgehen, und alle freien Bl"ocke merken */ + + heapfreemem = 0; + freeend=0; + for (;;) { + /* Anfang des n"achsten freien Bereiches suchen */ + freestart = findnextcombination_set_unset + (startbits, markbits, topofheap, freeend); + + /* Wenn es keinen freien Bereich mehr gibt -> fertig */ + if (freestart>=topofheap) goto freememfinished; + + /* Anfang des freien Bereiches markieren */ + setbit (markbits, freestart); + + /* Ende des freien Bereiches suchen */ + freeend = findnextsetbit (markbits, topofheap, freestart+1); + + /* Freien Bereich in Freispeicherliste einh"angen */ + memlist_addrange (freestart, freeend-freestart); + + /* Menge des freien Speichers mitnotieren */ + heapfreemem += (freeend-freestart); + } + + freememfinished: + + /* Die Rollen von markbits und startbits vertauschen */ + dummy = markbits; + markbits = startbits; + startbits = dummy; + + + /* Threashold-Wert f"ur n"achstes Collect */ + oldfillgrade = heapfillgrade; + heapfillgrade = topofheap - heapfreemem; + collectthreashold = heapfillgrade*3; /* eine nette Heuristik */ + + /* Eventuell eine Meldung ausgeben */ + if (collectverbose) { + sprintf (logtext, "Garbage Collection: previous/now = %d / %d ", + (int) (oldfillgrade * BLOCKSIZE), + (int) (heapfillgrade * BLOCKSIZE) ); + dolog (); + } + + + + /* alle gerade unerreichbar gewordenen Objekte mit + finalize-Methoden jetzt finalisieren. + Achtung: Diese Funktion kann zu neuerlichem GC f"uhren!! */ + finalizedead (); + +} + +/************************* Function: gc_init ********************************** + + Initializes the garbage collection thread mechanism. + +******************************************************************************/ + +#ifdef USE_THREADS +iMux gcStartMutex; +iMux gcThreadMutex; +iCv gcConditionStart; +iCv gcConditionDone; + +void +gc_init (void) +{ + gcStartMutex.holder = 0; + gcStartMutex.count = 0; + gcStartMutex.muxWaiters = 0; + + gcThreadMutex.holder = 0; + gcThreadMutex.count = 0; + gcThreadMutex.muxWaiters = 0; + + gcConditionStart.cvWaiters = 0; + gcConditionStart.mux = 0; + + gcConditionDone.cvWaiters = 0; + gcConditionDone.mux = 0; +} +#else +void +gc_init (void) +{ +} +#endif + +/************************* Function: gc_thread ******************************** + + In an endless loop waits for a condition to be posted, then + garbage collects the heap. + +******************************************************************************/ + +#ifdef USE_THREADS +void +gc_thread (void) +{ + intsRestore(); /* all threads start with interrupts disabled */ + + assert(blockInts == 0); + + lock_mutex(&gcThreadMutex); + + for (;;) + { + wait_cond(&gcThreadMutex, &gcConditionStart, 0); + + intsDisable(); + heap_docollect(); + intsRestore(); + + signal_cond(&gcConditionDone); + } +} +#endif + +void +gc_call (void) +{ +#ifdef USE_THREADS + lock_mutex(&gcThreadMutex); + + signal_cond(&gcConditionStart); + wait_cond(&gcThreadMutex, &gcConditionDone, 0); + + unlock_mutex(&gcThreadMutex); +#else + heap_docollect(); +#endif +} + + +/************************* Funktion: heap_init ******************************** + + Initialisiert den Garbage Collector. + Parameter: + heapbytesize: Maximale Gr"osse des Heap (in Bytes) + heapbytestartsize: Gr"osse des Heaps, bei dem zum ersten mal eine + GC durchgef"uhrt werden soll. + stackbottom: Ein Zeiger auf die Untergrenze des Stacks, im dem + Referenzen auf Objekte stehen k"onnen. + +******************************************************************************/ + +void heap_init (u4 heapbytesize, u4 heapbytestartsize, void **stackbottom) +{ + +#ifdef TRACECALLARGS + + heapsize = ALIGN (heapbytesize, getpagesize()); + heapsize = heapsize/BLOCKSIZE; + heap = (void*) mmap ((void*) 0x10000000, (size_t) (heapsize * BLOCKSIZE), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, (off_t) 0); + if (heap != (void *) 0x10000000) { + perror("mmap"); + printf("address = %p\n", heap); + panic("mmap failed\n"); + } + +#else + + heapsize = ALIGN (heapbytesize, 1024); + heapsize = heapsize/BLOCKSIZE; + heap = MNEW (heapblock, heapsize); + +#endif + + topofheap = 0; + startbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + markbits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + referencebits = MNEW (bitfieldtype, heapsize/BITFIELDBITS); + clearbitfield (startbits, heapsize); + clearbitfield (markbits, heapsize); + clearbitfield (referencebits, heapsize); + + heapfillgrade = 0; + collectthreashold = heapbytestartsize/BLOCKSIZE; + allglobalreferences = chain_new (); + bottom_of_stack = stackbottom; + + livefinalizees = NULL; + deadfinalizees = NULL; +} + + +/****************** Funktion: heap_close ************************************** + + Gibt allen ben"otigten Speicher frei + +******************************************************************************/ + +void heap_close () +{ +#ifndef TRACECALLARGS + MFREE (heap, heapblock, heapsize); */ +#endif + MFREE (startbits, bitfieldtype, heapsize/BITFIELDBITS); + MFREE (markbits, bitfieldtype, heapsize/BITFIELDBITS); + MFREE (referencebits, bitfieldtype, heapsize/BITFIELDBITS); + chain_free (allglobalreferences); + + while (livefinalizees) { + finalizernode *n = livefinalizees->next; + FREE (livefinalizees, finalizernode); + livefinalizees = n; + } +} + + +/***************** Funktion: heap_addreference ******************************** + + Teilt dem GC eine Speicherstelle mit, an der eine globale Referenz + auf Objekte gespeichert sein kann. + +******************************************************************************/ + +void heap_addreference (void **reflocation) +{ + intsDisable(); /* schani */ + + chain_addlast (allglobalreferences, reflocation); + + intsRestore(); /* schani */ +} + + + +/***************** Funktion: heap_allocate ************************************ + + Fordert einen Speicher vom Heap an, der eine gew"unschte Gr"osse + (in Byte angegeben) haben muss. + Wenn kein Speicher mehr vorhanden ist (auch nicht nach einem + Garbage Collection-Durchlauf), dann wird NULL zur"uckgegeben. + Zus"atzlich wird durch den Parameter 'references' angegeben, ob + in das angelegte Objekt Referenzen auf andere Objekte eingetragen + werden k"onnten. + (Wichtig wegen Beschleunigung des Mark&Sweep-Durchlauf) + Im Zweifelsfalle immer references=true verwenden. + +******************************************************************************/ + +void *heap_allocate (u4 bytelength, bool references, methodinfo *finalizer) +{ + u4 freestart,freelength; + u4 length = ALIGN(bytelength, BLOCKSIZE) / BLOCKSIZE; + + intsDisable(); /* schani */ + + memlist_getsuitable (&freestart, &freelength, length); + +onemoretry: + if (!freelength) { + if ( (topofheap+length > collectthreashold) + || (topofheap+length > heapsize) ) { + + intsRestore(); + gc_call(); + intsDisable(); + + memlist_getsuitable (&freestart, &freelength, length); + if (freelength) goto onemoretry; + } + + if (topofheap+length > heapsize) { + sprintf (logtext, "Heap-Allocation failed for %d bytes", + (int) bytelength); + dolog(); + intsRestore(); /* schani */ + return NULL; + } + + freestart = topofheap; + freelength = length; + setbit (startbits, topofheap); + topofheap += length; + } + else { + if (freelength>length) { + setbit (startbits, freestart+length); + memlist_addrange (freestart+length, freelength-length); + } + } + + if (references) setbit (referencebits, freestart); + + heapfillgrade += length; + + if (finalizer) { + finalizernode *n = NEW(finalizernode); + n -> next = livefinalizees; + n -> objstart = freestart; + n -> finalizer = finalizer; + livefinalizees = n; + } + + intsRestore(); /* schani */ + + if (runverbose) { + sprintf (logtext, "new returns: %lx", (long) (heap + freestart)); + dolog (); + } + + return (void*) (heap + freestart); +} + + + + diff --git a/tables.h b/tables.h new file mode 100644 index 000000000..80f789328 --- /dev/null +++ b/tables.h @@ -0,0 +1,63 @@ +/****************************** tables.h *************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/11/20 + +*******************************************************************************/ + +extern bool collectverbose; + + +#define CLASS(name) (unicode_getclasslink(unicode_new_char(name))) + +typedef void (*stringdeleter) ( java_objectheader *string ); + + +void suck_init (char *classpath); +bool suck_start (unicode *name); +void suck_stop (); +void suck_nbytes (u1 *buffer, u4 len); +void skip_nbytes (u4 len); +u1 suck_u1 (); +s1 suck_s1 (); +u2 suck_u2 (); +s2 suck_s2 (); +u4 suck_u4 (); +s4 suck_s4 (); +u8 suck_u8 (); +s8 suck_s8 (); +float suck_float (); +double suck_double (); + + +void unicode_init (); +void unicode_close (stringdeleter del); +void unicode_display (unicode *u); +void unicode_sprint (char *buffer, unicode *u); +void unicode_fprint (FILE *file, unicode *u); +unicode *unicode_new_u2 (u2 *text, u2 length); +unicode *unicode_new_char (char *text); +void unicode_setclasslink (unicode *u, classinfo *class); +classinfo *unicode_getclasslink (unicode *u); +void unicode_unlinkclass (unicode *u); +void unicode_setstringlink (unicode *u, java_objectheader *str); +void unicode_unlinkstring (unicode *u); +void unicode_show (); + +u2 desc_to_type (unicode *descriptor); +u2 desc_typesize (unicode *descriptor); + + +void heap_init (u4 size, u4 startsize, void **stackbottom); +void heap_close (); +void *heap_allocate (u4 bytelength, bool references, methodinfo *finalizer); +void heap_addreference (void **reflocation); + +void gc_init (void); +void gc_thread (void); +void gc_call (void); diff --git a/tests/JavaPerformance.java b/tests/JavaPerformance.java new file mode 100644 index 000000000..049fdb662 --- /dev/null +++ b/tests/JavaPerformance.java @@ -0,0 +1,396 @@ +import java.util.*; +import java.io.*; + +class SubClass1 extends Object { +} + +class SubClass2 extends Object { + int a,b,c; + + SubClass2 (int aa, int ab, int ac) { + a = aa; + b = ab; + c = ac; + } + + public void methodWithLocalAccess () { + int la,lb,lc; + for (int i=0; i0) { + int length = 1+Math.abs(r.nextInt())%5; + data = new List[length]; + for (int i=0; i1) + return x*fak(x-1); + else + return 1; + } + + public static void arithmeticTest () { + System.out.println ("Arithmetic time"); + System.out.println (); + + System.out.print ("ggT (24,42)..."); + long l = System.currentTimeMillis(); + for (int i = 0; i f2)) p(" (" + s1 + " > " + s2 + ") = true"); + else p(" (" + s1 + " > " + s2 + ") = false"); + if ( (f1 >= f2)) p(" (" + s1 + " >= " + s2 + ") = true"); + else p(" (" + s1 + " >= " + s2 + ") = false"); + + if (!(f1 == f2)) p("!(" + s1 + " == " + s2 + ") = true"); + else p("!(" + s1 + " == " + s2 + ") = false"); + if (!(f1 != f2)) p("!(" + s1 + " != " + s2 + ") = true"); + else p("!(" + s1 + " != " + s2 + ") = false"); + if (!(f1 < f2)) p("!(" + s1 + " < " + s2 + ") = true"); + else p("!(" + s1 + " < " + s2 + ") = false"); + if (!(f1 <= f2)) p("!(" + s1 + " <= " + s2 + ") = true"); + else p("!(" + s1 + " <= " + s2 + ") = false"); + if (!(f1 > f2)) p("!(" + s1 + " > " + s2 + ") = true"); + else p("!(" + s1 + " > " + s2 + ") = false"); + if (!(f1 >= f2)) p("!(" + s1 + " >= " + s2 + ") = true"); + else p("!(" + s1 + " >= " + s2 + ") = false"); + + if ( (d1 == d2)) p(" (" + s1 + " == " + s2 + ") = true"); + else p(" (" + s1 + " == " + s2 + ") = false"); + if ( (d1 != d2)) p(" (" + s1 + " != " + s2 + ") = true"); + else p(" (" + s1 + " != " + s2 + ") = false"); + if ( (d1 < d2)) p(" (" + s1 + " < " + s2 + ") = true"); + else p(" (" + s1 + " < " + s2 + ") = false"); + if ( (d1 <= d2)) p(" (" + s1 + " <= " + s2 + ") = true"); + else p(" (" + s1 + " <= " + s2 + ") = false"); + if ( (d1 > d2)) p(" (" + s1 + " > " + s2 + ") = true"); + else p(" (" + s1 + " > " + s2 + ") = false"); + if ( (d1 >= d2)) p(" (" + s1 + " >= " + s2 + ") = true"); + else p(" (" + s1 + " >= " + s2 + ") = false"); + + if (!(d1 == d2)) p("!(" + s1 + " == " + s2 + ") = true"); + else p("!(" + s1 + " == " + s2 + ") = false"); + if (!(d1 != d2)) p("!(" + s1 + " != " + s2 + ") = true"); + else p("!(" + s1 + " != " + s2 + ") = false"); + if (!(d1 < d2)) p("!(" + s1 + " < " + s2 + ") = true"); + else p("!(" + s1 + " < " + s2 + ") = false"); + if (!(d1 <= d2)) p("!(" + s1 + " <= " + s2 + ") = true"); + else p("!(" + s1 + " <= " + s2 + ") = false"); + if (!(d1 > d2)) p("!(" + s1 + " > " + s2 + ") = true"); + else p("!(" + s1 + " > " + s2 + ") = false"); + if (!(d1 >= d2)) p("!(" + s1 + " >= " + s2 + ") = true"); + else p("!(" + s1 + " >= " + s2 + ") = false"); + } + + // ********************* output methods **************************** + + public static int linenum = 0; + + public static void pnl() { + int i; + + System.out.println(); + for (i = 4 - Integer.toString(linenum).length(); i > 0; i--) + System.out.print(' '); + System.out.print(linenum); + System.out.print(". "); + linenum++; + } + + public static void p(String a) { + System.out.print(a); pnl(); + } + public static void p(boolean a) { + System.out.print(a); pnl(); + } + public static void p(int a) { + System.out.print("int: "); System.out.print(a); pnl(); + } + public static void p(long a) { + System.out.print("long: "); System.out.print(a); pnl(); + } + public static void p(short a) { + System.out.print("short: "); System.out.print(a); pnl(); + } + public static void p(byte a) { + System.out.print("byte: "); System.out.print(a); pnl(); + } + public static void p(char a) { + System.out.print("char: "); System.out.print((int)a); pnl(); + } + public static void p(float a) { + System.out.print("float: "); System.out.print(a); pnl(); + } + public static void p(double a) { + System.out.print("double: "); System.out.print(a); pnl(); + } + + public static void p(String s, boolean i) { + System.out.print(s); p(i); + } + public static void p(String s, int i) { + System.out.print(s); p(i); + } + public static void p(String s, byte i) { + System.out.print(s); p(i); + } + public static void p(String s, char i) { + System.out.print(s); p(i); + } + public static void p(String s, short i) { + System.out.print(s); p(i); + } + public static void p(String s, long l) { + System.out.print(s); p(l); + } + public static void p(String s, float f) { + System.out.print(s); p(f); + } + public static void p(String s, double d) { + System.out.print(s); p(d); + } + + } diff --git a/tests/ftest.java b/tests/ftest.java new file mode 100644 index 000000000..6c67971f2 --- /dev/null +++ b/tests/ftest.java @@ -0,0 +1,19 @@ +import java.awt.*; + +public class ftest { + public static void main(String [] s) { + +// Frame f = new Frame(s[0]); + +// f.show(); + +// System.getProperties().list (System.out); + + System.out.println ("-- default toolkit ---"); + System.out.println (Toolkit.getDefaultToolkit(). + getClass().getName() ); + + } + } + + \ No newline at end of file diff --git a/tests/hello.java b/tests/hello.java new file mode 100644 index 000000000..8243e1bd5 --- /dev/null +++ b/tests/hello.java @@ -0,0 +1,5 @@ +public class hello { + public static void main(String[] s) { + System.out.println ("Hello world"); + } + } diff --git a/tests/helper.java b/tests/helper.java new file mode 100644 index 000000000..4d340a3c9 --- /dev/null +++ b/tests/helper.java @@ -0,0 +1,3 @@ + +public class helper { + } diff --git a/tests/hi.java b/tests/hi.java new file mode 100644 index 000000000..ca1c61e79 --- /dev/null +++ b/tests/hi.java @@ -0,0 +1,12 @@ +public class hi { + public static void Ausgabe() { + System.out.println ("eine Zeile Text"); + } + + public static void main(String[] args) { + int i; + for (i=0; i<10; i++) Ausgabe(); + + System.out.println ("Juhu, das funktioniert"); + } +} diff --git a/tests/intsieve.java b/tests/intsieve.java new file mode 100644 index 000000000..e4c1620b5 --- /dev/null +++ b/tests/intsieve.java @@ -0,0 +1,52 @@ + +// Primzahlen sieben, Java-Version + +public class intsieve { + + static void sievenumber(int n, int[] no_prime, int p) { + int i; + for (i = p*2; i <= n; i += p) + no_prime[i] = 1; + } + + static void sieving(int n, int[] no_prime) { + int p; + for (p = 2; p <= n; p++) { + if (no_prime[p] != 0) sievenumber(n, no_prime, p); + } + } + + static public void main(String [] s) { + + int count=0; + int p; + + int n = Integer.parseInt (s[0]); + int times = Integer.parseInt (s[1]); + + int no_prime[] = new int[n+1]; + + System.out.print ("Start sieving primes from 2 to "); + System.out.print (n); + System.out.print (" for "); + System.out.print (times); + System.out.println (" times"); + + for (; times > 0; times--) { + for (p = 0; p < n+1; p++) + no_prime[p] = 0; + + sieving(n, no_prime); + + count = 0; + for (p = 2; p <= n; p++) + if (no_prime[p] != 0) count++; + } + + System.out.print (".... done, number of primes: "); + System.out.println (count); + } + + + } + \ No newline at end of file diff --git a/tests/jctest.java b/tests/jctest.java new file mode 100644 index 000000000..22093859c --- /dev/null +++ b/tests/jctest.java @@ -0,0 +1,1245 @@ +/************************* test/jctest.java ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Eine Klasse zum Testen (fast) aller JavaVM-Instruktionen + in verschiedenen Konstellationen. + + Die Ausgabe, die dieses Programm generiert, sollte bei allen + verschiedenen Java-Interpreter/Compiler-Systemen gleich + sein. Wenn nicht, dann ist wahrscheinlich eines der Systeme + fehlerhaft. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/12/03 + +*******************************************************************************/ + + +public class jctest implements jcinterface { + static int i1=77; + static long l1=123456789,l2=987654321,l3=-99999999999999L; + static int i2,i3=-100; + static float f1=0.1F,f2=0.2F,f3=0.3F; + static double d1=0.001,d2=0.002,d3=0.003; + static String s1,s2="der konstante String"; + + int n_i1,n_i2,n_i3; + long n_l1,n_l2,n_l3,n_l4; + float n_f1,n_f2,n_f3,n_f4; + int n_i4; + double n_d1,n_d2,n_d3,n_d4; + + + public static void main(String[] s) { + p ("=================== JavaVM - Tester ========================"); + + p ("------------------- test arguments"); + int i; + for (i=0; i 2"); break; + case 3: p ("-> 3"); break; + case 5: p ("-> 5"); break; + case 6: p ("-> 6"); break; + case 7: p ("-> 7"); break; + case 8: p ("-> 8"); break; + case 10: p ("-> 10"); break; + default: p ("default"); break; + } + } + + p ("------------------- test lookupswitch"); + + for (i = -5; i < 15; i++) { + switch (i) { + case 2: p ("-> 2"); break; + case 8: p ("-> 8"); break; + case 14: p ("-> 14"); break; + case -4: p ("-> -4"); break; + default: p ("default"); break; + } + } + } + + + // ****************** test type casts and array stores ********************* + + public static void testcasts() { + Object o = new Object(); + Object oi = new Integer(0); + Object[] oa = new Object [1]; + Object[] oia = new Integer[1]; + Integer i = new Integer(0); + Integer[] ia; + + p ("------------------- test casts"); + + try { + p ("type cast check: Integer = Object(Integer)"); + i = (Integer) oi; + p ("type cast check: Integer = Object"); + i = (Integer) o; + p ("error: class cast exception not thrown"); + } + catch (ClassCastException c) { + p ("exception: class cast"); + } + + try { + p ("type cast check: Integer[] = Object(Integer)[]"); + ia = (Integer[]) oia; + p ("type cast check: Integer[] = Object[]"); + ia = (Integer[]) oa; + p ("error: class cast exception not thrown"); + } + catch (ClassCastException c) { + p ("exception: class cast"); + } + + try { + p ("array store check: Object(Integer)[0] = Integer"); + oia[0] = i; + p ("array store check: Object(Integer)[0] = Object"); + oia[0] = o; + p ("error: array store exception not thrown"); + } + catch (ArrayStoreException c) { + p ("exception: array store"); + } + } + + + // ****************** test special null pointers *************************** + + public static void testspecialnullpointers() { + int i = 0; + jctest c = null; + jcinterface f = null; + + p ("------------------- test special null pointers"); + + try { + p ("null pointer check: put field"); + c.n_i1 = 0; + p ("error: put field null pointer exception not thrown"); + } + catch (NullPointerException x) { + p ("exception: null pointer"); + } + + try { + p ("null pointer check: get field"); + i = c.n_i1; + p ("error: get field null pointer exception not thrown"); + } + catch (NullPointerException x) { + p ("exception: null pointer"); + } + + try { + p ("null pointer check: invokevirtual"); + c.p_nonstatic("invokevirtual"); + p ("error: invokevirtual null pointer exception not thrown"); + } + catch (NullPointerException x) { + p ("exception: null pointer"); + } + + try { + p ("null pointer check: invokeinterface"); + f.p_nonstatic("invokeinterface"); + p ("error: invokeinterface null pointer exception not thrown"); + } + catch (NullPointerException x) { + p ("exception: null pointer"); + } + + try { + p ("null pointer check: monitorenter"); + synchronized (c) { + p ("error: monitorenter null pointer exception not thrown"); + } + } + catch (NullPointerException x) { + p ("exception: null pointer"); + } + } + + + // ************************ test array bounds ****************************** + + public static void testarraybounds(byte[] ba, int i) { + + p ("testarraybounds: " + (i - 10)); + ba[i-10] = 0; + p ("testarraybounds: " + (i - 5)); + ba[i-5] = 0; + p ("testarraybounds: " + (i)); + ba[i] = 0; + p ("testarraybounds: " + (i + 5)); + ba[i+5] = 0; + p ("testarraybounds: " + (i + 10)); + ba[i+10] = 0; + } + + + // ************************ test arrays ************************************ + + public static void testarrays() { + int i; + long l; + float f; + double d; + String s; + + p ("------------------- test byte arrays"); + + byte[] ba = null; + + try { + p ("null pointer check: byte array store"); + ba[1] = 0; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: byte array load"); + i = ba[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + try { + p ("negative array size check: byte array"); + ba = new byte [-2]; + p ("error: negative array size exception not thrown"); + } + catch (NegativeArraySizeException c) { + p ("exception: negative array size"); + } + + ba = new byte [100]; + + + try { + p ("array bound check: byte array store"); + ba[-1] = 0; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: byte array load"); + i = ba[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + try { + testarraybounds(ba, 5); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+5); + } + try { + testarraybounds(ba, 50); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+50); + } + try { + testarraybounds(ba, 100); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+100); + } + + try { + ba[-4] = 0; + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-4)); + } + try { + ba[-3] = 0; + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-3)); + } + for (i=-2; i<102; i++) { + try { + ba[i] = (byte) (i-50); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+i); + } + } + try { + ba[102] = 0; + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+102); + } + try { + ba[103] = 0; + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+103); + } + for (i=0; i<100; i++) p (ba[i]); + + + p ("-------- test short arrays"); + + short[] sa = null; + + try { + p ("null pointer check: short array store"); + sa[1] = 0; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: short array load"); + i = sa[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + sa = new short [100]; + + try { + p ("array bound check: short array store"); + sa[-1] = 0; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: short array load"); + i = sa[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + for (i=0; i<100; i++) sa[i] = (short) (i-50); + for (i=0; i<100; i++) p (sa[i]); + + + p ("-------- test int arrays"); + + int[] ia = null; + + try { + p ("null pointer check: int array store"); + ia[1] = 0; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: int array load"); + i = ia[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + ia = new int [50]; + + try { + p ("array bound check: int array store"); + ia[-1] = 0; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: int array load"); + i = ia[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + for (i=0; i<10; i++) ia[i] = (123456 + i); + for (i=0; i<10; i++) p (ia[i]); + + + + p ("-------- test long arrays"); + + long[] la = null; + + try { + p ("null pointer check: long array store"); + la[1] = 0; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: long array load"); + l = la[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + la = new long [10]; + + try { + p ("array bound check: long array store"); + la[-1] = 0; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: long array load"); + l = la[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + for (i=0; i<10; i++) la[i] = (1234567890123L + i); + for (i=0; i<10; i++) p (la[i]); + + + p ("-------- test char arrays"); + + char[] ca = null; + + try { + p ("null pointer check: char array store"); + ca[1] = 0; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: char array load"); + i = ca[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + ca = new char [50]; + + try { + p ("array bound check: char array store"); + ca[-1] = 0; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: char array load"); + i = ca[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + for (i=0; i<50; i++) ca[i] = (char) ('A' + i); + for (i=0; i<50; i++) p (ca[i]); + + p ("-------- test address arrays"); + + String[] sta = null; + + try { + p ("null pointer check: address array store"); + sta[1] = null; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + try { + p ("null pointer check: address array load"); + s = sta[1]; + p ("error: null pointer exception not thrown"); + } + catch (NullPointerException c) { + p ("exception: null pointer"); + } + + try { + p ("negative array size check: address array"); + sta = new String[-3]; + p ("error: negative array size exception not thrown"); + } + catch (NegativeArraySizeException c) { + p ("exception: negative array size"); + } + + sta = new String[5]; + + try { + p ("array bound check: address array store"); + sta[-1] = null; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + try { + p ("array bound check: address array load"); + s = sta[-1]; + p ("error: exception not thrown"); + } + catch (ArrayIndexOutOfBoundsException c) { + p ("exception: out of bounds: "+(-1)); + } + + for (i=0; i<5; i++) sta[i] = Integer.toString(i) + ". Zeile"; + for (i=0; i<5; i++) p (sta[i]); + + p ("-------- test multi dimensional arrays"); + + int [][][] iaaa = null; + + try { + p ("negative array size check: multi dimensional array"); + iaaa = new int[2][3][-4]; + p ("error: negative array size exception not thrown"); + } + catch (NegativeArraySizeException c) { + p ("exception: negative array size"); + } + + iaaa = new int[2][3][4]; + long [][][] laaa = new long[2][3][6]; + float [][][] faaa = new float[2][3][4]; + double [][][] daaa = new double[3][4][7]; + for (i=0; i<2; i++) { + int i2; for (i2=0; i2<3; i2++) { + int i3; for (i3=0; i3<4; i3++) { + iaaa[i][i2][i3] = i*i*i + i2*i2 + i3; + laaa[i][i2][i3] = i*i*i + i2*i2 + i3 + 7; + faaa[i][i2][i3] = i*i*i + i2*i2 + i3 + 0.4F; + daaa[i][i2][i3] = i*i*i + i2*i2 + i3 - 47.0001; + p (iaaa[i][i2][i3]); + p (laaa[i][i2][i3]); + p (faaa[i][i2][i3]); + p (daaa[i][i2][i3]); + } + } + } + + + + } + + + static public void testconst(int i, long l) { + p ("TESTCONST CALLED WITH ", i); + p (" AND ", l); + + if (!(i == (0))) p("not IF_ICMPEQ", (0)); + if (!(i != (0))) p("not IF_ICMPNE", (0)); + if (!(i < (0))) p("not IF_ICMPLT", (0)); + if (!(i <= (0))) p("not IF_ICMPLE", (0)); + if (!(i > (0))) p("not IF_ICMPGT", (0)); + if (!(i >= (0))) p("not IF_ICMPGE", (0)); + + if (!(l == (0))) p("not IF_LCMPEQ", (0)); + if (!(l != (0))) p("not IF_LCMPNE", (0)); + if (!(l < (0))) p("not IF_LCMPLT", (0)); + if (!(l <= (0))) p("not IF_LCMPLE", (0)); + if (!(l > (0))) p("not IF_LCMPGT", (0)); + if (!(l >= (0))) p("not IF_LCMPGE", (0)); + + p("IADDCONST: ", i + (-1)); + p("ISUBCONST: ", i - (-1)); + p("IMULCONST: ", i * (-1)); + p("ISHLCONST: ", i << (-1)); + p("ISHRCONST: ", i >> (-1)); + p("IUSHRCONST: ", i >>> (-1)); + p("IANDCONST: ", i & (-1)); + p("IORCONST: ", i | (-1)); + p("IXORCONST: ", i ^ (-1)); + + if (!(i == (-1))) p("not IF_ICMPEQ", (-1)); + if (!(i != (-1))) p("not IF_ICMPNE", (-1)); + if (!(i < (-1))) p("not IF_ICMPLT", (-1)); + if (!(i <= (-1))) p("not IF_ICMPLE", (-1)); + if (!(i > (-1))) p("not IF_ICMPGT", (-1)); + if (!(i >= (-1))) p("not IF_ICMPGE", (-1)); + + p("LADDCONST: ", l + (-1)); + p("LSUBCONST: ", l - (-1)); + p("LMULCONST: ", l * (-1)); + p("LSHLCONST: ", l << (-1)); + p("LSHRCONST: ", l >> (-1)); + p("LUSHRCONST: ", l >>> (-1)); + p("LANDCONST: ", l & (-1)); + p("LORCONST: ", l | (-1)); + p("LXORCONST: ", l ^ (-1)); + + if (!(l == (-1))) p("not IF_LCMPEQ", (-1)); + if (!(l != (-1))) p("not IF_LCMPNE", (-1)); + if (!(l < (-1))) p("not IF_LCMPLT", (-1)); + if (!(l <= (-1))) p("not IF_LCMPLE", (-1)); + if (!(l > (-1))) p("not IF_LCMPGT", (-1)); + if (!(l >= (-1))) p("not IF_LCMPGE", (-1)); + + p("IADDCONST: ", i + (1)); + p("ISUBCONST: ", i - (1)); + p("IMULCONST: ", i * (1)); + p("ISHLCONST: ", i << (1)); + p("ISHRCONST: ", i >> (1)); + p("IUSHRCONST: ", i >>> (1)); + p("IANDCONST: ", i & (1)); + p("IORCONST: ", i | (1)); + p("IXORCONST: ", i ^ (1)); + + if (!(i == (1))) p("not IF_ICMPEQ", (1)); + if (!(i != (1))) p("not IF_ICMPNE", (1)); + if (!(i < (1))) p("not IF_ICMPLT", (1)); + if (!(i <= (1))) p("not IF_ICMPLE", (1)); + if (!(i > (1))) p("not IF_ICMPGT", (1)); + if (!(i >= (1))) p("not IF_ICMPGE", (1)); + + p("LADDCONST: ", l + (1)); + p("LSUBCONST: ", l - (1)); + p("LMULCONST: ", l * (1)); + p("LSHLCONST: ", l << (1)); + p("LSHRCONST: ", l >> (1)); + p("LUSHRCONST: ", l >>> (1)); + p("LANDCONST: ", l & (1)); + p("LORCONST: ", l | (1)); + p("LXORCONST: ", l ^ (1)); + + if (!(l == (1))) p("not IF_LCMPEQ", (1)); + if (!(l != (1))) p("not IF_LCMPNE", (1)); + if (!(l < (1))) p("not IF_LCMPLT", (1)); + if (!(l <= (1))) p("not IF_LCMPLE", (1)); + if (!(l > (1))) p("not IF_LCMPGT", (1)); + if (!(l >= (1))) p("not IF_LCMPGE", (1)); + + p("IADDCONST: ", i + (255)); + p("ISUBCONST: ", i - (255)); + p("IMULCONST: ", i * (255)); + p("ISHLCONST: ", i << (255)); + p("ISHRCONST: ", i >> (255)); + p("IUSHRCONST: ", i >>> (255)); + p("IANDCONST: ", i & (255)); + p("IORCONST: ", i | (255)); + p("IXORCONST: ", i ^ (255)); + + if (!(i == (255))) p("not IF_ICMPEQ", (255)); + if (!(i != (255))) p("not IF_ICMPNE", (255)); + if (!(i < (255))) p("not IF_ICMPLT", (255)); + if (!(i <= (255))) p("not IF_ICMPLE", (255)); + if (!(i > (255))) p("not IF_ICMPGT", (255)); + if (!(i >= (255))) p("not IF_ICMPGE", (255)); + + p("LADDCONST: ", l + (255)); + p("LSUBCONST: ", l - (255)); + p("LMULCONST: ", l * (255)); + p("LSHLCONST: ", l << (255)); + p("LSHRCONST: ", l >> (255)); + p("LUSHRCONST: ", l >>> (255)); + p("LANDCONST: ", l & (255)); + p("LORCONST: ", l | (255)); + p("LXORCONST: ", l ^ (255)); + + if (!(l == (255))) p("not IF_LCMPEQ", (255)); + if (!(l != (255))) p("not IF_LCMPNE", (255)); + if (!(l < (255))) p("not IF_LCMPLT", (255)); + if (!(l <= (255))) p("not IF_LCMPLE", (255)); + if (!(l > (255))) p("not IF_LCMPGT", (255)); + if (!(l >= (255))) p("not IF_LCMPGE", (255)); + + p("IADDCONST: ", i + (256)); + p("ISUBCONST: ", i - (256)); + p("IMULCONST: ", i * (256)); + p("ISHLCONST: ", i << (256)); + p("ISHRCONST: ", i >> (256)); + p("IUSHRCONST: ", i >>> (256)); + p("IANDCONST: ", i & (256)); + p("IORCONST: ", i | (256)); + p("IXORCONST: ", i ^ (256)); + + if (!(i == (256))) p("not IF_ICMPEQ", (256)); + if (!(i != (256))) p("not IF_ICMPNE", (256)); + if (!(i < (256))) p("not IF_ICMPLT", (256)); + if (!(i <= (256))) p("not IF_ICMPLE", (256)); + if (!(i > (256))) p("not IF_ICMPGT", (256)); + if (!(i >= (256))) p("not IF_ICMPGE", (256)); + + p("LADDCONST: ", l + (256)); + p("LSUBCONST: ", l - (256)); + p("LMULCONST: ", l * (256)); + p("LSHLCONST: ", l << (256)); + p("LSHRCONST: ", l >> (256)); + p("LUSHRCONST: ", l >>> (256)); + p("LANDCONST: ", l & (256)); + p("LORCONST: ", l | (256)); + p("LXORCONST: ", l ^ (256)); + + if (!(l == (256))) p("not IF_LCMPEQ", (256)); + if (!(l != (256))) p("not IF_LCMPNE", (256)); + if (!(l < (256))) p("not IF_LCMPLT", (256)); + if (!(l <= (256))) p("not IF_LCMPLE", (256)); + if (!(l > (256))) p("not IF_LCMPGT", (256)); + if (!(l >= (256))) p("not IF_LCMPGE", (256)); + + p("IADDCONST: ", i + (32767)); + p("ISUBCONST: ", i - (32767)); + p("IMULCONST: ", i * (32767)); + p("ISHLCONST: ", i << (32767)); + p("ISHRCONST: ", i >> (32767)); + p("IUSHRCONST: ", i >>> (32767)); + p("IANDCONST: ", i & (32767)); + p("IORCONST: ", i | (32767)); + p("IXORCONST: ", i ^ (32767)); + + if (!(i == (32767))) p("not IF_ICMPEQ", (32767)); + if (!(i != (32767))) p("not IF_ICMPNE", (32767)); + if (!(i < (32767))) p("not IF_ICMPLT", (32767)); + if (!(i <= (32767))) p("not IF_ICMPLE", (32767)); + if (!(i > (32767))) p("not IF_ICMPGT", (32767)); + if (!(i >= (32767))) p("not IF_ICMPGE", (32767)); + + p("LADDCONST: ", l + (32767)); + p("LSUBCONST: ", l - (32767)); + p("LMULCONST: ", l * (32767)); + p("LSHLCONST: ", l << (32767)); + p("LSHRCONST: ", l >> (32767)); + p("LUSHRCONST: ", l >>> (32767)); + p("LANDCONST: ", l & (32767)); + p("LORCONST: ", l | (32767)); + p("LXORCONST: ", l ^ (32767)); + + if (!(l == (32767))) p("not IF_LCMPEQ", (32767)); + if (!(l != (32767))) p("not IF_LCMPNE", (32767)); + if (!(l < (32767))) p("not IF_LCMPLT", (32767)); + if (!(l <= (32767))) p("not IF_LCMPLE", (32767)); + if (!(l > (32767))) p("not IF_LCMPGT", (32767)); + if (!(l >= (32767))) p("not IF_LCMPGE", (32767)); + + p("IADDCONST: ", i + (32768)); + p("ISUBCONST: ", i - (32768)); + p("IMULCONST: ", i * (32768)); + p("ISHLCONST: ", i << (32768)); + p("ISHRCONST: ", i >> (32768)); + p("IUSHRCONST: ", i >>> (32768)); + p("IANDCONST: ", i & (32768)); + p("IORCONST: ", i | (32768)); + p("IXORCONST: ", i ^ (32768)); + + if (!(i == (32768))) p("not IF_ICMPEQ", (32768)); + if (!(i != (32768))) p("not IF_ICMPNE", (32768)); + if (!(i < (32768))) p("not IF_ICMPLT", (32768)); + if (!(i <= (32768))) p("not IF_ICMPLE", (32768)); + if (!(i > (32768))) p("not IF_ICMPGT", (32768)); + if (!(i >= (32768))) p("not IF_ICMPGE", (32768)); + + p("LADDCONST: ", l + (32768)); + p("LSUBCONST: ", l - (32768)); + p("LMULCONST: ", l * (32768)); + p("LSHLCONST: ", l << (32768)); + p("LSHRCONST: ", l >> (32768)); + p("LUSHRCONST: ", l >>> (32768)); + p("LANDCONST: ", l & (32768)); + p("LORCONST: ", l | (32768)); + p("LXORCONST: ", l ^ (32768)); + + if (!(l == (32768))) p("not IF_LCMPEQ", (32768)); + if (!(l != (32768))) p("not IF_LCMPNE", (32768)); + if (!(l < (32768))) p("not IF_LCMPLT", (32768)); + if (!(l <= (32768))) p("not IF_LCMPLE", (32768)); + if (!(l > (32768))) p("not IF_LCMPGT", (32768)); + if (!(l >= (32768))) p("not IF_LCMPGE", (32768)); + + p("IADDCONST: ", i + (-32768)); + p("ISUBCONST: ", i - (-32768)); + p("IMULCONST: ", i * (-32768)); + p("ISHLCONST: ", i << (-32768)); + p("ISHRCONST: ", i >> (-32768)); + p("IUSHRCONST: ", i >>> (-32768)); + p("IANDCONST: ", i & (-32768)); + p("IORCONST: ", i | (-32768)); + p("IXORCONST: ", i ^ (-32768)); + + if (!(i == (-32768))) p("not IF_ICMPEQ", (-32768)); + if (!(i != (-32768))) p("not IF_ICMPNE", (-32768)); + if (!(i < (-32768))) p("not IF_ICMPLT", (-32768)); + if (!(i <= (-32768))) p("not IF_ICMPLE", (-32768)); + if (!(i > (-32768))) p("not IF_ICMPGT", (-32768)); + if (!(i >= (-32768))) p("not IF_ICMPGE", (-32768)); + + p("LADDCONST: ", l + (-32768)); + p("LSUBCONST: ", l - (-32768)); + p("LMULCONST: ", l * (-32768)); + p("LSHLCONST: ", l << (-32768)); + p("LSHRCONST: ", l >> (-32768)); + p("LUSHRCONST: ", l >>> (-32768)); + p("LANDCONST: ", l & (-32768)); + p("LORCONST: ", l | (-32768)); + p("LXORCONST: ", l ^ (-32768)); + + if (!(l == (-32768))) p("not IF_LCMPEQ", (-32768)); + if (!(l != (-32768))) p("not IF_LCMPNE", (-32768)); + if (!(l < (-32768))) p("not IF_LCMPLT", (-32768)); + if (!(l <= (-32768))) p("not IF_LCMPLE", (-32768)); + if (!(l > (-32768))) p("not IF_LCMPGT", (-32768)); + if (!(l >= (-32768))) p("not IF_LCMPGE", (-32768)); + + p("IADDCONST: ", i + (-32769)); + p("ISUBCONST: ", i - (-32769)); + p("IMULCONST: ", i * (-32769)); + p("ISHLCONST: ", i << (-32769)); + p("ISHRCONST: ", i >> (-32769)); + p("IUSHRCONST: ", i >>> (-32769)); + p("IANDCONST: ", i & (-32769)); + p("IORCONST: ", i | (-32769)); + p("IXORCONST: ", i ^ (-32769)); + + if (!(i == (-32769))) p("not IF_ICMPEQ", (-32769)); + if (!(i != (-32769))) p("not IF_ICMPNE", (-32769)); + if (!(i < (-32769))) p("not IF_ICMPLT", (-32769)); + if (!(i <= (-32769))) p("not IF_ICMPLE", (-32769)); + if (!(i > (-32769))) p("not IF_ICMPGT", (-32769)); + if (!(i >= (-32769))) p("not IF_ICMPGE", (-32769)); + + p("LADDCONST: ", l + (-32769)); + p("LSUBCONST: ", l - (-32769)); + p("LMULCONST: ", l * (-32769)); + p("LSHLCONST: ", l << (-32769)); + p("LSHRCONST: ", l >> (-32769)); + p("LUSHRCONST: ", l >>> (-32769)); + p("LANDCONST: ", l & (-32769)); + p("LORCONST: ", l | (-32769)); + p("LXORCONST: ", l ^ (-32769)); + + if (!(l == (-32769))) p("not IF_LCMPEQ", (-32769)); + if (!(l != (-32769))) p("not IF_LCMPNE", (-32769)); + if (!(l < (-32769))) p("not IF_LCMPLT", (-32769)); + if (!(l <= (-32769))) p("not IF_LCMPLE", (-32769)); + if (!(l > (-32769))) p("not IF_LCMPGT", (-32769)); + if (!(l >= (-32769))) p("not IF_LCMPGE", (-32769)); + } + + static public void testint(int a, int b) { + p ("TESTINT CALLED WITH ", a); + p (" AND ", b); + + p("IADD: ", a+b); + p("ISUB: ", a-b); + p("IMUL: ", a*b); + try { p("IDIV: ", a/b); } + catch (ArithmeticException e) { p("divison by zero"); } + try { p("IREM: ", a%b); } + catch (ArithmeticException e) { p("divison by zero"); } + p("INEG: ", -a); + p("ISHL: ", a<>b); + p("IUSHR: ", a>>>b); + p("IAND: ", a & b); + p("IOR: ", a | b); + p("IXOR: ", a ^ b); + + p("I2L: ", (long) a); + p("I2F: ", (float) a); + p("I2D: ", (double) a); + p("INT2BYTE: ", (byte) a); + p("INT2CHAR: ", (char) a); + p("INT2SHORT: ", (short) a); + + if (!(a==0)) p("not IFEQ"); + if (!(a!=0)) p("not IFNE"); + if (!(a<0)) p("not IFLT"); + if (!(a<=0)) p("not IFLE"); + if (!(a>0)) p("not IFGT"); + if (!(a>=0)) p("not IFGE"); + + if (!(a==b)) p("not IF_ICMPEQ"); + if (!(a!=b)) p("not IF_ICMPNE"); + if (!(ab)) p("not IF_ICMPGT"); + if (!(a>=b)) p("not IF_ICMPGE"); + + } + + static public void testlong(long a, long b) { + p ("TESTLONG called with ", a); + p (" AND ", b); + + p("LADD: ", a + b); + p("LSUB: ", a - b); + p("LMUL: ", a * b); + try { p("LDIV: ", a / b); } + catch (ArithmeticException e) { p("divison by zero"); } + try { p("LREM: ", a % b); } + catch (ArithmeticException e) { p("divison by zero"); } + p("LNEG: ", -a); + p("LSHL: ", a << b); + p("LSHR: ", a >> b); + p("LUSHR: ", a >>>b); + p("LAND: ", a & b); + p("LOR: ", a | b); + p("LXOR: ", a ^ b); + + p("L2I: ", (int) a); + p("L2F: ", (float) a); + p("L2D: ", (double) a); + + p("LCMP a == b : ", a == b); + p("LCMP a != b : ", a != b); + p("LCMP a < b : ", a < b); + p("LCMP a <= b : ", a <= b); + p("LCMP a > b : ", a > b); + p("LCMP a >= b : ", a >= b); + + if ((a==b)) p("not IF_LCMPEQ"); + if ((a!=b)) p("not IF_LCMPNE"); + if ((ab)) p("not IF_LCMPGT"); + if ((a>=b)) p("not IF_LCMPGE"); + } + + static public void testfloat(float a, float b) { + p ("TESTFLOAT called with ", a); + p (" AND ", b); + + p("FADD: ", a+b); + p("FSUB: ", a-b); + p("FMUL: ", a*b); + p("FDIV: ", a/b); + p("FREM: ", a%b); + + p("F2I: ", (int) a); + p("F2L: ", (long) a); + p("F2D: ", (double) a); + + if ((a==b)) p("FCMP a=b"); + if ((a!=b)) p("FCMP a!=b"); + if ((ab)) p("FCMP a>b"); + if ((a>=b)) p("FCMP a>=b"); + } + + static public void testdouble(double a, double b) { + p ("TESTDOUBLE called with ", a); + p (" AND ", b); + + p("DADD: ", a+b); + p("DSUB: ", a-b); + p("DMUL: ", a*b); + p("DDIV: ", a/b); + p("DREM: ", a%b); + + p("D2I: ", (int) a); + p("D2L: ", (long) a); + p("D2F: ", (float) a); + + if ((a==b)) p("DCMP a=b"); + if ((a!=b)) p("DCMP a!=b"); + if ((ab)) p("DCMP a>b"); + if ((a>=b)) p("DCMP a>=b"); + } + + + // ********************* output methods **************************** + + public static int linenum = 0; + public static void pnl() { + System.out.println (); + System.out.print (linenum); + System.out.print (". "); + linenum++; + } + + public static void p(String a) { System.out.print(a); pnl(); } + public static void p(boolean a) {System.out.print(a); + pnl(); } + public static void p(int a) { System.out.print ("int: "); + System.out.print(a); + pnl(); } + public static void p(long a) { System.out.print ("long: "); + System.out.print(a); + pnl(); } + public static void p(short a) { System.out.print ("short: "); + System.out.print(a); + pnl(); } + public static void p(byte a) { System.out.print ("byte: "); + System.out.print(a); + pnl(); } + public static void p(char a) { System.out.print ("char: "); + System.out.print((int)a); + pnl(); } + public static void p(float a) { System.out.print ("float: "); + System.out.print ( java.lang.Float.floatToIntBits(a) ); + pnl(); } + public static void p(double a) { System.out.print ("double: "); + System.out.print( java.lang.Double.doubleToLongBits(a) ); + pnl(); } + + public static void p(String s,boolean i) { + System.out.print(s); p(i); + } + public static void p(String s,int i) { + System.out.print(s); p(i); + } + public static void p(String s,byte i) { + System.out.print(s); p(i); + } + public static void p(String s,char i) { + System.out.print(s); p(i); + } + public static void p(String s,short i) { + System.out.print(s); p(i); + } + public static void p(String s,long l) { + System.out.print(s); p(l); + } + public static void p(String s,float f) { + System.out.print(s); p(f); + } + public static void p(String s,double d) { + System.out.print(s); p(d); + } + + + + + // methods for testing interface and method calls + + public void jctest() { p (" wird aktiviert"); }; + public void p_manyparam (int p_i1,int p_i2, + int p_i3, int p_i4, + long p_l1,long p_l2, + long p_l3,long p_l4, + float p_f1, float p_f2, + float p_f3, float p_f4, + double p_d1, double p_d2, + double p_d3, double p_d4) { + n_i1 = p_i1; + n_i2 = p_i2; + n_i3 = p_i3; + n_i4 = p_i4; + n_l1 = p_l1; + n_l2 = p_l2; + n_l3 = p_l3; + n_l4 = p_l4; + n_f1 = p_f1; + n_f2 = p_f2; + n_f3 = p_f3; + n_f4 = p_f4; + n_d1 = p_d1; + n_d2 = p_d2; + n_d3 = p_d3; + n_d4 = p_d4; + } + + public void p_nonstatic (String a) { + p(a); + p(n_i1); + p(n_i2); + p(n_i3); + p(n_i4); + p(n_l1); + p(n_l2); + p(n_l3); + p(n_l4); + p(n_f1); + p(n_f2); + p(n_f3); + p(n_f4); + p(n_d1); + p(n_d2); + p(n_d3); + p(n_d4); + + } + + } + + +interface jcinterface { + public void p_nonstatic (String a); + } + + diff --git a/tests/leaf.java b/tests/leaf.java new file mode 100644 index 000000000..833a2263a --- /dev/null +++ b/tests/leaf.java @@ -0,0 +1,13 @@ + +public class leaf { + + public static int makesum (int a, int b, int c) { + return a+b+c; + } + + public static void main (String[] s) { + System.out.println (makesum (1,2,3) ); + } + + +} diff --git a/tests/longtest.java b/tests/longtest.java new file mode 100644 index 000000000..29abf6ea1 --- /dev/null +++ b/tests/longtest.java @@ -0,0 +1,8 @@ + +public class longtest { + public static void main(String []s) { + System.out.print ("juhu: "); + System.out.println ( (long) 0x12345678901234L ); + } + +} diff --git a/tests/main.java b/tests/main.java new file mode 100644 index 000000000..bc253b684 --- /dev/null +++ b/tests/main.java @@ -0,0 +1,44 @@ + +public class main { + + public static void main(String [] s) { + System.out.println ("Ausgabe startet"); + int i; + + float fa[] = new float[5]; + for (i=0; i<5; i++) fa[i]=47.20F + (float)i; + for (i=0; i<5; i++) System.out.println(fa[i]); + + double da[] = new double[5]; + for (i=0; i<5; i++) da[i]=99.40F + (double)i; + for (i=0; i<5; i++) System.out.println(da[i]); + + long la[] = new long[5]; + for (i=0; i<5; i++) la[i]=11 + i; + for (i=0; i<5; i++) System.out.println(la[i]); + + int ia[] = new int[5]; + for (i=0; i<5; i++) ia[i]=99 + i; + for (i=0; i<5; i++) System.out.println(ia[i]); + + short sa[] = new short[5]; + for (i=0; i<5; i++) sa[i]=(short)(77 + i); + for (i=0; i<5; i++) System.out.println(sa[i]); + + byte ba[] = new byte[5]; + for (i=0; i<5; i++) ba[i]=(byte)(66 + i); + for (i=0; i<5; i++) System.out.println(ba[i]); + + boolean boa[] = new boolean[5]; + for (i=0; i<5; i++) boa[i]=(i<2); + for (i=0; i<5; i++) System.out.println(boa[i]); + + char ca[] = new char[5]; + for (i=0; i<5; i++) ca[i]=(char)('A' + i); + for (i=0; i<5; i++) System.out.println(ca[i]); + + + } + } + + \ No newline at end of file diff --git a/tests/mem.java b/tests/mem.java new file mode 100644 index 000000000..627931a71 --- /dev/null +++ b/tests/mem.java @@ -0,0 +1,28 @@ + +public class mem { + public int dummy; + + public static void main(String[] s) { + int i; + + for (i=0; i<100000000; i++) { + try { + byte[] b = new byte[10000]; + b[0]=17; + } + catch (java.lang.Throwable c) { + System.out.print ("Out of mem after "); + System.out.print (i); + System.out.println (" allocations."); + } + finally { + System.out.println ("OK"); + } + } + + + } + + + } + \ No newline at end of file diff --git a/tests/memtest.java b/tests/memtest.java new file mode 100644 index 000000000..7f9fab71c --- /dev/null +++ b/tests/memtest.java @@ -0,0 +1,25 @@ +public class memtest { + public memtest next; + + public static memtest t; + + public memtest (memtest n) { next = n; } + public memtest () { }; + + public static void main (String[] s) { + int i; + + t = new memtest(new memtest(new memtest())); + char c[][] = new char[100][10]; + + for (i=0; i<100; i++) { + System.out.print (i); + System.out.println (". Objekt angelegt"); + memtest m = new memtest(); + } + + } + + } + + \ No newline at end of file diff --git a/tests/n.java b/tests/n.java new file mode 100644 index 000000000..e2ea20566 --- /dev/null +++ b/tests/n.java @@ -0,0 +1,7 @@ + +public class n implements a { + public void do_a () { }; + public void do_a2 () { }; + public void do_b () { }; + } + \ No newline at end of file diff --git a/tests/nan.java b/tests/nan.java new file mode 100644 index 000000000..879614b67 --- /dev/null +++ b/tests/nan.java @@ -0,0 +1,11 @@ +public class nan +{ + public static void main(String[] s) { + double a,b,c; + a = -1; + b = 0; + c = a/b; + + System.out.println (Long.toString(Double.doubleToLongBits(c)>>>4, 16) ); + } + } diff --git a/tests/prop.java b/tests/prop.java new file mode 100644 index 000000000..549e109fa --- /dev/null +++ b/tests/prop.java @@ -0,0 +1,5 @@ +public class prop { + public static void main(String [] s) { + System.getProperties().save (System.out, "alle properties:"); + } + } diff --git a/tests/scribble.java b/tests/scribble.java new file mode 100644 index 000000000..21dfac65a --- /dev/null +++ b/tests/scribble.java @@ -0,0 +1,29 @@ +import java.applet.*; +import java.awt.*; + +public class scribble extends Applet { + private int last_x=0; + private int last_y=0; + + + public void init() + { + this.setBackground(Color.white); + } + + + public boolean mouseDown(Event e, int x, int y) + { + last_x = x; last_y=y; + return true; + } + + public boolean mouseDrag(Event e, int x, int y) + { + Graphics g = getGraphics(); + g.setColor (Color.black); + g.drawLine(last_x,last_y,x,y); + last_x=x; last_y=y; + return true; + } +} diff --git a/tests/sieve.java b/tests/sieve.java new file mode 100644 index 000000000..cc8cca3af --- /dev/null +++ b/tests/sieve.java @@ -0,0 +1,50 @@ + +// Primzahlen sieben, Java-Version + +public class sieve { + + static void sievenumber(int n, boolean[] no_prime, int p) { + int i; + for (i=p*2; i<=n; i+=p) no_prime[i] = true; + } + + static void sieving(int n, boolean[] no_prime) { + int p; + for (p=2; p<=n; p++) { + if (!no_prime[p]) sievenumber(n,no_prime,p); + } + } + + static public void main(String [] s) { + + int count=0; + int p; + + int n = Integer.parseInt (s[0]); + int times = Integer.parseInt (s[1]); + + boolean no_prime[] = new boolean[n+1]; + + System.out.print ("Start sieving primes from 2 to "); + System.out.print (n); + System.out.print (" for "); + System.out.print (times); + System.out.println (" times"); + + for (; times>0; times--) { + for (p=0; p 0; i -= inc) { + s1 += inc; + s2 -= inc; + } + + System.out.print (".... done, sum: "); + System.out.println (s1); + System.out.println (s2); + } + + + } + \ No newline at end of file diff --git a/tests/suml.java b/tests/suml.java new file mode 100644 index 000000000..00437f87b --- /dev/null +++ b/tests/suml.java @@ -0,0 +1,25 @@ + +// Zahlen summieren, Java Version + +public class suml { + + + static public void main(String [] arg) { + + long s1 = 0, s2 = 0; + long i = Integer.parseInt (arg[0]); + + + for (; i > 0; i--) { + s1++; + s2--; + } + + System.out.print (".... done, sum: "); + System.out.print (s1); + System.out.println (s2); + } + + + } + \ No newline at end of file diff --git a/tests/sumlempty.java b/tests/sumlempty.java new file mode 100644 index 000000000..accf4eb0c --- /dev/null +++ b/tests/sumlempty.java @@ -0,0 +1,21 @@ + +// Zahlen summieren, Java Version + +public class sumlempty { + + + static public void main(String [] arg) { + + long i = Long.parseLong (arg[0]); + + + for (; i > 0; i--) { + } + + System.out.print (".... done, sum: "); + System.out.println (i); + } + + + } + \ No newline at end of file diff --git a/tests/t.java b/tests/t.java new file mode 100644 index 000000000..8fa588e7e --- /dev/null +++ b/tests/t.java @@ -0,0 +1,43 @@ + +public class t { + public static void main(String [] s) { + ausgeber m1 = new m(4711); + float a=(float)7.5,b=(float)3.2; + double ad=5.3,bd=2.1; + + int i; for (i=0; i=width) width=c+1; + if (l>=height) height=l+1; + } + c++; + } + } + } + } catch (Throwable e) { }; + + output.println ("------------------------------------------------------"); + + for (c=width-1; c>=0; c--) { + for (l=0; l, 1996. + */ + +#include +#include + +#include "thread.h" +#include "locks.h" + +#include "../tables.h" +#include "../native.h" +#include "../loader.h" + +static classinfo *class_java_lang_IllegalMonitorStateException; + +#if 1 +#define DBG(s) +#else +#define DBG(s) s +#endif + +extern thread* currentThread; + +#if defined(USE_INTERNAL_THREADS) + +mutexHashEntry *mutexHashTable; +int mutexHashTableSize; +long mutexHashMask; + +mutexHashEntry *mutexOverflowTable; +int mutexOverflowTableSize; +mutexHashEntry *firstFreeOverflowEntry = 0; + +conditionHashEntry *conditionHashTable; +int conditionHashTableSize; +long conditionHashMask; + +/* + * Init the tables. + */ +void +initLocks (void) +{ + int i; + + mutexHashTableSize = MUTEX_HASH_TABLE_SIZE; + mutexHashTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) * mutexHashTableSize); + mutexHashMask = (mutexHashTableSize - 1) << 3; + + for (i = 0; i < mutexHashTableSize; ++i) + { + mutexHashTable[i].object = 0; + mutexHashTable[i].mutex.holder = 0; + mutexHashTable[i].mutex.count = 0; + mutexHashTable[i].mutex.muxWaiters = 0; + mutexHashTable[i].conditionCount = 0; + mutexHashTable[i].next = 0; + } + + mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE; + mutexOverflowTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) + * mutexOverflowTableSize); + + firstFreeOverflowEntry = &mutexOverflowTable[0]; + + for (i = 0; i < mutexOverflowTableSize; ++i) + { + mutexOverflowTable[i].object = 0; + mutexOverflowTable[i].mutex.holder = 0; + mutexOverflowTable[i].mutex.count = 0; + mutexOverflowTable[i].mutex.muxWaiters = 0; + mutexOverflowTable[i].conditionCount = 0; + mutexOverflowTable[i].next = &mutexOverflowTable[i + 1]; + } + mutexOverflowTable[i - 1].next = 0; + + conditionHashTableSize = CONDITION_HASH_TABLE_SIZE; + conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry) + * conditionHashTableSize); + conditionHashMask = (conditionHashTableSize - 1) << 3; + + for (i = 0; i < conditionHashTableSize; ++i) + { + conditionHashTable[i].object = 0; + conditionHashTable[i].condition.cvWaiters = 0; + conditionHashTable[i].condition.mux = 0; + } + + /* Load exception classes */ + class_java_lang_IllegalMonitorStateException = + loader_load(unicode_new_char("java/lang/IllegalMonitorStateException")); +} + +/* + * Reorders part of the condition hash table. Must be called after an entry has been deleted. + */ +void +reorderConditionHashTable (int begin) +{ + while (conditionHashTable[begin].object != 0) + { + int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object); + + if (hashValue != begin) + { + while (conditionHashTable[hashValue].object != 0) + { + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + if (hashValue == begin) + break; + } + if (hashValue != begin) + { + conditionHashTable[hashValue] = conditionHashTable[begin]; + conditionHashTable[begin].object = 0; + conditionHashTable[begin].condition.cvWaiters = 0; + conditionHashTable[begin].condition.mux = 0; + } + } + + begin = CONDITION_HASH_SUCCESSOR(begin); + } +} + +/* + * Looks up an entry in the condition hash table. + */ +iCv* +conditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != object + && conditionHashTable[hashValue].object != 0) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + if (conditionHashTable[hashValue].object == 0) + { + intsRestore(); + return 0; + } + + intsRestore(); + return &conditionHashTable[hashValue].condition; +} + +/* + * Adds a new entry in the condition hash table and returns a pointer to the condition + */ +iCv* +addConditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != 0) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + conditionHashTable[hashValue].object = object; + + intsRestore(); + + return &conditionHashTable[hashValue].condition; +} + +/* + * Removes an entry from the condition hash table. + */ +void +removeConditionForObject (java_objectheader *object) +{ + int hashValue; + + intsDisable(); + + hashValue = CONDITION_HASH_VALUE(object); + while (conditionHashTable[hashValue].object != object) + hashValue = CONDITION_HASH_SUCCESSOR(hashValue); + + conditionHashTable[hashValue].object = 0; + conditionHashTable[hashValue].condition.cvWaiters = 0; + conditionHashTable[hashValue].condition.mux = 0; + + reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue)); + + intsRestore(); +} + +/* + * Returns the mutex entry for the specified object and increments its conditionCount. + */ +mutexHashEntry* +conditionLockedMutexForObject (java_objectheader *object) +{ + int hashValue; + mutexHashEntry *entry; + + assert(object != 0); + + intsDisable(); + + hashValue = MUTEX_HASH_VALUE(object); + entry = &mutexHashTable[hashValue]; + + if (entry->object != 0) + { + if (entry->mutex.count == 0 && entry->conditionCount == 0) + { + entry->object = 0; + entry->mutex.holder = 0; + entry->mutex.count = 0; + entry->mutex.muxWaiters = 0; + } + else + { + while (entry->next != 0 && entry->object != object) + entry = entry->next; + + if (entry->object != object) + { + entry->next = firstFreeOverflowEntry; + firstFreeOverflowEntry = firstFreeOverflowEntry->next; + + entry = entry->next; + entry->object = 0; + entry->next = 0; + assert(entry->conditionCount == 0); + } + } + } + + if (entry->object == 0) + entry->object = object; + + ++entry->conditionCount; + + intsRestore(); + + return entry; +} + +/* + * Wait for the condition of an object to be signalled + */ +void +wait_cond_for_object (java_objectheader *obj, s8 time) +{ + iCv *condition; + mutexHashEntry *mutexEntry; + + intsDisable(); + + mutexEntry = conditionLockedMutexForObject(obj); + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); ); + + internal_wait_cond(&mutexEntry->mutex, condition, time); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); + --mutexEntry->conditionCount; + + intsRestore(); +} + +/* + * Signal the condition of an object + */ +void +signal_cond_for_object (java_objectheader *obj) +{ + iCv *condition; + + intsDisable(); + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); ); + + internal_signal_cond(condition); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); + + intsRestore(); +} + +/* + * Broadcast the condition of an object. + */ +void +broadcast_cond_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_broadcast_cond_for_object(obj); + intsRestore(); +} + +/* + * Internal: Broadcast the condition of an object. + */ +void +internal_broadcast_cond_for_object (java_objectheader *obj) +{ + iCv *condition; + + condition = conditionForObject(obj); + if (condition == 0) + condition = addConditionForObject(obj); + + internal_broadcast_cond(condition); + + if (condition->cvWaiters == 0 && condition->mux == 0) + removeConditionForObject(obj); +} + +/* + * Lock a mutex. + */ +void +lock_mutex (iMux *mux) +{ + intsDisable(); + internal_lock_mutex(mux); + intsRestore(); +} + +/* + * Lock the mutex for an object. + */ +void +lock_mutex_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_lock_mutex_for_object(obj); + intsRestore(); +} + +/* + * Unlock a mutex. + */ +void +unlock_mutex (iMux *mux) +{ + intsDisable(); + internal_unlock_mutex(mux); + intsRestore(); +} + +/* + * Unlock the mutex for an object. + */ +void +unlock_mutex_for_object (java_objectheader *obj) +{ + intsDisable(); + internal_unlock_mutex_for_object(obj); + intsRestore(); +} + +/* + * Wait on a condition variable. + */ +void +wait_cond (iMux *mux, iCv *cond, s8 timeout) +{ + intsDisable(); + internal_wait_cond(mux, cond, timeout); + intsRestore(); +} + +/* + * Signal a condition variable. + */ +void +signal_cond (iCv *cond) +{ + intsDisable(); + internal_signal_cond(cond); + intsRestore(); +} + +/* + * Broadcast a condition variable. + */ +void +broadcast_cond (iCv *cond) +{ + intsDisable(); + internal_broadcast_cond(cond); + intsRestore(); +} + +/* + * Internal: Lock a mutex. + */ +void +internal_lock_mutex(iMux* mux) +{ + assert(blockInts == 1); + + if (mux->holder == 0) + { + mux->holder = currentThread; + mux->count = 1; + DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); ) + } + else if (mux->holder == currentThread) + { + mux->count++; + } + else + { + while (mux->holder != 0) + { + suspendOnQThread(currentThread, &mux->muxWaiters); + } + mux->holder = currentThread; + mux->count = 1; + } +} + +/* + * Internal: Release a mutex. + */ +void +internal_unlock_mutex(iMux* mux) +{ + thread* tid; + + assert(blockInts == 1); + + assert(mux->holder == currentThread); + + mux->count--; + if (mux->count == 0) + { + mux->holder = 0; + if (mux->muxWaiters != 0) + { + tid = mux->muxWaiters; + mux->muxWaiters = tid->next; + iresumeThread(tid); + } + } +} + +/* + * Internal: Wait on a conditional variable. + * (timeout currently ignored) + */ +void +internal_wait_cond(iMux* mux, iCv* cv, s8 timeout) +{ + int count; + thread* tid; + + DBG( fprintf(stderr, "waiting on %p\n", cv); ); + + if (mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + count = mux->count; + mux->holder = 0; + mux->count = 0; + cv->mux = mux; + + /* If there's anyone waiting here, wake them up */ + if (mux->muxWaiters != 0) { + tid = mux->muxWaiters; + mux->muxWaiters = tid->next; + iresumeThread(tid); + } + + /* Suspend, and keep suspended until I re-get the lock */ + suspendOnQThread(currentThread, &cv->cvWaiters); + while (mux->holder != 0) { + DBG( fprintf(stderr, "woke up\n"); ); + suspendOnQThread(currentThread, &mux->muxWaiters); + } + + mux->holder = currentThread; + mux->count = count; +} + +/* + * Internal: Wake one thread on a conditional variable. + */ +void +internal_signal_cond (iCv* cv) +{ + thread* tid; + + DBG( fprintf(stderr, "signalling on %p\n", cv); ); + + /* If 'mux' isn't set then we've never waited on this object. */ + if (cv->mux == 0) { + return; + } + + if (cv->mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + /* Remove one thread from cv list */ + if (cv->cvWaiters != 0) { + DBG( fprintf(stderr, "releasing a waiter\n"); ); + + tid = cv->cvWaiters; + cv->cvWaiters = tid->next; + + /* Place it on mux list */ + tid->next = cv->mux->muxWaiters; + cv->mux->muxWaiters = tid; + } +} + +/* + * Internal: Wake all threads on a conditional variable. + */ +void +internal_broadcast_cond (iCv* cv) +{ + thread** tidp; + + /* If 'mux' isn't set then we've never waited on this object. */ + if (cv->mux == 0) { + return; + } + + if (cv->mux->holder != currentThread) { + exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException); + } + + assert(blockInts == 1); + + /* Find the end of the cv list */ + if (cv->cvWaiters) { + for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next) + ; + + /* Place entire cv list on mux list */ + (*tidp) = cv->mux->muxWaiters; + cv->mux->muxWaiters = cv->cvWaiters; + cv->cvWaiters = 0; + } +} + +#endif diff --git a/threads/locks.h b/threads/locks.h new file mode 100644 index 000000000..e5224677e --- /dev/null +++ b/threads/locks.h @@ -0,0 +1,141 @@ +/* + * locks.h + * Manage locking system + * This include the mutex's and cv's. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#ifndef __locks_h +#define __locks_h + +#ifdef USE_THREADS + +#include "../global.h" +#include "sysdep/defines.h" + +#define WAITFOREVER -1 + +#if defined(USE_INTERNAL_THREADS) + +struct _thread; + +typedef struct _iMux { + struct _thread *holder; + int count; + struct _thread *muxWaiters; +} iMux; + +typedef struct _iCv { + struct _thread* cvWaiters; + struct _iMux* mux; +} iCv; + +#define MAX_MUTEXES 256 + +typedef struct _mutexHashEntry +{ + java_objectheader *object; + iMux mutex; + struct _mutexHashEntry *next; + int conditionCount; +} mutexHashEntry; + +#define MUTEX_HASH_TRASH_BITS 3 +#define MUTEX_HASH_SIGN_BITS 10 + +#define MUTEX_HASH_TABLE_SIZE 1024 +#define MUTEX_OVERFLOW_TABLE_SIZE 1024 +/* +#define MAX_MUTEX_HASH_TABLE_SIZE 65536 +*/ + +/* +#define MUTEX_USE_THRESHOLD 1024 +*/ + +extern long mutexHashMask; +extern int mutexHashTableSize; +extern mutexHashEntry *mutexHashTable; + +extern mutexHashEntry *mutexOverflowTable; +extern int mutexOverflowTableSize; +extern mutexHashEntry *firstFreeOverflowEntry; + +#define MUTEX_HASH_MASK ((MUTEX_HASH_TABLE_SIZE - 1) << 3) + +#if 0 +#define MUTEX_HASH_VALUE(a) ((((long)(a)) & MUTEX_HASH_MASK) >> MUTEX_HASH_TRASH_BITS) +#else +#define MUTEX_HASH_VALUE(a) (( (((long)(a)) ^ ((long)(a) >> MUTEX_HASH_SIGN_BITS)) & mutexHashMask) >> MUTEX_HASH_TRASH_BITS) +#endif +#define MUTEX_HASH_SUCCESSOR(h) (((h) + 7) & (mutexHashTableSize - 1)) + +typedef struct _conditionHashEntry +{ + java_objectheader *object; + iCv condition; +} conditionHashEntry; + +#define CONDITION_HASH_TABLE_SIZE 1024 + +#define CONDITION_HASH_VALUE(a) ((((long)(a)) & conditionHashMask) >> 3) +#define CONDITION_HASH_SUCCESSOR(h) (((h) + 7) & (conditionHashTableSize - 1)) + +typedef struct +{ + bool free; + java_objectheader *object; + iMux mutex; + iCv condition; +} object_mutex; + +extern void initLocks (void); + +mutexHashEntry* conditionLockedMutexForObject (java_objectheader *object); + +void reorderConditionHashTable (int begin); +iCv* conditionForObject (java_objectheader *object); +iCv* addConditionForObject (java_objectheader *object); +void removeConditionForObject (java_objectheader *object); + +/* + * use these functions only outside critical sections (intsEnable/intsRestore). + */ + +void signal_cond_for_object (java_objectheader *obj); +void broadcast_cond_for_object (java_objectheader *obj); +void wait_cond_for_object (java_objectheader *obj, s8 time); +void lock_mutex_for_object (java_objectheader *obj); +void unlock_mutex_for_object (java_objectheader *obj); + +void lock_mutex (iMux*); +void unlock_mutex (iMux*); +void wait_cond (iMux*, iCv*, s8); +void signal_cond (iCv*); +void broadcast_cond (iCv*); + +/* + * use these internal functions only in critical sections. blockInts must be exactly + * 1. + */ +void internal_lock_mutex (iMux*); +void internal_unlock_mutex (iMux*); +void internal_wait_cond (iMux*, iCv*, s8); +void internal_signal_cond (iCv*); +void internal_broadcast_cond (iCv*); + +void internal_lock_mutex_for_object (java_objectheader *obj); +void internal_unlock_mutex_for_object (java_objectheader *obj); +void internal_broadcast_cond_for_object (java_objectheader *obj); + +#endif + +#endif /* USE_THREADS */ + +#endif /* __locks_h */ diff --git a/threads/notyet.c b/threads/notyet.c new file mode 100644 index 000000000..3a4535cd8 --- /dev/null +++ b/threads/notyet.c @@ -0,0 +1,110 @@ +/* ------------------------ thread.c -------------------------- */ + +/* + * Put a thread to sleep. + */ +void +sleepThread(int64 time) +{ + thread** tidp; + + /* Sleep for no time */ + if (time == 0) { + return; + } + + intsDisable(); + + /* Get absolute time */ + currentThread->PrivateInfo->time = time + currentTime(); + + /* Find place in alarm list */ + for (tidp = &alarmList; (*tidp) != 0; tidp = &(*tidp)->next) { + if ((*tidp)->PrivateInfo->time > currentThread->PrivateInfo->time) { + break; + } + } + + /* If I'm head of alarm list, restart alarm */ + if (tidp == &alarmList) { + MALARM(time); + } + + /* Suspend thread on it */ + suspendOnQThread(currentThread, tidp); + + intsRestore(); +} + +/* + * Handle alarm. + * This routine uses a different meaning of "blockInts". Formerly, it was just + * "don't reschedule if you don't have to". Now it is "don't do ANY + * rescheduling actions due to an expired timer". An alternative would be to + * block SIGALARM during critical sections (by means of sigprocmask). But + * this would be required quite often (for every outmost intsDisable(), + * intsRestore()) and therefore would be much more expensive than just + * setting an int flag which - sometimes - might cause an additional + * setitimer call. + */ +static +void +alarmException(int sig) +{ + thread* tid; + int64 time; + + /* Re-enable signal - necessary for SysV */ + signal(sig, (SIG_T)alarmException); + + /* + * If ints are blocked, this might indicate an inconsistent state of + * one of the thread queues (either alarmList or threadQhead/tail). + * We better don't touch one of them in this case and come back later. + */ + if (blockInts > 0) { + MALARM(50); + return; + } + + intsDisable(); + + /* Wake all the threads which need waking */ + time = currentTime(); + while (alarmList != 0 && alarmList->PrivateInfo->time <= time) { + tid = alarmList; + alarmList = alarmList->next; + iresumeThread(tid); + } + + /* Restart alarm */ + if (alarmList != 0) { + MALARM(alarmList->PrivateInfo->time - time); + } + + /* + * The next bit is rather tricky. If we don't reschedule then things + * are fine, we exit this handler and everything continues correctly. + * On the otherhand, if we do reschedule, we will schedule the new + * thread with alarms blocked which is wrong. However, we cannot + * unblock them here incase we have just set an alarm which goes + * off before the reschedule takes place (and we enter this routine + * recusively which isn't good). So, we set a flag indicating alarms + * are blocked, and allow the rescheduler to unblock the alarm signal + * after the context switch has been made. At this point it's safe. + */ + alarmBlocked = true; + intsRestore(); + alarmBlocked = false; +} + +/* + * How many stack frames have I invoked? + */ +long +framesThread(thread* tid) +{ + long count; + THREADFRAMES(tid, count); + return (count); +} diff --git a/threads/thread.c b/threads/thread.c new file mode 100644 index 000000000..89dde1d28 --- /dev/null +++ b/threads/thread.c @@ -0,0 +1,681 @@ +/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */ +/* + * thread.c + * Thread support. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#include + +#include +#include /* for mprotect */ +#include + +#include "thread.h" +#include "locks.h" +#include "sysdep/defines.h" +#include "sysdep/threads.h" + +#include "../tables.h" +#include "../native.h" +#include "../loader.h" +#include "../builtin.h" +#include "../asmpart.h" + +static classinfo *class_java_lang_ThreadDeath; + +#if 1 +#define DBG(s) +#define SDBG(s) +#else +#define DBG(s) s +#define SDBG(s) s +#endif + +#if defined(USE_INTERNAL_THREADS) + +thread* currentThread; +thread* threadQhead[MAX_THREAD_PRIO + 1]; +thread* threadQtail[MAX_THREAD_PRIO + 1]; + +thread* liveThreads; +thread* alarmList; + +thread* gcDaemonThread; + +int blockInts; +bool needReschedule; + +ctx contexts[MAXTHREADS]; + +/* Number of threads alive, also counting daemons */ +static int talive; + +/* Number of daemon threads alive */ +static int tdaemon; + +static void firstStartThread(void); + +void reschedule(void); + +/* Setup default thread stack size - this can be overwritten if required */ +int threadStackSize = THREADSTACKSIZE; + +static thread* startDaemon(void* func, char* nm, int stackSize); + +/* + * Allocate the stack for a thread + */ +void +allocThreadStack (thread *tid, int size) +{ + int pageSize = getpagesize(), + result; + unsigned long pageBegin; + + CONTEXT(tid).stackMem = malloc(size + 2 * pageSize); + assert(CONTEXT(tid).stackMem != 0); + CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize; + + pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1; + pageBegin = pageBegin - pageBegin % pageSize; + + result = mprotect((void*)pageBegin, pageSize, PROT_NONE); + assert(result == 0); + + CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize; +} + +/* + * Free the stack for a thread + */ +void +freeThreadStack (thread *tid) +{ + if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC)) + { + int pageSize = getpagesize(), + result; + unsigned long pageBegin; + + pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1; + pageBegin = pageBegin - pageBegin % pageSize; + + result = mprotect((void*)pageBegin, pageSize, + PROT_READ | PROT_WRITE | PROT_EXEC); + assert(result == 0); + + free(CONTEXT(tid).stackMem); + } + CONTEXT(tid).stackMem = 0; + CONTEXT(tid).stackBase = 0; + CONTEXT(tid).stackEnd = 0; +} + +/* + * Initialize threads. + */ +void +initThreads(u1 *stackbottom) +{ + int i; + + initLocks(); + + for (i = 0; i < MAXTHREADS; ++i) + contexts[i].free = true; + + /* Allocate a thread to be the main thread */ + currentThread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread"))); + assert(currentThread != 0); + + currentThread->PrivateInfo = 1; + CONTEXT(currentThread).free = false; + + liveThreads = currentThread; + + currentThread->name = javastring_new(unicode_new_char("main")); + currentThread->priority = NORM_THREAD_PRIO; + CONTEXT(currentThread).priority = (u1)currentThread->priority; + CONTEXT(currentThread).exceptionptr = 0; + currentThread->next = 0; + CONTEXT(currentThread).status = THREAD_SUSPENDED; + CONTEXT(currentThread).stackBase = CONTEXT(currentThread).stackEnd = stackbottom; + THREADINFO(&CONTEXT(currentThread)); + + DBG( printf("main thread %p base %p end %p\n", + currentThread, + CONTEXT(currentThread).stackBase, + CONTEXT(currentThread).stackEnd); ); + + CONTEXT(currentThread).flags = THREAD_FLAGS_NOSTACKALLOC; + CONTEXT(currentThread).nextlive = 0; + currentThread->single_step = 0; + currentThread->daemon = 0; + currentThread->stillborn = 0; + currentThread->target = 0; + currentThread->interruptRequested = 0; + currentThread->group = + (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup"))); + /* we should call the constructor */ + assert(currentThread->group != 0); + + talive++; + + /* Add thread into runQ */ + iresumeThread(currentThread); + + /* Start garbage collection thread */ + gcDaemonThread = startDaemon(gc_thread, "gc", 1024*512); + iresumeThread(gcDaemonThread); + + heap_addreference((void**)&gcDaemonThread); + + /* Load exception classes */ + class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath")); + + DBG( fprintf(stderr, "finishing initThreads\n"); ); + + assert(blockInts == 0); +} + +/* + * Start a new thread running. + */ +void +startThread (thread* tid) +{ + int i; + + /* Allocate a stack context */ + for (i = 0; i < MAXTHREADS; ++i) + if (contexts[i].free) + break; + + if (i == MAXTHREADS) + panic("Too many threads"); + + tid->PrivateInfo = i + 1; + CONTEXT(tid).free = false; + CONTEXT(tid).nextlive = liveThreads; + liveThreads = tid; + allocThreadStack(tid, threadStackSize); + CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase; + CONTEXT(tid).flags = THREAD_FLAGS_GENERAL; + CONTEXT(tid).status = THREAD_SUSPENDED; + CONTEXT(tid).priority = (u1)tid->priority; + CONTEXT(tid).exceptionptr = 0; + + /* Construct the initial restore point. */ + THREADINIT((&CONTEXT(tid)), firstStartThread); + + DBG( printf("new thread %p base %p end %p\n", + tid, CONTEXT(tid).stackBase, + CONTEXT(tid).stackEnd); ); + + talive++; + if (tid->daemon) + tdaemon++; + + /* Add thread into runQ */ + iresumeThread(tid); +} + +/* + * Start a daemon thread. + */ +static thread* +startDaemon(void* func, char* nm, int stackSize) +{ + thread* tid; + int i; + + DBG( printf("startDaemon %s\n", nm); ); + + tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread"))); + assert(tid != 0); + + for (i = 0; i < MAXTHREADS; ++i) + if (contexts[i].free) + break; + if (i == MAXTHREADS) + panic("Too many threads"); + + tid->PrivateInfo = i + 1; + CONTEXT(tid).free = false; + tid->name = 0; /* for the moment */ + tid->priority = MAX_THREAD_PRIO; + CONTEXT(tid).priority = (u1)tid->priority; + tid->next = 0; + CONTEXT(tid).status = THREAD_SUSPENDED; + + allocThreadStack(tid, stackSize); + tid->single_step = 0; + tid->daemon = 1; + tid->stillborn = 0; + tid->target = 0; + tid->interruptRequested = 0; + tid->group = 0; + + /* Construct the initial restore point. */ + THREADINIT((&CONTEXT(tid)), func); + + talive++; + tdaemon++; + + return tid; +} + +/* + * All threads start here. + */ +static void +firstStartThread(void) +{ + methodinfo *method; + + DBG( printf("firstStartThread %p\n", currentThread); ); + + /* Every thread starts with the interrupts off */ + intsRestore(); + assert(blockInts == 0); + + /* Find the run()V method and call it */ + method = class_findmethod(currentThread->header.vftbl->class, + unicode_new_char("run"), unicode_new_char("()V")); + if (method == 0) + panic("Cannot find method \'void run ()\'"); + asm_calljavamethod(method, currentThread, NULL, NULL, NULL); + + killThread(0); + assert("Thread returned from killThread" == 0); +} + +/* + * Resume a thread running. + * This routine has to be called only from locations which ensure + * run / block queue consistency. There is no check for illegal resume + * conditions (like explicitly resuming an IO blocked thread). There also + * is no update of any blocking queue. Both has to be done by the caller + */ +void +iresumeThread(thread* tid) +{ + DBG( printf("resumeThread %p\n", tid); ); + + intsDisable(); + + if (CONTEXT(tid).status != THREAD_RUNNING) + { + CONTEXT(tid).status = THREAD_RUNNING; + + DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); ); + + /* Place thread on the end of its queue */ + if (threadQhead[CONTEXT(tid).priority] == 0) { + threadQhead[CONTEXT(tid).priority] = tid; + threadQtail[CONTEXT(tid).priority] = tid; + if (CONTEXT(tid).priority + > CONTEXT(currentThread).priority) + needReschedule = true; + } + else + { + threadQtail[CONTEXT(tid).priority]->next = tid; + threadQtail[CONTEXT(tid).priority] = tid; + } + tid->next = 0; + } + SDBG( else { printf("Re-resuming %p\n", tid); } ); + + intsRestore(); +} + +/* + * Yield process to another thread of equal priority. + */ +void +yieldThread() +{ + intsDisable(); + + if (threadQhead[CONTEXT(currentThread).priority] + != threadQtail[CONTEXT(currentThread).priority]) + { + /* Get the next thread and move me to the end */ + threadQhead[CONTEXT(currentThread).priority] = currentThread->next; + threadQtail[CONTEXT(currentThread).priority]->next = currentThread; + threadQtail[CONTEXT(currentThread).priority] = currentThread; + currentThread->next = 0; + needReschedule = true; + } + + intsRestore(); +} + +/* + * Explicit request by user to resume a thread + * The definition says that it is just legal to call this after a preceeding + * suspend (which got through). If the thread was blocked for some other + * reason (either sleep or IO or a muxSem), we simply can't do it + * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose + * (which is set by suspendThread(.)) + */ +void +resumeThread(thread* tid) +{ + if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0) + { + intsDisable(); + CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND; + iresumeThread(tid); + intsRestore(); + } +} + +/* + * Suspend a thread. + * This is an explicit user request to suspend the thread - the counterpart + * for resumeThreadRequest(.). It is JUST called by the java method + * Thread.suspend() + * What makes it distinct is the fact that the suspended thread is not contained + * in any block queue. Without a special flag (indicating the user suspend), we + * can't check s suspended thread for this condition afterwards (which is + * required by resumeThreadRequest()). The new thread flag + * THREAD_FLAGS_USER_SUSPEND is used for this purpose. + */ +void +suspendThread(thread* tid) +{ + thread** ntid; + + intsDisable(); + + if (CONTEXT(tid).status != THREAD_SUSPENDED) + { + CONTEXT(tid).status = THREAD_SUSPENDED; + + /* + * This is used to indicate the explicit suspend condition + * required by resumeThreadRequest() + */ + CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND; + + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + tid->next = 0; + if (tid == currentThread) + { + reschedule(); + } + break; + } + } + } + SDBG( else { printf("Re-suspending %p\n", tid); } ); + + intsRestore(); +} + +/* + * Suspend a thread on a queue. + */ +void +suspendOnQThread(thread* tid, thread** queue) +{ + thread** ntid; + + DBG( printf("suspendOnQThread %p %p\n", tid, queue); ); + + assert(blockInts == 1); + + if (CONTEXT(tid).status != THREAD_SUSPENDED) + { + CONTEXT(tid).status = THREAD_SUSPENDED; + + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + /* Insert onto head of lock wait Q */ + tid->next = *queue; + *queue = tid; + if (tid == currentThread) + { + DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n", + tid, currentThread, CONTEXT(tid).priority); ); + reschedule(); + } + break; + } + } + } + SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } ); +} + +/* + * Kill thread. + */ +void +killThread(thread* tid) +{ + thread** ntid; + + intsDisable(); + + /* A null tid means the current thread */ + if (tid == 0) + { + tid = currentThread; + } + + DBG( printf("killThread %p\n", tid); ); + + if (CONTEXT(tid).status != THREAD_DEAD) + { + /* Get thread off runq (if it needs it) */ + if (CONTEXT(tid).status == THREAD_RUNNING) + { + for (ntid = &threadQhead[CONTEXT(tid).priority]; + *ntid != 0; + ntid = &(*ntid)->next) + { + if (*ntid == tid) + { + *ntid = tid->next; + break; + } + } + } + + CONTEXT(tid).status = THREAD_DEAD; + talive--; + if (tid->daemon) { + tdaemon--; + } + + /* If we only have daemons left, then everyone is dead. */ + if (talive == tdaemon) { + /* Am I suppose to close things down nicely ?? */ + exit(0); + } + + /* Notify on the object just in case anyone is waiting */ + internal_lock_mutex_for_object(&tid->header); + internal_broadcast_cond_for_object(&tid->header); + internal_unlock_mutex_for_object(&tid->header); + + /* Remove thread from live list to it can be garbaged */ + for (ntid = &liveThreads; + *ntid != 0; + ntid = &(CONTEXT((*ntid)).nextlive)) + { + if (tid == (*ntid)) + { + (*ntid) = CONTEXT(tid).nextlive; + break; + } + } + + /* Free stack */ + freeThreadStack(tid); + + /* free context */ + CONTEXT(tid).free = true; + + /* Run something else */ + needReschedule = true; + } + intsRestore(); +} + +/* + * Change thread priority. + */ +void +setPriorityThread(thread* tid, int prio) +{ + thread** ntid; + + if (tid->PrivateInfo == 0) { + tid->priority = prio; + return; + } + + if (CONTEXT(tid).status == THREAD_SUSPENDED) { + CONTEXT(tid).priority = (u8)prio; + return; + } + + intsDisable(); + + /* Remove from current thread list */ + for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) { + if (*ntid == tid) { + *ntid = tid->next; + break; + } + } + + /* Insert onto a new one */ + tid->priority = prio; + CONTEXT(tid).priority = (u8)tid->priority; + if (threadQhead[prio] == 0) { + threadQhead[prio] = tid; + threadQtail[prio] = tid; + if (prio > CONTEXT(currentThread).priority) { + needReschedule = true; + } + } + else { + threadQtail[prio]->next = tid; + threadQtail[prio] = tid; + } + tid->next = 0; + + intsRestore(); +} + +/* + * Is this thread alive? + */ +bool +aliveThread(thread* tid) +{ + if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD) + return (true); + else + return (false); +} + +/* + * Reschedule the thread. + * Called whenever a change in the running thread is required. + */ +void +reschedule(void) +{ + int i; + thread* lastThread; + int b; + /* sigset_t nsig; */ + + /* A reschedule in a non-blocked context is half way to hell */ + assert(blockInts > 0); + b = blockInts; + + /* Check events - we may release a high priority thread */ + /* Just check IO, no need for a reschedule call by checkEvents() */ + needReschedule = false; + checkEvents(false); + + for (;;) + { + for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--) + { + if (threadQhead[i] != 0) + { + DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); ); + + if (threadQhead[i] != currentThread) + { + USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); + + lastThread = currentThread; + currentThread = threadQhead[i]; + + CONTEXT(currentThread).exceptionptr = exceptionptr; + + THREADSWITCH((&CONTEXT(currentThread)), + (&CONTEXT(lastThread))); + blockInts = b; + + exceptionptr = CONTEXT(currentThread).exceptionptr; + + /* Alarm signal may be blocked - if so + * unblock it. + */ + /* + if (alarmBlocked == true) { + alarmBlocked = false; + sigemptyset(&nsig); + sigaddset(&nsig, SIGALRM); + sigprocmask(SIG_UNBLOCK, &nsig, 0); + } + */ + + /* I might be dying */ + if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED) + != 0) + { + CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED; + exceptionptr = native_new_and_init(class_java_lang_ThreadDeath); + } + } + /* Now we kill the schedule and turn ints + back on */ + needReschedule = false; + return; + } + } + /* Nothing to run - wait for external event */ + DBG( fprintf(stderr, "nothing more to do\n"); ); + checkEvents(true); + } +} + +#endif diff --git a/threads/thread.h b/threads/thread.h new file mode 100644 index 000000000..1f72d9e9e --- /dev/null +++ b/threads/thread.h @@ -0,0 +1,151 @@ +/* + * thread.h + * Thread support. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#ifndef __thread_h +#define __thread_h + +#ifdef USE_THREADS + +#include "../global.h" + +#define MAXTHREADS 256 /* schani */ + +#define THREADCLASS "java/lang/Thread" +#define THREADGROUPCLASS "java/lang/ThreadGroup" +#define THREADDEATHCLASS "java/lang/ThreadDeath" + +#define MIN_THREAD_PRIO 1 +#define NORM_THREAD_PRIO 5 +#define MAX_THREAD_PRIO 10 + +#define THREAD_SUSPENDED 0 +#define THREAD_RUNNING 1 +#define THREAD_DEAD 2 +#define THREAD_KILL 3 + +#define THREAD_FLAGS_GENERAL 0 +#define THREAD_FLAGS_NOSTACKALLOC 1 +#define THREAD_FLAGS_USER_SUSPEND 2 /* Flag explicit suspend() call */ +#define THREAD_FLAGS_KILLED 4 + +struct _thread; + +typedef struct _ctx +{ + bool free; /* schani */ + u1 status; + u1 priority; + u1* restorePoint; + u1* stackMem; /* includes guard page */ + u1* stackBase; + u1* stackEnd; + u1* usedStackTop; + s8 time; + java_objectheader *exceptionptr; + struct _thread *nextlive; + u1 flags; +} ctx; + +/* +struct _stringClass; +struct _object; +*/ + +/* This structure mirrors java.lang.ThreadGroup.h */ + +typedef struct _threadGroup +{ + java_objectheader header; + struct _threadGroup* parent; + java_objectheader* name; + s4 maxPrio; + s4 destroyed; + s4 daemon; + s4 nthreads; + java_objectheader* threads; + s4 ngroups; + java_objectheader* groups; +} threadGroup; + +/* This structure mirrors java.lang.Thread.h */ +typedef struct _thread +{ + java_objectheader header; + java_objectheader* name; + s4 priority; + struct _thread* next; + s8 PrivateInfo; + struct java_lang_Object* eetop; /* ??? */ + s4 single_step; + s4 daemon; + s4 stillborn; + java_objectheader* target; + s4 interruptRequested; + threadGroup* group; +} thread; + +void initThreads(u1 *stackbottom); +void startThread(thread*); +void resumeThread(thread*); +void iresumeThread(thread*); +void suspendThread(thread*); +void suspendOnQThread(thread*, thread**); +void yieldThread(void); +void killThread(thread*); +void setPriorityThread(thread*, int); + +void sleepThread(s8); +bool aliveThread(thread*); +long framesThread(thread*); + +void reschedule(void); + +void checkEvents(bool block); + +extern int blockInts; +extern bool needReschedule; +extern thread *currentThread; +extern ctx contexts[]; +extern int threadStackSize; + +extern thread *liveThreads; + +extern thread *threadQhead[MAX_THREAD_PRIO + 1]; + +#define CONTEXT(_t) \ + (contexts[(_t)->PrivateInfo - 1]) + +#if 1 +#define intsDisable() blockInts++ +#define intsRestore() if (blockInts == 1 && needReschedule) { \ + reschedule(); \ + } \ + blockInts-- +#else +#define intsDisable() do { blockInts++; fprintf(stderr, "++: %d (%s:%d)\n", blockInts, __FILE__, __LINE__); } while (0) +#define intsRestore() do { \ + if (blockInts == 1 && needReschedule) { \ + reschedule(); \ + } \ + blockInts--; \ + fprintf(stderr, "--: %d (%s:%d)\n", blockInts, __FILE__, __LINE__); \ + } while (0) +#endif + +#else + +#define intsDisable() +#define intsRestore() + +#endif + +#endif diff --git a/threads/threadio.c b/threads/threadio.c new file mode 100644 index 000000000..e538b409a --- /dev/null +++ b/threads/threadio.c @@ -0,0 +1,358 @@ +/* + * threadCalls.c + * Support for threaded ops which may block (read, write, connect, etc.). + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Tim Wilkinson , 1996. + */ + +#define DBG(s) + +#include "sysdep/defines.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" + +/* + * We only need this stuff is we are using the internal thread system. + */ +#if defined(USE_INTERNAL_THREADS) + +#define TH_READ 0 +#define TH_WRITE 1 +#define TH_ACCEPT TH_READ +#define TH_CONNECT TH_WRITE + +static int maxFd; +static fd_set readsPending; +static fd_set writesPending; +static thread* readQ[FD_SETSIZE]; +static thread* writeQ[FD_SETSIZE]; +static struct timeval tm = { 0, 0 }; + +void blockOnFile(int, int); +void waitOnEvents(void); + +extern thread* currentThread; + +/* These are undefined because we do not yet support async I/O */ +#undef F_SETOWN +#undef FIOSETOWN +#undef O_ASYNC +#undef FIOASYNC + +/* + * Create a threaded file descriptor. + */ +int +threadedFileDescriptor(int fd) +{ +#if !defined(BLOCKING_CALLS) + int r; + int on = 1; + int pid; + + /* Make non-blocking */ +#if defined(HAVE_FCNTL) && defined(O_NONBLOCK) + r = fcntl(fd, F_GETFL, 0); + r = fcntl(fd, F_SETFL, r|O_NONBLOCK); +#elif defined(HAVE_IOCTL) && defined(FIONBIO) + r = ioctl(fd, FIONBIO, &on); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } + + /* Allow socket to signal this process when new data is available */ + pid = getpid(); +#if defined(HAVE_FCNTL) && defined(F_SETOWN) + r = fcntl(fd, F_SETOWN, pid); +#elif defined(HAVE_IOCTL) && defined(FIOSETOWN) + r = ioctl(fd, FIOSETOWN, &pid); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } + +#if defined(HAVE_FCNTL) && defined(O_ASYNC) + r = fcntl(fd, F_GETFL, 0); + r = fcntl(fd, F_SETFL, r|O_ASYNC); +#elif defined(HAVE_IOCTL) && defined(FIOASYNC) + r = ioctl(fd, FIOASYNC, &on); +#else + r = 0; +#endif + if (r < 0) + { + return (r); + } +#endif + return (fd); +} + +/* + * Threaded create socket. + */ +int +threadedSocket(int af, int type, int proto) +{ + int fd; + int r; + int on = 1; + int pid; + + fd = socket(af, type, proto); + return (threadedFileDescriptor(fd)); +} + +/* + * Threaded file open. + */ +int +threadedOpen(char* path, int flags, int mode) +{ + int fd; + int r; + int on = 1; + int pid; + + fd = open(path, flags, mode); + return (threadedFileDescriptor(fd)); +} + +/* + * Threaded socket connect. + */ +int +threadedConnect(int fd, struct sockaddr* addr, int len) +{ + int r; + + r = connect(fd, addr, len); +#if !defined(BLOCKING_CALLS) + if ((r < 0) + && (errno == EINPROGRESS || errno == EALREADY + || errno == EWOULDBLOCK)) { + blockOnFile(fd, TH_CONNECT); + r = 0; /* Assume it's okay when we get released */ + } +#endif + + return (r); +} + +/* + * Threaded socket accept. + */ +int +threadedAccept(int fd, struct sockaddr* addr, int* len) +{ + int r; + int on = 1; + + for (;;) + { +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_ACCEPT); +#endif + r = accept(fd, addr, len); + if (r >= 0 + || !(errno == EINPROGRESS || errno == EALREADY + || errno == EWOULDBLOCK)) + { + break; + } +#if !defined(BLOCKING_CALLS) + blockOnFile(fd, TH_ACCEPT); +#endif + } + return (threadedFileDescriptor(r)); +} + +/* + * Read but only if we can. + */ +int +threadedRead(int fd, char* buf, int len) +{ + int r; + + DBG( printf("threadedRead\n"); ) + +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_READ); +#endif + for (;;) + { + r = read(fd, buf, len); + if (r < 0 + && (errno == EAGAIN || errno == EWOULDBLOCK + || errno == EINTR)) + { + blockOnFile(fd, TH_READ); + continue; + } + return (r); + } +} + +/* + * Write but only if we can. + */ +int +threadedWrite(int fd, char* buf, int len) +{ + int r; + char* ptr; + + ptr = buf; + r = 1; + + DBG( printf("threadedWrite %dbytes\n",len); ) + + while (len > 0 && r > 0) + { +#if defined(BLOCKING_CALLS) + blockOnFile(fd, TH_WRITE); +#endif + r = write(fd, ptr, len); + if (r < 0 + && (errno == EAGAIN || errno == EWOULDBLOCK + || errno == EINTR)) + { +#if !defined(BLOCKING_CALLS) + blockOnFile(fd, TH_WRITE); +#endif + r = 1; + } + else + { + ptr += r; + len -= r; + } + } + return (ptr - buf); +} + +/* + * An attempt to access a file would block, so suspend the thread until + * it will happen. + */ +void +blockOnFile(int fd, int op) +{ +DBG( printf("blockOnFile()\n"); ) + + intsDisable(); + + if (fd > maxFd) + { + maxFd = fd; + } + if (op == TH_READ) + { + FD_SET(fd, &readsPending); + suspendOnQThread(currentThread, &readQ[fd]); + FD_CLR(fd, &readsPending); + } + else + { + FD_SET(fd, &writesPending); + suspendOnQThread(currentThread, &writeQ[fd]); + FD_CLR(fd, &writesPending); + } + + intsRestore(); +} + +/* + * Check if some file descriptor or other event to become ready. + * Block if required (but make sure we can still take timer interrupts). + */ +void +checkEvents(bool block) +{ + int r; + fd_set rd; + fd_set wr; + thread* tid; + thread* ntid; + int i; + int b; + +DBG( printf("checkEvents block:%d\n", block); ) + +#if defined(FD_COPY) + FD_COPY(&readsPending, &rd); + FD_COPY(&writesPending, &wr); +#else + memcpy(&rd, &readsPending, sizeof(rd)); + memcpy(&wr, &writesPending, sizeof(wr)); +#endif + + /* + * If select() is called with indefinite wait, we have to make sure + * we can get interrupted by timer events. + */ + if (block == true) + { + b = blockInts; + blockInts = 0; + r = select(maxFd+1, &rd, &wr, 0, 0); + blockInts = b; + } + else + { + r = select(maxFd+1, &rd, &wr, 0, &tm); + } + + /* We must be holding off interrupts before we start playing with + * the read and write queues. This should be already done but a + * quick check never hurt anyone. + */ + assert(blockInts > 0); + +DBG( printf("Select returns %d\n", r); ) + + for (i = 0; r > 0 && i <= maxFd; i++) + { + if (readQ[i] != 0 && FD_ISSET(i, &rd)) + { + for (tid = readQ[i]; tid != 0; tid = ntid) + { + ntid = tid->next; + iresumeThread(tid); + } + readQ[i] = 0; + r--; + } + if (writeQ[i] != 0 && FD_ISSET(i, &wr)) + { + for (tid = writeQ[i]; tid != 0; tid = ntid) + { + ntid = tid->next; + iresumeThread(tid); + } + writeQ[i] = 0; + r--; + } + } +} +#endif diff --git a/threads/threadio.h b/threads/threadio.h new file mode 100644 index 000000000..1e9d5c2a2 --- /dev/null +++ b/threads/threadio.h @@ -0,0 +1,26 @@ +/* -*- c -*- */ + +#ifndef __threadio_h_ +#define __threadio_h_ + +#include +#include + +#include "../global.h" + +#ifdef USE_THREADS +int threadedFileDescriptor(int fd); +int threadedSocket(int af, int type, int proto); +int threadedOpen(char* path, int flags, int mode); +int threadedConnect(int fd, struct sockaddr* addr, int len); +int threadedAccept(int fd, struct sockaddr* addr, int* len); +int threadedRead(int fd, char* buf, int len); +int threadedWrite(int fd, char* buf, int len); +#else +#define threadedFileDescriptor(fd) +#define threadedRead(fd,buf,len) read(fd,buf,len) +#define threadedWrite(fd,buf,len) write(fd,buf,len) +#endif + + +#endif diff --git a/toolbox/Makefile b/toolbox/Makefile new file mode 100755 index 000000000..191d8a2df --- /dev/null +++ b/toolbox/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# Makefile for the program independent toolbox # +################################################################################ +# +# Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst +# +# See the file COPYRIGHT for information on usage and disclaimer of warranties +# +# Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at +# +# Last Change: 1997/10/30 +# +################################################################################ + +OBJECTS = memory.o loging.o chain.o tree.o list.o + +toolbox.a: $(OBJECTS) Makefile + rm -f toolbox.a + ar qcs toolbox.a $(OBJECTS) + +memory.o: memory.c memory.h loging.h +loging.o: loging.c loging.h +chain.o: chain.c chain.h memory.h +tree.o: tree.c tree.h memory.h +list.o: list.c list.h + +clean: + rm -f *.o *.a diff --git a/toolbox/chain.c b/toolbox/chain.c new file mode 100644 index 000000000..7e50617d1 --- /dev/null +++ b/toolbox/chain.c @@ -0,0 +1,243 @@ +/************************* toolbox/chain.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see chain.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include + +#include "memory.h" +#include "chain.h" + + + +chain *chain_new () +{ + chain *c; + + c = NEW (chain); + c -> usedump = 0; + c -> first = NULL; + c -> last = NULL; + c -> active = NULL; + + return c; +} + +chain *chain_dnew () +{ + chain *c; + + c = DNEW (chain); + c -> usedump = 1; + c -> first = NULL; + c -> last = NULL; + c -> active = NULL; + + return c; +} + + +void chain_free (chain *c) +{ + chainlink *l; + + assert (! c->usedump); + + l = c->first; + while (l) { + chainlink *nextl = l->next; + + FREE (l, chainlink); + l = nextl; + } + + FREE (c, chain); +} + + +void chain_addafter(chain *c, void *element) +{ + chainlink *active,*newlink; + + active = c->active; + + if (c -> usedump) newlink = DNEW (chainlink); + else newlink = NEW (chainlink); + + newlink -> element = element; + + if (active) { + newlink -> next = active -> next; + newlink -> prev = active; + + active -> next = newlink; + if (newlink -> next) newlink -> next -> prev = newlink; + else c -> last = newlink; + } + else { + newlink -> next = NULL; + newlink -> prev = NULL; + + c -> active = newlink; + c -> first = newlink; + c -> last = newlink; + } +} + + +void chain_addbefore(chain *c, void *element) +{ + chainlink *active,*newlink; + + active = c->active; + + if (c -> usedump) newlink = DNEW (chainlink); + else newlink = NEW (chainlink); + + newlink -> element = element; + + if (active) { + newlink -> next = active; + newlink -> prev = active -> prev; + + active -> prev = newlink; + if (newlink -> prev) newlink -> prev -> next = newlink; + else c -> first = newlink; + } + else { + newlink -> next = NULL; + newlink -> prev = NULL; + + c -> active = newlink; + c -> first = newlink; + c -> last = newlink; + } +} + +void chain_addlast (chain *c, void *e) +{ + chain_last (c); + chain_addafter (c, e); +} + +void chain_addfirst (chain *c, void *e) +{ + chain_first (c); + chain_addbefore (c, e); +} + + +void chain_remove (chain *c) +{ + chainlink *active; + + active = c -> active; + assert (active); + + if (active -> next) { + active -> next -> prev = active -> prev; + } + else { + c -> last = active -> prev; + } + + if (active -> prev) { + active -> prev -> next = active -> next; + } + else { + c -> first = active -> next; + } + + + if (active->prev) + c -> active = active->prev; + else + c -> active = active->next; + + if (! c -> usedump) FREE (active, chainlink); +} + + +void *chain_remove_go_prev (chain *c) +{ + chain_remove (c); + return chain_this (c); +} + + + +void chain_removespecific(chain *c, void *e) +{ + void *ce; + + ce = chain_first (c); + while (ce) { + if (e == ce) { chain_remove (c); return; } + ce = chain_next (c); + } + +} + +void *chain_next(chain *c) +{ + chainlink *active; + + active = c -> active; + if (!active) return NULL; + + if (active -> next) { + c -> active = active -> next; + return c -> active -> element; + } + + return NULL; +} + +void *chain_prev(chain *c) +{ + chainlink *active; + + active = c -> active; + if (!active) return NULL; + + if (active -> prev) { + c -> active = active -> prev; + return c -> active -> element; + } + + return NULL; +} + + +void *chain_this(chain *c) +{ + if (c -> active) return c -> active -> element; + return NULL; +} + + +void *chain_first(chain *c) +{ + c -> active = c -> first; + if (c -> active) return c -> active -> element; + return NULL; +} + +void *chain_last(chain *c) +{ + c -> active = c -> last; + if (c -> active) return c -> active -> element;; + return NULL; +} + diff --git a/toolbox/chain.h b/toolbox/chain.h new file mode 100644 index 000000000..e065c07fe --- /dev/null +++ b/toolbox/chain.h @@ -0,0 +1,92 @@ +/************************* toolbox/chain.h ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + dient zur Verwaltung doppelt verketteter Listen mit externer Verkettung + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef struct chainlink { /* Struktur f"ur ein Listenelement */ + struct chainlink *next,*prev; + void *element; + } chainlink; + +typedef struct chain { /* Struktur f"ur eine Liste */ + int usedump; + + chainlink *first,*last; + chainlink *active; + } chain; + + +chain *chain_new (); +chain *chain_dnew (); +void chain_free(chain *c); + +void chain_addafter(chain *c, void *element); +void chain_addbefore(chain *c, void *element); +void chain_addlast (chain *c, void *element); +void chain_addfirst (chain *c, void *element); + +void chain_remove(chain *c); +void *chain_remove_go_prev(chain *c); +void chain_removespecific(chain *c, void *element); + +void *chain_next(chain *c); +void *chain_prev(chain *c); +void *chain_this(chain *c); + +void *chain_first(chain *c); +void *chain_last(chain *c); + + +/* +--------------------------- Schnittstellenbeschreibung ------------------------ + +Bei Verwendung dieser Funktionen f"ur die Listenverwaltung mu"s, im +Gegenstatz zum Modul 'list', keine zus"atzliche Vorbereitung in den +Element-Strukturen gemacht werden. + +Diese Funktionen sind daher auch ein wenig langsamer und brauchen +mehr Speicher. + +Eine neue Liste wird mit + chain_new + oder chain_dnew +angelegt. Der Unterschied ist, da"s bei der zweiten Variante alle +zus"atzlichen Datenstrukturen am DUMP-Speicher angelegt werden (was +schneller geht, und ein explizites Freigeben am Ende der Verarbeitung +unn"otig macht). Dabei mu"s man aber achtgeben, da"s man nicht +versehentlich Teile dieser Strukturen durch ein verfr"uhtes 'dump_release' +freigibt. + +Eine nicht mehr verwendete Liste kann mit + chain_free +freigegeben werden (nur verwenden, wenn mit 'chain_new' angefordert) + + +Das Eintragen neuer Elemente geht sehr einfach mit: + chain_addafter, chain_addlast, chain_addbefore, chain_addfirst + +Durchsuchen der Liste mit: + chain_first, chain_last, chain_prev, chain_next, chain_this + +L"oschen von Elementen aus der Liste: + chain_remove, chain_remove_go_prev, chain_removespecific + + +ACHTUNG: In den zu verkettenden Elementen gibt es ja (wie oben gesagt) keine + Referenzen auf die Liste oder irgendwelche Listenknoten, deshalb k"onnen + die Elemente nicht als Ortsangabe innerhalb der Liste fungieren. + Es gibt vielmehr ein Art 'Cursor', der ein Element als das gerade + aktuelle festh"alt, und alle Ein-/und Ausf"ugeoperationen geschehen + relativ zu diesem Cursor. + +*/ + diff --git a/toolbox/list.c b/toolbox/list.c new file mode 100644 index 000000000..6183684d5 --- /dev/null +++ b/toolbox/list.c @@ -0,0 +1,107 @@ +/************************** toolbox/list.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see chain.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include + +#include "list.h" + + +void list_init (list *l, int nodeoffset) +{ + l->first = NULL; + l->last = NULL; + l->nodeoffset = nodeoffset; +} + +void list_addlast (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (l->last) { + n->prev = l->last; + n->next = NULL; + l->last->next = n; + l->last = n; + } + else { + n->prev = NULL; + n->next = NULL; + l->last = n; + l->first = n; + } +} + +void list_addfirst (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (l->first) { + n->prev = NULL; + n->next = l->first; + l->first->prev = n; + l->first = n; + } + else { + n->prev = NULL; + n->next = NULL; + l->last = n; + l->first = n; + } +} + + +void list_remove (list *l, void *element) +{ + listnode *n = (listnode*) ( ((char*) element) + l->nodeoffset ); + + if (n->next) n->next->prev = n->prev; + else l->last = n->prev; + if (n->prev) n->prev->next = n->next; + else l->first = n->next; +} + + +void *list_first (list *l) +{ + if (!l->first) return NULL; + return ((char*) l->first) - l->nodeoffset; +} + + +void *list_last (list *l) +{ + if (!l->last) return NULL; + return ((char*) l->last) - l->nodeoffset; +} + + +void *list_next (list *l, void *element) +{ + listnode *n; + n = (listnode*) ( ((char*) element) + l->nodeoffset ); + if (!n->next) return NULL; + return ((char*) n->next) - l->nodeoffset; +} + + +void *list_prev (list *l, void *element) +{ + listnode *n; + n = (listnode*) ( ((char*) element) + l->nodeoffset ); + if (!n->prev) return NULL; + return ((char*) n->prev) - l->nodeoffset; +} + diff --git a/toolbox/list.h b/toolbox/list.h new file mode 100644 index 000000000..22f7ec061 --- /dev/null +++ b/toolbox/list.h @@ -0,0 +1,97 @@ +/************************** toolbox/list.h ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Verwaltung von doppelt verketteten Listen. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef struct listnode { /* Struktur f"ur ein Listenelement */ + struct listnode *next,*prev; + } listnode; + +typedef struct list { /* Struktur f"ur den Listenkopf */ + listnode *first,*last; + int nodeoffset; + } list; + + +void list_init (list *l, int nodeoffset); + +void list_addlast (list *l, void *element); +void list_addfirst (list *l, void *element); + +void list_remove (list *l, void *element); + +void *list_first (list *l); +void *list_last (list *l); + +void *list_next (list *l, void *element); +void *list_prev (list *l, void *element); + + +/* +---------------------- Schnittstellenbeschreibung ----------------------------- + +Die Listenverwaltung mit diesem Modul geht so vor sich: + + - jede Struktur, die in die Liste eingeh"angt werden soll, mu"s + eine Komponente vom Typ 'listnode' haben. + + - es mu"s ein Struktur vom Typ 'list' bereitgestellt werden. + + - die Funktion list_init (l, nodeoffset) initialisiert diese Struktur, + dabei gibt der nodeoffset den Offset der 'listnode'-Komponente in + den Knotenstrukturen an. + + - Einf"ugen, Aush"angen und Suchen von Elementen der Liste geht mit + den "ubrigen Funktionen. + +Zum besseren Verst"andnis ein kleines Beispiel: + + + void bsp() { + struct node { + listnode linkage; + int value; + } a,b,c, *el; + + list l; + + a.value = 7; + b.value = 9; + c.value = 11; + + list_init (&l, OFFSET(struct node,linkage) ); + list_addlast (&l, a); + list_addlast (&l, b); + list_addlast (&l, c); + + e = list_first (&l); + while (e) { + printf ("Element: %d\n", e->value); + e = list_next (&l,e); + } + } + + + Dieses Programm w"urde also folgendes ausgeben: + 7 + 9 + 11 + + + +Der Grund, warum beim Initialisieren der Liste der Offset mitangegeben +werden mu"s, ist der da"s ein und das selbe Datenelement gleichzeitig +in verschiedenen Listen eingeh"angt werden kann (f"ur jede Liste mu"s +also eine Komponente vom Typ 'listnode' im Element enthalten sein). + +*/ + diff --git a/toolbox/loging.c b/toolbox/loging.c new file mode 100644 index 000000000..e4b9f2370 --- /dev/null +++ b/toolbox/loging.c @@ -0,0 +1,136 @@ +/************************* toolbox/loging.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see loging.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include + +#include "loging.h" + +/*************************************************************************** + LOGFILE - BEHANDLUNG +***************************************************************************/ + +char logtext[MAXLOGTEXT]; /* Musz mit dem gewuenschten Text vor */ + /* Aufruf von dolog() beschrieben werden */ + + +FILE *logfile = NULL; + + + + +void log_init(char *fname) +{ + if (fname) { + if (fname[0]) { + logfile = fopen(fname, "w"); + } + } +} + + + +/*********************** Funktion: dolog ************************************ + +Gibt den in logtext stehenden Text auf die Protokollierungsdatei +aus (wenn sie offen ist) und auszerdem auf stdout. + +**************************************************************************/ + +void dolog() +{ + if (logfile) { + fprintf (logfile, "%s\n",logtext); + fflush (logfile); + } + else { + printf ("LOG: %s\n",logtext); + fflush (stdout); + } +} + +/********************* Funktion: log_text ********************************/ + +void log_text (char *text) +{ + sprintf (logtext, "%s",text); + dolog(); +} + + +/********************* Funktion: log_cputime ****************************/ + +void log_cputime () +{ + long int t; + int sec,usec; + + t = getcputime(); + sec = t/1000000; + usec = t%1000000; + + sprintf (logtext, "Total CPU usage: %d seconds and %d milliseconds", + sec,usec/1000); + dolog(); +} + + + +/************************** Funktion: error ******************************* + +Wie dolog(), aber das Programm wird auszerdem sofort terminiert. + +**************************************************************************/ + +void error() +{ + if (logfile) { + fprintf (logfile, "ERROR: %s\n", logtext); + } + printf ("ERROR: %s\n",logtext); + exit(10); +} + + +/************************ Funktion: panic (txt) **************************** + + Wie error(), jedoch wird der auszugebende Text als Argument uebergeben + +***************************************************************************/ + +void panic(char *txt) +{ + sprintf (logtext, "%s", txt); + error(); +} + + +/********************** Funktion: getcputime ******************************** + + liefert die verbrauchte CPU-Zeit im Mikrosekunden + +****************************************************************************/ + +long int getcputime() +{ + struct rusage ru; + int sec,usec; + + getrusage (RUSAGE_SELF, &ru); + sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec; + usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec; + return sec*1000000 + usec; +} + diff --git a/toolbox/loging.h b/toolbox/loging.h new file mode 100644 index 000000000..d28472bb7 --- /dev/null +++ b/toolbox/loging.h @@ -0,0 +1,53 @@ +/************************* toolbox/loging.h ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Stellt Funktionen f"urs Logging zur Verf"ugung + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#define PANICIF(when,txt) if(when)panic(txt) + +#define MAXLOGTEXT 500 +extern char logtext[MAXLOGTEXT]; + +void log_init(char *fname); +void log_text(char *txt); + +void log_cputime(); + +void dolog(); +void error(); +void panic(char *txt); + +long int getcputime(); + + +/* + +-------------------------- Schnittstellenbeschreibung ------------------------- + +log_init .... Initialisiert das Logfile-System + fname ....... Dateiname f"ur die Protokollierungsdatei + keepfile .... 1, wenn die alte Datei nicht gel"oscht werden soll + echostdout .. 1, wenn auch auf stdout ausgegeben werden soll + +log_text .... Gibt einen Text auf das Logfile aus +log_cputime . Gibt eine Information "uber die verbrauchte CPU-Zeit aus +dolog ....... Gibt den Inhalt von logtext aus +error ....... Gibt den Inhalt von logtext aus, und stoppt das System +panic ....... Gibt eine Text auf das Logfile aus + +logtext ..... dieses globale Array mu"s vor Benutzung der Funktionen 'log' + oder 'error' mit dem auszugebenen Text bef"ullt werden. + +getcputimew . gibt die vom Programm verbrauchte CPU-Zeit in + Mikrosekunden zur"uck + +*/ diff --git a/toolbox/memory.c b/toolbox/memory.c new file mode 100644 index 000000000..2cc8e9437 --- /dev/null +++ b/toolbox/memory.c @@ -0,0 +1,458 @@ +/************************* toolbox/memory.c ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see memory.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "../callargs.h" +#include "loging.h" +#include "memory.h" + + + /********* allgemeine Typen, Variablen und Hilfsfunktionen *********/ + +#define DUMPBLOCKSIZE (2<<18) +#define ALIGNSIZE 8 + +typedef struct dumplist { + struct dumplist *prev; + char *dumpmem; +} dumplist; + + + +long int memoryusage = 0; + +long int dumpsize = 0; +long int dumpspace = 0; +dumplist *topdumpblock = NULL; + +long int maxmemusage = 0; +long int maxdumpsize = 0; + +/* #define TRACECALLARGS */ + +#ifdef TRACECALLARGS +static char nomallocmem[16777216]; +static char *nomalloctop = nomallocmem + 16777216; +static char *nomallocptr = nomallocmem; + +static void *lit_checked_alloc (int length) +{ + void *m; + + nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE); + + m = nomallocptr; + nomallocptr += length; + if (nomallocptr > nomalloctop) panic ("Out of memory"); + return m; +} + +#else + +static void *lit_checked_alloc (int length) +{ + void *m = malloc(length); + if (!m) panic ("Out of memory"); + return m; +} + +#endif + + +static void *checked_alloc (int length) +{ + void *m = malloc(length); + if (!m) panic ("Out of memory"); + return m; +} + +static int mmapcodesize = 0; +static void *mmapcodeptr = NULL; + +void *mem_mmap(int length) +{ + void *retptr; + + length = (ALIGN(length,ALIGNSIZE)); + if (length > mmapcodesize) { + mmapcodesize = 0x10000; + if (length > mmapcodesize) + mmapcodesize = length; + mmapcodesize = (ALIGN(mmapcodesize, getpagesize())); + mmapcodeptr = mmap (NULL, (size_t) mmapcodesize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0); + if (mmapcodeptr == (void*) -1) + panic ("Out of memory"); + } + retptr = mmapcodeptr; + mmapcodeptr = (void*) ((char*) mmapcodeptr + length); + mmapcodesize -= length; + return retptr; +} + + +#ifdef DEBUG + + /************ Sichere Version des Speichermanages **************/ + + +typedef struct memblock { + struct memblock *prev,*next; + int length; +} memblock; + +#define BLOCKOFFSET (ALIGN(sizeof(memblock),ALIGNSIZE)) + +struct memblock *firstmemblock; + + + +void *mem_alloc(int length) +{ + memblock *mb; + + if (length==0) return NULL; + mb = checked_alloc (length + BLOCKOFFSET); + + mb -> prev = NULL; + mb -> next = firstmemblock; + mb -> length = length; + + if (firstmemblock) firstmemblock -> prev = mb; + firstmemblock = mb; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return ((char*) mb) + BLOCKOFFSET; +} + + +void *lit_mem_alloc(int length) +{ + memblock *mb; + + if (length==0) return NULL; + mb = lit_checked_alloc (length + BLOCKOFFSET); + + mb -> prev = NULL; + mb -> next = firstmemblock; + mb -> length = length; + + if (firstmemblock) firstmemblock -> prev = mb; + firstmemblock = mb; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return ((char*) mb) + BLOCKOFFSET; +} + + +void mem_free(void *m, int length) +{ + memblock *mb; + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + mb = (memblock*) (((char*) m) - BLOCKOFFSET); + + if (mb->length != length) { + sprintf (logtext, + "Memory block of size %d has been return as size %d", + mb->length, length); + error(); + } + + if (mb->prev) mb->prev->next = mb->next; + else firstmemblock = mb->next; + if (mb->next) mb->next->prev = mb->prev; + + free (mb); + + memoryusage -= length; +} + + +void lit_mem_free(void *m, int length) +{ + memblock *mb; + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + mb = (memblock*) (((char*) m) - BLOCKOFFSET); + + if (mb->length != length) { + sprintf (logtext, + "Memory block of size %d has been return as size %d", + mb->length, length); + error(); + } + + if (mb->prev) mb->prev->next = mb->next; + else firstmemblock = mb->next; + if (mb->next) mb->next->prev = mb->prev; + +#ifdef TRACECALLARGS +#else + free (mb); +#endif + + memoryusage -= length; +} + + +void *mem_realloc (void *m1, int len1, int len2) +{ + void *m2; + + m2 = mem_alloc (len2); + memcpy (m2, m1, len1); + mem_free (m1, len1); + + return m2; +} + + + + +static void mem_characterlog (unsigned char *m, int len) +{ +# define LINESIZE 16 + int z,i; + + for (z=0; z=' ' && m[i]<=127) ? m[i] : '.'); + } + + dolog(); + } +} + +#else + /******* Schnelle Version des Speichermanagers ******/ + + +void *mem_alloc(int length) +{ + if (length==0) return NULL; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return checked_alloc (length); +} + + +void *lit_mem_alloc(int length) +{ + if (length==0) return NULL; + + memoryusage += length; + if (memoryusage > maxmemusage) maxmemusage = memoryusage; + + return lit_checked_alloc (length); +} + + +void mem_free(void *m, int length) +{ + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + memoryusage -= length; + + free (m); +} + + +void lit_mem_free(void *m, int length) +{ + if (!m) { + if (length==0) return; + panic ("returned memoryblock with address NULL, length != 0"); + } + + memoryusage -= length; + +#ifdef TRACECALLARGS +#else + free (m); +#endif +} + + +void *mem_realloc (void *m1, int len1, int len2) +{ + void *m2; + + if (!m1) { + if (len1!=0) + panic ("reallocating memoryblock with address NULL, length != 0"); + } + + memoryusage = (memoryusage - len1) + len2; + + m2 = realloc (m1, len2); + if (!m2) panic ("Out of memory"); + return m2; +} + + +#endif + + /******* allgemeine Teile des Speichermanagers ******/ + + + +long int mem_usage() +{ + return memoryusage; +} + + + + + +void *dump_alloc(int length) +{ + void *m; + + if (length==0) return NULL; + + length = ALIGN (length, ALIGNSIZE); + + assert (length <= DUMPBLOCKSIZE); + assert (length > 0); + + if (dumpsize + length > dumpspace) { + dumplist *newdumpblock = checked_alloc (sizeof(dumplist)); + + newdumpblock -> prev = topdumpblock; + topdumpblock = newdumpblock; + + newdumpblock -> dumpmem = checked_alloc (DUMPBLOCKSIZE); + + dumpsize = dumpspace; + dumpspace += DUMPBLOCKSIZE; + } + + m = topdumpblock -> dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize); + dumpsize += length; + + if (dumpsize > maxdumpsize) { + maxdumpsize = dumpsize; + } + + return m; +} + + +void *dump_realloc(void *ptr, int len1, int len2) +{ + void *p2 = dump_alloc (len2); + memcpy (p2, ptr, len1); + return p2; +} + + +long int dump_size() +{ + return dumpsize; +} + + +void dump_release(long int size) +{ + assert (size >= 0 && size <= dumpsize); + + dumpsize = size; + + while (dumpspace > dumpsize + DUMPBLOCKSIZE) { + dumplist *oldtop = topdumpblock; + + topdumpblock = oldtop -> prev; + dumpspace -= DUMPBLOCKSIZE; + +#ifdef TRACECALLARGS +#else + free (oldtop -> dumpmem); + free (oldtop); +#endif + } +} + + + + +void mem_usagelog (int givewarnings) +{ + if ((memoryusage!=0) && givewarnings) { + sprintf (logtext, "Allocated memory not returned: %d", + (int)memoryusage); + dolog(); + +#ifdef DEBUG + { + memblock *mb = firstmemblock; + while (mb) { + sprintf (logtext, " Memory block size: %d", + (int)(mb->length) ); + dolog(); + mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length); + mb = mb->next; + } + } +#endif + + } + + if ((dumpsize!=0) && givewarnings) { + sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize); + dolog(); + } + + + sprintf (logtext, "Random/Dump - memory usage: %dK/%dK", + (int)((maxmemusage+1023)/1024), + (int)((maxdumpsize+1023)/1024) ); + dolog(); + +} + diff --git a/toolbox/memory.h b/toolbox/memory.h new file mode 100644 index 000000000..c4122f96e --- /dev/null +++ b/toolbox/memory.h @@ -0,0 +1,121 @@ +/************************* toolbox/memory.h ************************************ + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Headerfiles und Makros f"ur die Speicherverwaltung. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#define CODEMMAP + +#define ALIGN(pos,size) ( ( ((pos)+(size)-1) / (size))*(size) ) +#define PADDING(pos,size) ( ALIGN((pos),(size)) - (pos) ) +#define OFFSET(s,el) ( (int) &( ((s*)0) -> el ) ) + + +#define NEW(type) ((type*) mem_alloc ( sizeof(type) )) +#define FREE(ptr,type) mem_free (ptr, sizeof(type) ) + +#define LNEW(type) ((type*) lit_mem_alloc ( sizeof(type) )) +#define LFREE(ptr,type) lit_mem_free (ptr, sizeof(type) ) + +#define MNEW(type,num) ((type*) mem_alloc ( sizeof(type) * (num) )) +#define MFREE(ptr,type,num) mem_free (ptr, sizeof(type) * (num) ) +#define MREALLOC(ptr,type,num1,num2) mem_realloc (ptr, sizeof(type) * (num1), \ + sizeof(type) * (num2) ) + +#define DNEW(type) ((type*) dump_alloc ( sizeof(type) )) +#define DMNEW(type,num) ((type*) dump_alloc ( sizeof(type) * (num) )) +#define DMREALLOC(ptr,type,num1,num2) dump_realloc (ptr, sizeof(type)*(num1),\ + sizeof(type) * (num2) ) + +#define MCOPY(dest,src,type,num) memcpy (dest,src, sizeof(type)* (num) ) + +#ifdef CODEMMAP +#define CNEW(type,num) ((type*) mem_mmap ( sizeof(type) * (num) )) +#define CFREE(ptr,num) +#else +#define CNEW(type,num) ((type*) mem_alloc ( sizeof(type) * (num) )) +#define CFREE(ptr,num) mem_free (ptr, num) +#endif + +void *mem_alloc(int length); +void *mem_mmap(int length); +void *lit_mem_alloc(int length); +void mem_free(void *m, int length); +void lit_mem_free(void *m, int length); +void *mem_realloc(void *m, int len1, int len2); +long int mem_usage(); + +void *dump_alloc(int length); +void *dump_realloc(void *m, int len1, int len2); +long int dump_size(); +void dump_release(long int size); + +void mem_usagelog(int givewarnings); + + + +/* +---------------------------- Schnittstellenbeschreibung ----------------------- + +Der Speicherverwalter hat zwei m"ogliche Arten Speicher zu reservieren +und freizugeben: + + 1. explizites Anfordern / Freigeben + + mem_alloc ..... Anfordern eines Speicherblocks + mem_free ...... Freigeben eines Speicherblocks + mem_realloc ... Vergr"o"sern eines Speicherblocks (wobei + der Inhalt eventuell an eine neue Position kommt) + mem_usage ..... Menge des bereits belegten Speichers + + + 2. explizites Anfordern und automatisches Freigeben + + dump_alloc .... Anfordern eines Speicherblocks vom + (wie ich es nenne) DUMP-Speicher + dump_realloc .. Vergr"o"sern eines Speicherblocks + dump_size ..... Merkt sich eine Freigabemarke am Dump + dump_release .. Gibt allen Speicher, der nach der Marke angelegt + worden ist, wieder frei. + + +Es gibt f"ur diese Funktionen ein paar praktische Makros: + + NEW (type) ....... legt Speicher f"ur ein Element des Typs `type` an. + FREE (ptr,type) .. gibt Speicher zur"uck + + MNEW (type,num) .. legt Speicher f"ur ein ganzes Array an + MFREE (ptr,type,num) .. gibt den Speicher wieder her + + MREALLOC (ptr,type,num1,num2) .. vergr"o"sert den Speicher f"ur das Array + auf die Gr"o"se num2 + +Die meisten der Makros gibt es auch f"ur den DUMP-Speicher, na"mlich mit +gleichem Namen, nur mit vorangestelltem 'D', also: + + DNEW, DMNEW, DMREALLOC (DFREE gibt es nat"urlich keines) + + +------------------------------------------------------------------------------- + +Die restlichen Makros: + + ALIGN (pos, size) ... Rundet den Wert von 'pos' auf die n"achste durch + 'size' teilbare Zahl auf. + + + OFFSET (s,el) ....... Berechnet den Offset (in Bytes) des Elementes 'el' + in der Struktur 's'. + + MCOPY (dest,src,type,num) ... Kopiert 'num' Elemente vom Typ 'type'. + + +*/ diff --git a/toolbox/tree.c b/toolbox/tree.c new file mode 100644 index 000000000..ae74ffc19 --- /dev/null +++ b/toolbox/tree.c @@ -0,0 +1,166 @@ +/************************** toolbox/tree.c ************************************* + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Not documented, see tree.h. + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +#include +#include + +#include "memory.h" +#include "tree.h" + + +tree *tree_new (treeelementcomperator comperator) +{ + tree *t = NEW (tree); + + t -> usedump = 0; + t -> comperator = comperator; + t -> top = NULL; + t -> active = NULL; + + return t; +} + +tree *tree_dnew (treeelementcomperator comperator) +{ + tree *t = DNEW (tree); + + t -> usedump = 1; + t -> comperator = comperator; + t -> top = NULL; + t -> active = NULL; + + return t; +} + + +static void tree_nodefree (treenode *tn) +{ + if (!tn) return; + tree_nodefree (tn -> left); + tree_nodefree (tn -> right); + FREE (tn, treenode); +} + +void tree_free (tree *t) +{ + assert (! t -> usedump); + + tree_nodefree ( t -> top ); + FREE (t, tree); +} + + +static treenode *tree_nodeadd + (tree *t, treenode *par, treenode *n, void *element, void *key) +{ + if (!n) { + if ( t-> usedump ) n = DNEW (treenode); + else n = NEW (treenode); + + n -> left = NULL; + n -> right = NULL; + n -> parent = par; + n -> element = element; + } + else { + if ( t->comperator (key, n -> element) < 0 ) { + n -> left = tree_nodeadd (t, n, n -> left, element, key); + } + else { + n -> right = tree_nodeadd (t, n, n -> right, element, key); + } + } + + return n; +} + +void tree_add (tree *t, void *element, void *key) +{ + t -> top = tree_nodeadd (t, NULL, t -> top, element, key); + t -> active = t -> top; +} + + +static treenode *tree_nodefind (tree *t, treenode *n, void *key) +{ + int way; + + if (!n) return NULL; + + way = t -> comperator (key, n->element); + if (way==0) return n; + if (way<0) return tree_nodefind (t, n -> left, key); + else return tree_nodefind (t, n -> right, key); +} + + +void *tree_find (tree *t, void *key) +{ + treenode *tn = tree_nodefind (t, t -> top, key); + if (!tn) return NULL; + + t -> active = tn; + return tn -> element; +} + + + +void *tree_this (tree *t) +{ + if (! t->active) return NULL; + return t->active->element; +} + + +static treenode *leftmostnode(treenode *t) +{ + while (t->left) t=t->left; + return t; +} + +void *tree_first (tree *t) +{ + treenode *a = t->top; + if (!a) return NULL; + + a = leftmostnode (a); + t->active = a; + return a->element; +} + +void *tree_next (tree *t) +{ + treenode *a = t->active; + treenode *comefrom = NULL; + + while (a) { + if (!a) return NULL; + + if (a->left && (a->left == comefrom)) { + t -> active = a; + return a->element; + } + + if (a->right && (a->right != comefrom) ) { + a = leftmostnode(a->right); + t -> active = a; + return a->element; + } + + comefrom=a; + a=a->parent; + } + t->active = NULL; + return NULL; +} diff --git a/toolbox/tree.h b/toolbox/tree.h new file mode 100644 index 000000000..fa974bbe0 --- /dev/null +++ b/toolbox/tree.h @@ -0,0 +1,45 @@ +/************************* toolbox/tree.h ************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Verwaltung bin"arer B"aume + + Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1996/10/03 + +*******************************************************************************/ + +typedef int (*treeelementcomperator) (void *key, void * element); + + +typedef struct treenode { + struct treenode *left,*right; + struct treenode *parent; + + void *element; + } treenode; + +typedef struct { + int usedump; + treeelementcomperator comperator; + + treenode *top; + treenode *active; + } tree; + + + +tree *tree_new (treeelementcomperator comperator); +tree *tree_dnew (treeelementcomperator comperator); +void tree_free (tree *t); + +void tree_add (tree *t, void *element, void *key); +void *tree_find (tree *t, void *key); + +void *tree_this (tree *t); +void *tree_first (tree *t); +void *tree_next (tree *t); + -- 2.25.1