Kaffe:
main(): main.c
Set up environment variable.
initialise the virtual machine (JNI_CreateJavaVM).
Call main2.
JNI_CreateJavaVM(): jni.c
Setup the machine (initialiseKaffe).
Setup JNI for main thread.
Setup the JNI Exception handler.
Return the VM and JNI we're using.
initialiseKaffe(): baseClasses.c
Initialise the machine.
Initialise the, native, threading system(*Kaffe_ThreadInterface.init
= Tinit).
Setup CLASSPATH (initClasspath).
Init native support (initNative).
Create the initialise and finalize names and signatures, here need a unicode
string to Utf8 constant string (makeUtf8ConstFixed).
Read in base classes (initBaseClasses).
Setup exceptions (initExceptions).
Init thread support (initThreads).
Tinit: systems/unix-jthreads/internal.c
Initialise a thread system (jthread_init).
Add a presistent reference to the main thread (gc_add_ref
= gcAddRef).
jthread_init: systems/unix-jthreads/jthread.c
Initialize the threading system.
Create a threaded file descriptor (jthreadedFileDescriptor)
Setup signal handlers (catchSignal)
Allocate thread queue header and tail object (allocator
= thread_malloc)
Allocate a new thread context with stack size 0 (newThreadCtx)
and initialise it.
Resume the thread (resumeThread)
jthreadedFileDescriptor: systems/unix-jthreads/jthread.c
Create a threaded file descriptor
catchSignal: exception.c
Setup a signal handler
thread_malloc: systems/unix-jthreads/internal.c
Allocate a new object (gc_malloc = gcMalloc)
gcMalloc: mem/gc-incremental.c
Allocate a new object. The object is attached to the white queue.
After allocation, if incremental collection is active we peform a little
garbage collection. If we finish it, we wakeup the garbage collector.
Initialise GC (initGc), if not done yet.
Allocate a piece of memory (gc_heap_malloc)
Update the GC list (OBJECTSTATSADD = objectStatsChange),
i.e. an object just be creadted.
Determine whether we need to finalise or not
If object is fixed, we give it the fixed colour and do not attach it to
any lists. This object is not part of the GC regieme and must be
freed explicitly
Note that as soon as we put the object on the white list, the gc might
come along and free the object if it can't find any references to it.
This is why we need to keep a reference in `mem'. Note that keeping
a reference in `unit' will not do because markObject performs a UTOUNIT()!
initGc: mem/gc-incremental.c
Initalise the Garbage Collection system
gc_heap_malloc: mem/gc-mem.c
Initialise GC heap first time in (gc_heap_initialise)-
we must assume single threaded operation here so we can do the lock initialising
(initStaticLock = __initLock)
Lock the lock (lockStaticMutex = __lockMutex)
Allocate memory depend on object size (gc_small_block)
and (gc_large_block) which might use different GC algorithms
If failed to find space in any freelists. Must try to get the memory from
somewhere, including
-
The first try: Try invoking GC (invokeGC), but only if we've got some heap
and the GC is available and it's worth doing. Notice that it needs unlock
the lock first (unlockStaticMutex = __unlockMutex)
and relock (lockStaticMutex = __lockMutex) after
GC.
-
The second try: Get from the system (gc_system_alloc),
place block into the freelist for subsequent use, attach block to object
hash, then free block into the system (gc_primitive_free)
-
The third try: Throw a OutOfMemoryException, i.e. if we fail to allocate
memory for it, all is lost. Then unlock the lock (unlockStaticMutex
= __unlockMutex)
If success, unlock the lock (unlockStaticMutex
= __unlockMutex) before return
gc_heap_initialise: mem/gc-mem.c
Initialise allocator
__initLock: locks.c
Initialise a new lock
Initialise a new lock (*Kaffe_LockInterface.ini = Linit)
Linit: systems/unix-jthreads/internal.c
Implementation of the locking subsystem based on jlocks.. Also keep track
of lk->holder, and its type is void
The first lock init is for the memory manager - so we can't use it yet.
Allocate from static space. For locks later created need to dynamically
allocate memory (thread_malloc)
Initialise the locking subsystem (jmutex_initialise),
(jcondvar_initialise)
jmutex_initialise: systems/unix-jthreads/jthread.c
Initialise the mutex (jmutex) by setting
its member data, holder and waiting to NULL
jcondvar_initialise: systems/unix-jthreads/jthread.c
Initialise the condition variable (jcondvar)
__lockMutex: locks.c
Lock the given lock
Check if lock is hold by currentNative; if yes, increment lock count; if
not, lock the lock (*Kaffe_LockInterface.lock =
Llock)
Llock: systems/unix-jthreads/internal.c
Lock a given lock
lock the lock mutex (jmutex_lock)
Set lock is hold by current thread (jthread_current)
jmutex_lock: systems/unix-jthreads/jthread.c
Lock the mutex of a given lock
Need to disable interrupts (intsDisable) first,
then restore interrupts (intsRestore) after
finished
Suspend the current thread to the queue (suspendOnQThread), while someone
is holding the mutex.
Set mutex is hold by current thread (jthread_current)
until the current thread is permitted to hold the mutex.
intsDisable: systems/unix-jthreads/jthread.c
disable interrupts
Instead of blocking signals, we increment a counter.
If a signal comes in while the counter is non-zero, we set a pending flag
and mark the signal as pending.
intsDisable may be invoked recursively. (is that really a good idea? -
gb)
intsRestore: systems/unix-jthreads/jthread.c
restore interrupts
If interrupts are about to be reenabled, execute the handlers for all signals
that are pending (processSignals)
Reschedule if necessary (reschedule)
jthread_current: systems/unix-jthreads/jthread.h
return the current thread
gc_small_block: mem/gc-mem.c
Allocate a new block of GC'ed memory. The block will contain one
or many same size objects.
Allocate a block of memory with a page size (gc_primitive_alloc)
Calculate number of objects in this block
Setup the meta-data for the block
Build the objects into a free list
gc_primitive_alloc: mem/gc-mem.c
Allocate a block of memory from the free list or, failing that, the system
pool.
gc_system_alloc: mem/gc-mem.c
Allocate a block of memory from the system heap
If the needed size pass the heap boundary, return 0 to indicate that run
out of heap; if not allocate a block of page (pagealloc)
pagealloc: mem/gc-mem.c
Actual implementation of allocate a block of memory from the system heap
gc_primitive_free: mem/gc-mem.c
Return a block of memory to the free list
__unlockMutex: locks.c
Release a given mutex
decrement the lock count; if 0, unlock the lock (*Kaffe_LockInterface.unlock
= Lunlock)
Lunlock: systems/unix-jthreads/internal.c
Unlock a given lock
Set lock holder to 0, then unlock the lock mutex (jmutex_unlock)
jmutex_unlock: systems/unix-jthreads/jthread.c
Unlock a given mutex
Need to disable interrupts (intsDisable) first,
then restore interrupts (intsRestore) after
finished
Set mutex is hold by NULL. If some thread is waiting for the mutex, let
the next thread in the queue hold the mutex and resume the thread (resumeThread).
objectStatsChange: mem/gc-incremental.c
Update the gcList for statistics gathering for GC.
newThreadCtx: systems/unix-jthreads/jthread.c
Allocate a new thread context and stack.
Allocate a piece of memory with size being size of jthread + stackSize
(allocator) and initialise it.
resumeThread: systems/unix-jthreads/jthread.c
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)
Need to disable interrupts (intsDisable) first,
then restore interrupts (intsRestore) after
finished
Remove from alarmQ or lockQ, if necessary.
Place thread on the end of its queue
gcAddRef: mem/gc-incremental.c
Add a presistent reference to an object for GC
If found the reference, just increase reference; if not found - create
a new one (gcMalloc)
initClasspath: findInJar.c
Initialise class path
If class path is not empty, build classpathEntries from it (makeClasspath);
if empty, discover all available jar and zip files in the home location
and build a classpath from them. (discoverClasspath).
makeClasspath: findInJar.c
Build classpathEntries from the given classpath.
Add the given entry into the Classpath (addClasspath).
Allocat a piece of memory (gc_malloc_fixed = gcMalloc)
and put all Classpath entries in it.
addClasspath: findInJar.c
Add an entry in the Classpath dynamically.
Allocate memory if the entry need to be build (gc_malloc_fixed
= gcMalloc); then initialise it.
initNative: external.c
Initialise native support, i.e. method calls to other languages
Allocat a piece of memory (gc_malloc_fixed = gcMalloc)
and put librariy path entries in it.
Find the default library and load it (loadNativeLibrary).
loadNativeLibrary: external.c
Find a library handle. If we find the library has already been loaded,
don't bother to get it again, just increase the reference count. If not,
load the library and allocat a piece of memory (gc_malloc_fixed
= gcMalloc) for the library name.
makeUtf8ConstFixed: string.c
Create a Utf8 string object. The diffenence with makeUtf8Const
is that it ensure system doesn't GC the Utf8 string.
Create a Utf8 string (makeUtf8Const).
Add a presistent reference to the created Utf8 string (gc_add_ref
= gcAddRef), so system doesn't GC classes.
makeUtf8Const: string.c
Create a Utf8 string object. The diffenence with makeUtf8ConstFixed
is that it does not ensure system doesn't GC the Utf8 string.
Allocat necessary memory (gc_malloc = gcMalloc)
for the Utf8 string and put the unicode content in it.
Calculate its hash value (hashUtf8String).
hashUtf8String: string.c
Calculate a hash value for a string encoded in Utf8 format. This returns
the same hash value as specified or java.lang.String.hashCode.
Count the number of Unicode chars (strLengthUtf8).
Calculate its hash value.
strLengthUtf8: string.c
Count the number of Unicode chars encoded in a given Ut8 string.
initBaseClasses: baseClasses.c
Need to use certain classes in the internal machine so we better get them
in now in a known way so we can refer back to them. Currently we need java/lang/Object,
java/lang/Class, java/lang/String and java/lang/System.
Initialise the primitive types (initTypes).
Load the base types, basic types classes and Exception handling types (loadStaticClass).
Fixup primitive types (finishTypes).
initTypes: itypes.c
Intialise the internal types.
Initialise primitive classes (initPrimClass),
like void, byte, int, etc.
initPrimClass: itypes.c
Create a new class object (newClass).
Initialise the class as primity type; also need to convert class name to
Utf8 string (makeUtf8Const).
newClass: object.c
Allocate a new class object.
Allocate memory (gc_malloc = gcMalloc).
We don't GC classes at the moment so secure this one (gc_add_ref
= gcAddRef);
loadStaticClass: classMethod.c
Create a new object (newClass).
Find class entry by its name (lookupClassEntry).
Lock the entry (lockMutex = _lockMutex) to see
if the class has been loaded, i.e. by the class entry. If yes, need to
find it in a directory or JAR file (findClass).
Then unlock the entry (unlockMutex = _unlockMutex).
Initialise the class (processClass) with state
Cstate_Linked.
lookupClassEntry: classMethod.c
Find its class entry by given class name. If not exist, allocate memory
and add an entry.
If the class table, classHashLock, has not been initialized, i.e. chlinit
== false, initialize it (initStaticLock = __initLock).
If failed to find class entry - create a new one, i.e. need to allocate
memory (gc_malloc_fixed = gcMalloc). Then, lock
the class table (lockStaticMutex = __lockMutex)
and insert entry into it, but, if someone else added it - discard ours
(gc_free_fixed) and return the new one. If no one added it, add ours to
end of hash and also keep an extra reference to the utf8 name so it won't
be GCed (gc_add_ref = gcAddRef). After unlock the
class table (unlockStaticMutex = __unlockMutex).
_lockMutex: locks.c
Lock a mutex by using the address to find a lock.
Retrieve the lock associated with the given address. If one isn't
found, allocate it (newLock).
lock the found lock (__lockMutex).
newLock: locks.c
Retrieve a machine specific, possibly, locking structure associated with
the given address. If one isn't found, allocate it.
Get the hash list header from the lock table, lock the hash list (*Kaffe_LockInterface.spinon
= Tspinon).
Try to find the lock with the given address; if found, simply increment
reference count; if not but found a free lock, i.e. no reference, get the
free lock.
Allocate a new lock structure, if necessary - use a free one if we found
it, or need to allocate memory (gc_malloc = gcMalloc)
and initialise it (*Kaffe_LockInterface.init = Linit).
Unlock the hash list (*Kaffe_LockInterface.spinoff
= Tspinoff).
Tspinon: systems/unix-jthreads/internal.c
Using internal system to support lock; in Linux, it simply disable interrupt
(intsDisable).
Tspinoff: systems/unix-jthreads/internal.c
Using internal system to support unlock; in Linux, it simply enable interrupt
(intsRestore).
findClass: findInJar.c
Find the named class in a directory or JAR file
Locate the class by name in the CLASSPATH (findInJar).
Depend on class file type, try to new (newClass)
and read class (readClass) if zip file,
or register class (registerClass) if shared library.
Certain classes, like java/lang/ClassNotFoundException or java/lang/Object,
are essential. If we don't find them then abort.
findInJar: findInJar.c
Locate the given class name in the CLASSPATH.
Initialise a lock (initStaticLock = __initLock)
on first use. Here we allow one into the jar at once (lockStaticMutex
= __lockMutex).
If class file type is zip, need to open the jar file (openJarFile),
find if the given calss name is in the jar file (lookupJarFile)
(getDataJarFile).
If class file type isDIR,
If class file type is shared lib, need to (loadNativeLibrary), (generateMangledName),
(loadNativeLibrarySym).
lookupJarFile: jar.c
Simply compare the given class name with each jar entry in the jar file.
openJarFile: jar.c (unfinished)
Open the jar file.
processClass: classMethod.c
Process all the stage of a classes initialisation. We can provide
a state to aim for (so we don't have to do this all at once). This
is called by various parts of the machine in order to load, link and initialise
the class. Putting it all together here makes it a damn sight easier
to understand what's happening.
Initialise a lock (initStaticLock = __initLock)
on first use. For the moment we only allow one thread to initialise any
classes at once. This is because we need to check circular class
dependencies (lockStaticMutex = __lockMutex).
Allocate any static space required by class and initialise the space with
any constant values. This isn't necessaryfor pre-loaded classes (allocStaticFields).
Load (getClass) and link the super class (processClass).
Load all the implemented interfaces. If class is an interface, include
the superclass as well.
We build a list of *all* interfaces this class can use.
(resolveObjectFields).
(resolveStaticFields).
Build dispatch table (buildDispatchTable). We must handle interfaces
a little differently (buildInterfaceDispatchTable) since they only have
a <clinit> method.
Second stage verification - check the class format is okay (verify2).
Third stage verification - check the bytecode is okay (verify3).
If init is in progress return. This must be the same thread because
we lock the class when we come in here.
Initialise the constants (resolveConstants).
Find the class initialization method (findMethodLocal),
i.e. <clinit>.
Call the class initialization method (callMethodA),
i.e. <clinit>.
allocStaticFields: classMethod.c
Allocate the space for the static class data.
_unlockMutex: locks.c
Release a mutex by using the address to find a lock.
Retrieve the lock associated with the given address (getLock).
Unlock the found lock (__unlockMutex).
Free the lock if necessary (freeLock).
getLock: locks.c
Retrieve a machine specific, possibly, locking structure associated with
the given address. If one isn't found, don't allocate it, which is
different with (newLock).
Simply search the lockTable.
freeLock: locks.c
Decrement the reference count or free a lock if no longer in use.
Get the hash list header from the lock table, lock the hash list (*Kaffe_LockInterface.spinon
= Tspinon).
Decrement reference count; if reference is 0, release it for reallocation,
i.e. no count, no holder.
Unlock the hash list (*Kaffe_LockInterface.spinoff
= Tspinoff).
finishTypes: itypes.c
Finish the internal types.
initExceptions: exception.c
Setup the internal exceptions.
Catch signals we need to convert to exceptions (Catchsignal
= catchSignal).
initThreads: thread.c
Initialise threads, not whole thread system, which is different than (Tinit.).
Get a handle on the thread and thread group classes (lookupClass).
Create base group, i.e. ThreadGroupClass (newObject),
then initialise the group.
Allocate a thread to be the main thread (createInitialThread).
initialize thread start lock (initStaticLock = __initLock).
Start the GC daemons (createDaemon) we need,
i.e. finaliser and gc with priority THREAD_MAXPRIO.
lookupClass: classMethod.c
Get the handle on class by the given name.
Lookup a named class, loading it if necessary (loadClass).
Process the class (processClass) with state
CSTATE_OK.
loadClass: classMethod.c
Lookup a named class, loading it if necessary. The name is as used
in class files, e.g. "java/lang/String".
look up the class entry (lookupClassEntry).
If failed to find class, we must now load it. If we use a class loader,
we must call out to Java code.
If not use loader, i.e. loader == NULL, use findClass
which will set centry->class if it finds it.
We process the class (processClass) with state
Cstate_Linked, while we're holding the centry lock so that other threads
will find a processed class if centry->class is not null.
newObject: object.c
Create a new Java object. If the object is a Class then we make it a root,
just for the moment. Otherwise, if the object has a finalize method we
look it up and store it with the object for it's later use. Otherwise
the object is normal.
Allocate memory (gc_malloc = gcMalloc) and fill
in object information.
createInitialThread: thread.c
Create the initial thread with a given name, "main"? We should only ever
call this once.
Allocate a thread to be the main thread (newObject)
and initialise it.
(*Kaffe_ThreadInterface.createFirst = TcreateFirst).
Attach thread to threadGroup, i.e. by call the method "add" of ThreadGroupClass
(do_execute_java_method).
TcreateFirst: systems/unix-jthreads/internal.c
Set the function, runfinalizer, to be run (jthread_atexit)
when all non-daemon threads have exited.
Set Java thread, which is obtained by GET_COOKIE
= jthread_current, associated with main thread (GC_WRITE).
jthread_atexit: systems/unix-jthreads/jthread.c
Set a given function to be run when all non-daemon threads have exited.
do_execute_java_method: support.c
Execute a method of a class.
Call a Java method on a class from native code (do_execute_java_method_v),
static or non-static.
createDaemon: thread.c
Start a daemon thread with a given function.
Keep daemon threads as root objects (newObject)
and initialise it.
Create a thread with the given function by using internal system support
(*Kaffe_ThreadInterface.create = Tcreate).
do_execute_java_method_v: support.c
Call a Java method from native code.
If method handler is 0, look up the handler first. For static call, use
(lookupClassMethod); for non-static call,
use (lookupObjectMethod).
Call the method (callMethodV).
lookupObjectMethod: support.c
Lookup a method given object, name and signature.
Get the object's class handler first, then call lookupClassMethod.
lookupClassMethod: support.c
Lookup a method given class, name and signature.
Find the method (findMethod) with name and signature
converted to Utf8 string (makeUtf8Const).
findMethod: lookup.c
Lookup a method (and translate) in the specified class, it will look up
through super class.
Waz CSTATE_LINKED ?- Must resolve constants before we do any translation.
Might not be right though ... XXX --> call processClass
with state CSTATE_OK.
Lookup method (findMethodLocal) up through
each superclass until found.
findMethodLocal: lookup.c
Lookup a method (and translate) in the specified class, no look up through
superclass.
Compare the method name and signature, and ensure the method is not abstract.
callMethodA: support.c
Generic routine to call a native or Java method (array style).
Fill in the callMethodInfo
structure describes the information necessary to invoke a native or just-in-time
compiled method.
For interpreter mode:
-
If not native method, call virtualMachine
to execute the bytecode.
-
If native method, make the call for native method - system dependent (sysdepCallMethod).
Fot JIT mode, make the call for native method - system dependent (sysdepCallMethod),
which again will call Translate for
the first time executing the bytecode.
callMethodV: support.c
Generic routine to call a native or Java method with varargs style.
Fill in the callMethodInfo
structure describes the information necessary to invoke a native or just-in-time
compiled method.
For interpreter mode:
-
If not native method, call virtualMachine
to execute the bytecode.
-
If native method, make the call for native method - system dependent (sysdepCallMethod).
Fot JIT mode, make the call for native method - system dependent (sysdepCallMethod),
which again will call Translate for
the first time executing the bytecode.
Tcreate: systems/unix-jthreads/internal.c
Create a native thread (jthread_create).
Set Java thread associated with native thread (GC_WRITE).
jthread_create: systems/unix-jthreads/jthread.c
Create a new jthread
Lock the threadLock (jmutex_lock).
Allocate a new thread context with given stack size, threadStackSize, (newThreadCtx).
Note: thread 1 is the main thread, thread 2 and 3 are the garbage collector/finalizer.
Let's assume for now the finalizer does not have to be preempted. Thus,
for thread > 3, we activate time slicing (activate_time_slicing).
Unlock the threadLock (jmutex_unlock).
Note that when we return from setjmp in the context of a new thread, we
must no longer access any local variables in this function. The reason
is that we didn't munge the base pointer that is used to access these variables.
To be safe, we immediately call a new function (start_this_sucker_on_a_new_frame).
Set up context for new thread. Use the macros dealing with stack pointer,
like GET_SP, SET_SP, GET_FP, and SET_FP.
Resume the thread (resumeThread).
activate_time_slicing: systems/unix-jthreads/jthread.c
Set virtual timer for 10ms round-robin time-slicing.