From: <pi...@us...> - 2008-11-04 14:59:38
|
Revision: 15137 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15137&view=rev Author: pizlo Date: 2008-11-04 14:59:30 +0000 (Tue, 04 Nov 2008) Log Message: ----------- merged mminterface package Modified Paths: -------------- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/scheduler/RVMThread.java Added Paths: ----------- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Barrier.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/CollectorThread.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ConcurrentCollectorThread.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/DebugUtil.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIterator.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIteratorGroup.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Handshake.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/MemoryManager.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/MemoryManagerConstants.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Monitor.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/SpecializedScanMethod.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/SynchronizationBarrier.java rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ThreadContext.java Removed Paths: ------------- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/memorymanagers/ Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Barrier.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Barrier.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Barrier.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,91 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.VM; +import org.jikesrvm.scheduler.HeavyCondLock; +import org.jikesrvm.scheduler.RVMThread; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Interruptible; + +/** + * This class implements barrier synchronization. + * The mechanism handles proper resetting by usnig 3 underlying counters + * and supports unconditional blocking until the number of participants + * can be determined. + */ +@Uninterruptible +final class Barrier { + + public static final int VERBOSE = 0; + + private HeavyCondLock lock; + private int target; + private int[] counters=new int[2]; // are two counters enough? + private int[] modes=new int[2]; + private int countIdx; + + public Barrier() {} + + @Interruptible + public void boot(int target) { + lock=new HeavyCondLock(); + this.target=target; + countIdx=0; + } + + public boolean arrive(int mode) { + if (false) { + VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(), + " entered ",RVMThread.getCurrentThread().barriersEntered++, + " barriers"); + } + lock.lock(); + int myCountIdx=countIdx; + boolean result; + if (VM.VerifyAssertions) { + if (counters[myCountIdx]==0) { + modes[myCountIdx]=mode; + } else { + VM._assert(modes[myCountIdx]==mode); + } + } + counters[myCountIdx]++; + if (counters[myCountIdx]==target) { + counters[myCountIdx]=0; + countIdx^=1; + lock.broadcast(); + if (false) { + VM.sysWriteln("waking everyone"); + } + result=true; + } else { + while (counters[myCountIdx]!=0) { + lock.await(); + } + result=false; + } + lock.unlock(); + if (false) { + VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(), + " exited ",RVMThread.getCurrentThread().barriersExited++, + " barriers"); + } + return result; + } +} +/* +Local Variables: + c-basic-offset: 2 +End: +*/ Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/CollectorThread.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/CollectorThread.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/CollectorThread.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,576 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.ArchitectureSpecific; +import org.jikesrvm.VM; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.mm.mmtk.Collection; +import org.jikesrvm.mm.mmtk.MMTk_Events; +import org.jikesrvm.mm.mmtk.ScanThread; +import org.jikesrvm.mm.mmtk.Scanning; +import org.jikesrvm.runtime.Magic; +import org.jikesrvm.runtime.Time; +import org.jikesrvm.scheduler.Synchronization; +import org.jikesrvm.scheduler.RVMThread; +import org.mmtk.plan.Plan; +import org.mmtk.utility.heap.HeapGrowthManager; +import org.mmtk.utility.options.Options; +import org.vmmagic.pragma.BaselineNoRegisters; +import org.vmmagic.pragma.BaselineSaveLSRegisters; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.NoOptCompile; +import org.vmmagic.pragma.NonMoving; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.UnpreemptibleNoWarn; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; + +/** + * System thread used to preform garbage collections. + * + * These threads are created by VM.boot() at runtime startup. One is created for + * each processor that will (potentially) participate in garbage collection. + * + * <pre> + * Its "run" method does the following: + * 1. wait for a collection request + * 2. synchronize with other collector threads (stop mutation) + * 3. reclaim space + * 4. synchronize with other collector threads (resume mutation) + * 5. goto 1 + * </pre> + * + * Between collections, the collector threads are parked on a pthread + * condition variable. A collection in initiated by a call to the static + * {@link #collect()} method, which calls + * {@link Handshake#requestAndAwaitCompletion} to signal the threads. + * The collection commences when all + * scheduled collector threads arrive at the first "rendezvous" in the run + * methods run loop. + * + * An instance of Handshake contains state information for the "current" + * collection. When a collection is finished, a new Handshake is allocated + * for the next garbage collection. + * + * @see Handshake + */ +@NonMoving +public final class CollectorThread extends RVMThread { + + /*********************************************************************** + * + * Class variables + */ + private static final int verbose = 0; + + /** Name used by toString() and when we create the associated + * java.lang.Thread. */ + private static final String myName = "CollectorThread"; + + /** When true, causes RVM collectors to display heap configuration + * at startup */ + static final boolean DISPLAY_OPTIONS_AT_BOOT = false; + + /** + * When true, causes RVM collectors to measure time spent in each + * phase of collection. Will also force summary statistics to be + * generated. + */ + public static final boolean TIME_GC_PHASES = false; + + /** + * When true, collector threads measure time spent waiting for + * buffers while processing the Work Deque, and time spent waiting + * in Rendezvous during the collection process. Will also force + * summary statistics to be generated. + */ + public static final boolean MEASURE_WAIT_TIMES = false; + + /** gc threads are indexed from 1 for now... */ + public static final int GC_ORDINAL_BASE = 1; + + /** array of size 1 to count arriving collector threads */ + static final int[] participantCount; + + /** number of collections */ + static int collectionCount; + + /** + * The Handshake object that contains the state of the next or + * current (in progress) collection. Read by mutators when + * detecting a need for a collection, and passed to the collect + * method when requesting a collection. + */ + public static final Handshake handshake; + + /** Use by collector threads to rendezvous during collection */ + public static SynchronizationBarrier gcBarrier; + + /** The base collection attempt */ + public static int collectionAttemptBase = 0; + + /*********************************************************************** + * + * Instance variables + */ + /** arrival order of collectorThreads participating in a collection */ + private int gcOrdinal; + + /** used by each CollectorThread when scanning stacks for references */ + private final ScanThread threadScanner = new ScanThread(); + + /** time waiting in rendezvous (milliseconds) */ + int timeInRendezvous; + + static boolean gcThreadRunning; + + /** The thread to use to determine stack traces if Throwables are created **/ + private Address stackTraceThread; + + /** @return the thread scanner instance associated with this instance */ + @Uninterruptible + public ScanThread getThreadScanner() { return threadScanner; } + + /*********************************************************************** + * + * Initialization + */ + + /** + * Class initializer. This is executed <i>prior</i> to bootstrap + * (i.e. at "build" time). + */ + static { + handshake = new Handshake(); + participantCount = new int[1]; // counter for threads starting a collection + } + + /** + * Constructor + * + * @param stack The stack this thread will run on + * @param processorAffinity The processor with which this thread is + * associated. + */ + CollectorThread(byte[] stack) { + super(stack, myName); + // PNT: need to somehow do this at build time + this.collectorContext = new Selected.Collector(this); + makeDaemon(true); // this is redundant, but harmless + } + + /** + * Is this the GC thread? + * @return true + */ + @Uninterruptible + public boolean isGCThread() { + return true; + } + + /** + * Get the thread to use for building stack traces. + */ + @Uninterruptible + @Override + public RVMThread getThreadForStackTrace() { + if (stackTraceThread.isZero()) + return this; + return (RVMThread)Magic.addressAsObject(stackTraceThread); + } + + /** + * Set the thread to use for building stack traces. + */ + @Uninterruptible + public void setThreadForStackTrace(RVMThread thread) { + stackTraceThread = Magic.objectAsAddress(thread); + } + + /** + * Set the thread to use for building stack traces. + */ + @Uninterruptible + public void clearThreadForStackTrace() { + stackTraceThread = Address.zero(); + } + + /** + * Initialize for boot image. + */ + @Interruptible + public static void init() { + gcBarrier = new SynchronizationBarrier(); + } + + public static void boot() { + handshake.boot(); + gcBarrier.boot(); + } + + /** + * Make a collector thread that will participate in gc.<p> + * + * Note: the new thread's stack must be in pinned memory: currently + * done by allocating it in immortal memory. + * + * @return a new collector thread + */ + @Interruptible + public static CollectorThread createActiveCollectorThread() { + byte[] stack = MemoryManager.newStack(ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_COLLECTOR, true); + return new CollectorThread(stack); + } + + /** + * Initiate a garbage collection. Called by a mutator thread when + * its allocator runs out of space. The caller should pass the + * Handshake that was referenced by the static variable "collect" + * at the time space was unavailable. + * + * @param handshake Handshake for the requested collection + */ + @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") + public static void collect(Handshake handshake, int why) { + Processor.getCurrentFeedlet().addEvent(MMTk_Events.events.gcStart, why); + handshake.requestAndAwaitCompletion(why); + Processor.getCurrentFeedlet().addEvent(MMTk_Events.events.gcStop); + } + + /** + * Initiate a garbage collection at next GC safe point. Called by a + * mutator thread at any time. The caller should pass the + * Handshake that was referenced by the static variable + * "collect". + * + * @param handshake Handshake for the requested collection + */ + @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") + public static void asyncCollect(Handshake handshake, int why) { + handshake.requestAndContinue(why); + } + + /** + * Override Thread.toString + * + * @return A string describing this thread. + */ + @Uninterruptible + public String toString() { + return myName; + } + + /** + * Returns number of collector threads participating in a collection + * + * @return The number of collector threads participating in a collection + */ + @Uninterruptible + public static int numCollectors() { + return (participantCount[0]); + } + + /** + * Return the GC ordinal for this collector thread. An integer, + * 1,2,... assigned to each collector thread participating in the + * current collection. Only valid while GC is "InProgress". + * + * @return The GC ordinal + */ + @Uninterruptible + public int getGCOrdinal() { + return gcOrdinal; + } + + /** + * Set the GC ordinal for this collector thread. An integer, + * 1,2,... assigned to each collector thread participating in the + * current collection. + * + * @param ord The new GC ordinal for this thread + */ + @Uninterruptible + public void setGCOrdinal(int ord) { + gcOrdinal = ord; + } + + /** + * Run method for collector thread (one per processor). Enters + * an infinite loop, waiting for collections to be requested, + * performing those collections, and then waiting again. Calls + * Collection.collect to perform the collection, which will be + * different for the different allocators/collectors that the RVM + * can be configured to use. + */ + @NoOptCompile + // refs stored in registers by opt compiler will not be relocated by GC + @BaselineNoRegisters + // refs stored in registers by baseline compiler will not be relocated by GC, so use stack only + @BaselineSaveLSRegisters + // and store all registers from previous method in prologue, so that we can stack access them while scanning this thread. + @Unpreemptible + public void run() { + // this is kind of stupid. + gcOrdinal = Synchronization.fetchAndAdd(participantCount, Offset.zero(), 1) + GC_ORDINAL_BASE; + + RVMThread.getCurrentThread().disableYieldpoints(); + + for (int count = 0; ; count++) { + // wait for collection to start + + RVMThread.getCurrentThread().enableYieldpoints(); + + /* suspend this thread: it will resume when scheduled by + * Handshake.request(). */ + handshake.parkCollectorThread(); + + RVMThread.getCurrentThread().disableYieldpoints(); + + if (verbose >= 2) VM.sysWriteln("GC Message: CT.run waking up"); + + long startTime = Time.nanoTime(); + + if (verbose > 2) VM.sysWriteln("GC Message: CT.run entering first rendezvous - gcOrdinal =", gcOrdinal); + + boolean userTriggered = handshake.gcTrigger == Collection.EXTERNAL_GC_TRIGGER; + boolean internalPhaseTriggered = handshake.gcTrigger == Collection.INTERNAL_PHASE_GC_TRIGGER; + if (gcOrdinal == GC_ORDINAL_BASE) { + Plan.setCollectionTrigger(handshake.gcTrigger); + } + + /* block all threads. note that some threads will have already blocked + themselves (if they had made their own GC requests). */ + if (gcOrdinal == GC_ORDINAL_BASE) { + if (verbose>=2) VM.sysWriteln("Thread #",getThreadSlot()," is about to block a bunch of threads."); + RVMThread.handshakeLock.lock(); + // fixpoint until there are no threads that we haven't blocked. + // fixpoint is needed in case some thread spawns another thread + // while we're waiting. that is unlikely but possible. + for (;;) { + RVMThread.acctLock.lock(); + RVMThread.processAboutToTerminate(); // community service + int numToHandshake=0; + for (int i=0;i<RVMThread.numThreads;++i) { + RVMThread t=threads[i]; + if (!(t.isGCThread() && !t.isConcurrentGCThread()) && + !t.ignoreHandshakesAndGC()) { + RVMThread.handshakeThreads[numToHandshake++]=t; + } + } + RVMThread.acctLock.unlock(); + + for (int i=0;i<numToHandshake;++i) { + RVMThread t=RVMThread.handshakeThreads[i]; + t.monitor().lock(); + if (t.blockedFor(RVMThread.gcBlockAdapter) || + RVMThread.notRunning(t.asyncBlock(RVMThread.gcBlockAdapter))) { + // already blocked or not running, remove + RVMThread.handshakeThreads[i--]= + RVMThread.handshakeThreads[--numToHandshake]; + RVMThread.handshakeThreads[numToHandshake]=null; // help GC + } + t.monitor().unlock(); + } + + // quit trying to block threads if all threads are either blocked + // or not running (a thread is "not running" if it is NEW or TERMINATED; + // in the former case it means that the thread has not had start() + // called on it while in the latter case it means that the thread + // is either in the TERMINATED state or is about to be in that state + // real soon now, and will not perform any heap-related stuff before + // terminating). + if (numToHandshake==0) break; + + for (int i=0;i<numToHandshake;++i) { + if (verbose>=2) VM.sysWriteln("waiting for ",RVMThread.handshakeThreads[i].getThreadSlot()," to block"); + RVMThread.handshakeThreads[i].block(RVMThread.gcBlockAdapter); + RVMThread.handshakeThreads[i]=null; // help GC + } + } + RVMThread.handshakeLock.unlock(); + if (verbose>=2) { + VM.sysWriteln("Thread #",getThreadSlot()," just blocked a bunch of threads."); + RVMThread.dumpAcct(); + } + } + + /* wait for other collector threads to arrive or be made + * non-participants */ + if (verbose >= 2) VM.sysWriteln("GC Message: CT.run initializing rendezvous"); + gcBarrier.startupRendezvous(); + for (;;) { + /* actually perform the GC... */ + if (verbose >= 2) VM.sysWriteln("GC Message: CT.run starting collection"); + Selected.Collector.get().collect(); // gc + if (verbose >= 2) VM.sysWriteln("GC Message: CT.run finished collection"); + + gcBarrier.rendezvous(5200); + + if (gcOrdinal == GC_ORDINAL_BASE) { + long elapsedTime = Time.nanoTime() - startTime; + HeapGrowthManager.recordGCTime(Time.nanosToMillis(elapsedTime)); + if (Selected.Plan.get().lastCollectionFullHeap() && !internalPhaseTriggered) { + if (Options.variableSizeHeap.getValue() && !userTriggered) { + // Don't consider changing the heap size if gc was forced by System.gc() + HeapGrowthManager.considerHeapSize(); + } + HeapGrowthManager.reset(); + } + + if (internalPhaseTriggered) { + if (Selected.Plan.get().lastCollectionFailed()) { + internalPhaseTriggered = false; + Plan.setCollectionTrigger(Collection.INTERNAL_GC_TRIGGER); + } + } + + if (Scanning.threadStacksScanned()) { + /* Snip reference to any methods that are still marked + * obsolete after we've done stack scans. This allows + * reclaiming them on the next GC. */ + CompiledMethods.snipObsoleteCompiledMethods(); + Scanning.clearThreadStacksScanned(); + + collectionAttemptBase++; + } + + collectionCount += 1; + } + + startTime = Time.nanoTime(); + boolean cont=Selected.Plan.get().lastCollectionFailed() && !Plan.isEmergencyCollection(); + gcBarrier.rendezvous(5201); + if (!cont) break; + } + + if (gcOrdinal == GC_ORDINAL_BASE && !internalPhaseTriggered) { + /* If the collection failed, we may need to throw OutOfMemory errors. + * As we have not cleared the GC flag, allocation is not budgeted. + * + * This is not flawless in the case we physically can not allocate + * anything right after a GC, but that case is unlikely (we can + * not make it happen) and is a lot of work to get around. */ + if (Plan.isEmergencyCollection()) { + RVMThread.getCurrentThread().setEmergencyAllocation(); + boolean gcFailed = Selected.Plan.get().lastCollectionFailed(); + // Allocate OOMEs (some of which *may* not get used) + for(int t=0; t < RVMThread.numThreads; t++) { + RVMThread thread = RVMThread.threads[t]; + if (thread != null) { + if (thread.getCollectionAttempt() > 0) { + /* this thread was allocating */ + if (gcFailed || thread.physicalAllocationFailed()) { + allocateOOMEForThread(thread); + } + } + } + } + RVMThread.getCurrentThread().clearEmergencyAllocation(); + } + } + + /* Wake up mutators waiting for this gc cycle and reset + * the handshake object to be used for next gc cycle. + * Note that mutators will not run until after thread switching + * is enabled, so no mutators can possibly arrive at old + * handshake object: it's safe to replace it with a new one. */ + if (gcOrdinal == GC_ORDINAL_BASE) { + + // reset the handshake. this ensures that once threads are awakened, + // any new GC requests that they make actually result in GC activity. + handshake.reset(); + if (verbose>=2) VM.sysWriteln("Thread #",getThreadSlot()," just reset the handshake."); + + Plan.collectionComplete(); + + if (verbose>=2) VM.sysWriteln("Marked the collection as complete."); + + collectionAttemptBase = 0; + + if (verbose>=2) VM.sysWriteln("Thread #",getThreadSlot()," is unblocking a bunch of threads."); + // and now unblock all threads + RVMThread.handshakeLock.lock(); + RVMThread.acctLock.lock(); + RVMThread.processAboutToTerminate(); // community service + int numToHandshake=0; + for (int i=0;i<RVMThread.numThreads;++i) { + RVMThread t=threads[i]; + if (!(t.isGCThread() && !t.isConcurrentGCThread()) && + !t.ignoreHandshakesAndGC()) { + RVMThread.handshakeThreads[numToHandshake++]=t; + } + } + RVMThread.acctLock.unlock(); + + for (int i=0;i<numToHandshake;++i) { + RVMThread.handshakeThreads[i].unblock(RVMThread.gcBlockAdapter); + RVMThread.handshakeThreads[i]=null; // help GC + } + RVMThread.handshakeLock.unlock(); + if (verbose>=2) VM.sysWriteln("Thread #",getThreadSlot()," just unblocked a bunch of threads."); + + /* schedule the FinalizerThread, if there is work to do & it is idle */ + Collection.scheduleFinalizerThread(); + } + + /* wait for other collector threads to arrive here */ + rendezvous(5210); + if (verbose > 2) VM.sysWriteln("CollectorThread: past rendezvous 1 after collection"); + + /* final cleanup for initial collector thread */ + if (gcOrdinal == GC_ORDINAL_BASE) { + /* clear the GC flags */ + + gcThreadRunning = false; + } // if designated thread + rendezvous(9999); + } // end of while(true) loop + + } // run + + /** + * Return true if no threads are still in GC. + * + * @return <code>true</code> if no threads are still in GC. + */ + @Uninterruptible + public static boolean noThreadsInGC() { + return !gcThreadRunning; + } + + @Uninterruptible + public int rendezvous(int where) { + return gcBarrier.rendezvous(where); + } + + /** + * Allocate an OutOfMemoryError for a given thread. + * @param thread + */ + @UnpreemptibleNoWarn("Calls out to interruptible OOME constructor") + public void allocateOOMEForThread(RVMThread thread) { + /* We are running inside a gc thread, so we will allocate if physically possible */ + this.setThreadForStackTrace(thread); + thread.setOutOfMemoryError(new OutOfMemoryError()); + this.clearThreadForStackTrace(); + } + +} + +/* +Local Variables: + c-basic-offset: 2 +End: +*/ Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ConcurrentCollectorThread.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ConcurrentCollectorThread.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/ConcurrentCollectorThread.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,190 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.ArchitectureSpecific; +import org.jikesrvm.VM; +import org.jikesrvm.scheduler.RVMThread; +import org.jikesrvm.scheduler.HeavyCondLock; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.NonMoving; + +/** + * Threads that perform collector work while mutators are active. these + * threads wait for the collector to activate them. + */ +@NonMoving +public final class ConcurrentCollectorThread extends RVMThread { + + /*********************************************************************** + * + * Class variables + */ + private static final int verbose = 0; + + /** Name used by toString() and when we create the associated + * java.lang.Thread. */ + private static final String myName = "ConcurrentCollectorThread"; + + private static Barrier barrier = new Barrier(); + + + private static HeavyCondLock schedLock; + private static boolean triggerRun; + private static int maxRunning; + private static int running; + + /*********************************************************************** + * + * Instance variables + */ + + /*********************************************************************** + * + * Initialization + */ + + /** + * Constructor + * + * @param stack The stack this thread will run on + * @param processorAffinity The processor with which this thread is + * associated. + */ + ConcurrentCollectorThread(byte[] stack) { + super(stack, myName); + this.collectorContext = new Selected.Collector(this); + makeDaemon(true); // this is redundant, but harmless + } + + /** + * Initialize for boot image. + */ + @Interruptible + public static void init() { + } + + public static void boot() { + maxRunning=RVMThread.numProcessors; + barrier.boot(maxRunning); + schedLock = new HeavyCondLock(); + } + + /** + * Make a concurrent collector thread.<p> + * + * Note: the new thread's stack must be in pinned memory: currently + * done by allocating it in immortal memory. + * + * @param processorAffinity processor to run on + * @return a new collector thread + */ + @Interruptible + public static ConcurrentCollectorThread createConcurrentCollectorThread() { + byte[] stack = MemoryManager.newStack(ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_COLLECTOR, true); + + schedLock.lock(); + running++; + schedLock.unlock(); + + return new ConcurrentCollectorThread(stack); + } + + /** + * Override Thread.toString + * + * @return A string describing this thread. + */ + @Uninterruptible + public String toString() { + return myName; + } + + /** + * Run method for concurrent collector thread. + */ + @Unpreemptible + public void run() { + if (verbose >= 1) VM.sysWriteln("GC Message: Concurrent collector thread entered run..."); + + while (true) { + /* suspend this thread: it will resume when the garbage collector + * notifies it there is work to do. */ + schedLock.lock(); + running--; + if (running==0) { + schedLock.broadcast(); + } + while (!triggerRun) { + schedLock.waitNicely(); + } + running++; + schedLock.unlock(); + + if (barrier.arrive(1)) { + schedLock.lock(); + triggerRun=false; + schedLock.broadcast(); + schedLock.unlock(); + } + + if (verbose >= 1) VM.sysWriteln("GC Message: Concurrent collector awake"); + Selected.Collector.get().concurrentCollect(); + if (verbose >= 1) VM.sysWriteln("GC Message: Concurrent collector finished"); + } + } + + @Uninterruptible + public static void scheduleConcurrentCollectorThreads() { + schedLock.lock(); + if (true) { + // this code is what is needed to make it work + // but this is dangerous ... do we know that the concurrent workers will go into + // quiescence before this is called? + if (!triggerRun && running==0) { + // now start a new cycle + triggerRun=true; + schedLock.broadcast(); + } + } else { + // this is the code I'd much rather be using + // wait for previous concurrent collection cycle to finish + while (triggerRun || running!=0) { + schedLock.waitNicely(); + } + // now start a new cycle + triggerRun=true; + schedLock.broadcast(); + } + schedLock.unlock(); + } + + /** + * Is this a concurrent collector thread? Concurrent collector threads + * need to be stopped during GC. + * @return true + */ + @Uninterruptible + public boolean isConcurrentGCThread() { + return true; + } + +} + +/* +Local Variables: + c-basic-offset: 2 +End: +*/ Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/DebugUtil.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/DebugUtil.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/DebugUtil.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,188 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.VM; +import org.jikesrvm.classloader.RVMArray; +import org.jikesrvm.classloader.RVMType; +import org.jikesrvm.objectmodel.ObjectModel; +import org.jikesrvm.objectmodel.TIB; +import org.jikesrvm.runtime.BootRecord; +import org.jikesrvm.runtime.Magic; +import org.jikesrvm.scheduler.RVMThread; +import org.mmtk.policy.Space; +import org.mmtk.utility.heap.Mmapper; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.ObjectReference; + +/** + * Common debugging utility functions used by various garbage collectors + */ +@Uninterruptible +public class DebugUtil implements org.mmtk.utility.Constants, org.jikesrvm.Constants { + + private static TIB tibForArrayType; + private static TIB tibForClassType; + private static TIB tibForPrimitiveType; + + @Interruptible + static void boot(BootRecord theBootRecord) { + // get addresses of TIBs for RVMArray & RVMClass used for testing Type ptrs + RVMType t = RVMArray.IntArray; + tibForArrayType = ObjectModel.getTIB(t); + tibForPrimitiveType = ObjectModel.getTIB(RVMType.IntType); + t = Magic.getObjectType(BootRecord.the_boot_record); + tibForClassType = ObjectModel.getTIB(t); + } + + /** + * Check if an address appears to point to an instance of RVMType + * + * @param typeAddress the address to check + */ + @Uninterruptible + public static boolean validType(ObjectReference typeAddress) { + if (!Space.isMappedObject(typeAddress)) { + return false; // type address is outside of heap + } + + // check if types tib is one of three possible values + TIB typeTib = ObjectModel.getTIB(typeAddress); + return ((typeTib == tibForClassType) || (typeTib == tibForArrayType) || (typeTib == tibForPrimitiveType)); + } + + /** + * Dump all threads & their stacks starting at the frame identified + * by the threads saved contextRegisters (ip & fp fields). + */ + @Uninterruptible + public static void dumpAllThreadStacks() { + RVMThread.dumpVirtualMachine(); + } // dumpAllThreadStacks + + /** + * Check if a ref, its tib pointer & type pointer are all in the heap + */ + @Uninterruptible + public static boolean validObject(Object ref) { + return validRef(ObjectReference.fromObject(ref)); + } + + @Uninterruptible + public static boolean validRef(ObjectReference ref) { + + if (ref.isNull()) return true; + if (!Space.isMappedObject(ref)) { + VM.sysWrite("validRef: REF outside heap, ref = "); + VM.sysWrite(ref); + VM.sysWrite("\n"); + Space.printVMMap(); + return false; + } + if (MemoryManagerConstants.MOVES_OBJECTS) { + /* + TODO: Work out how to check if forwarded + if (Plan.isForwardedOrBeingForwarded(ref)) { + // TODO: actually follow forwarding pointer + // (need to bound recursion when things are broken!!) + return true; + } + */ + } + + TIB tib = ObjectModel.getTIB(ref); + Address tibAddr = Magic.objectAsAddress(tib); + if (!Space.isMappedObject(ObjectReference.fromObject(tib))) { + VM.sysWrite("validRef: TIB outside heap, ref = "); + VM.sysWrite(ref); + VM.sysWrite(" tib = "); + VM.sysWrite(tibAddr); + VM.sysWrite("\n"); + ObjectModel.dumpHeader(ref); + return false; + } + if (tibAddr.isZero()) { + VM.sysWrite("validRef: TIB is Zero! "); + VM.sysWrite(ref); + VM.sysWrite("\n"); + ObjectModel.dumpHeader(ref); + return false; + } + if (tib.length() == 0) { + VM.sysWrite("validRef: TIB length zero, ref = "); + VM.sysWrite(ref); + VM.sysWrite(" tib = "); + VM.sysWrite(tibAddr); + VM.sysWrite("\n"); + ObjectModel.dumpHeader(ref); + return false; + } + + ObjectReference type = ObjectReference.fromObject(tib.getType()); + if (!validType(type)) { + VM.sysWrite("validRef: invalid TYPE, ref = "); + VM.sysWrite(ref); + VM.sysWrite(" tib = "); + VM.sysWrite(Magic.objectAsAddress(tib)); + VM.sysWrite(" type = "); + VM.sysWrite(type); + VM.sysWrite("\n"); + ObjectModel.dumpHeader(ref); + return false; + } + return true; + } // validRef + + @Uninterruptible + public static boolean mappedVMRef(ObjectReference ref) { + return Space.isMappedObject(ref) && Mmapper.objectIsMapped(ref); + } + + @Uninterruptible + public static void dumpRef(ObjectReference ref) { + VM.sysWrite("REF="); + if (ref.isNull()) { + VM.sysWrite("NULL\n"); + return; + } + VM.sysWrite(ref); + if (!mappedVMRef(ref)) { + VM.sysWrite(" (REF OUTSIDE OF HEAP OR NOT MAPPED)\n"); + return; + } + ObjectModel.dumpHeader(ref); + ObjectReference tib = ObjectReference.fromObject(ObjectModel.getTIB(ref)); + if (!MemoryManager.mightBeTIB(tib)) { + VM.sysWrite(" (INVALID TIB: CLASS NOT ACCESSIBLE)\n"); + return; + } + RVMType type = Magic.getObjectType(ref.toObject()); + ObjectReference itype = ObjectReference.fromObject(type); + VM.sysWrite(" TYPE="); + VM.sysWrite(itype); + if (!validType(itype)) { + VM.sysWrite(" (INVALID TYPE: CLASS NOT ACCESSIBLE)\n"); + return; + } + VM.sysWrite(" CLASS="); + VM.sysWrite(type.getDescriptor()); + VM.sysWrite("\n"); + } + + public static boolean addrInBootImage(Address addr) { + return (addr.GE(BOOT_IMAGE_DATA_START) && addr.LT(BOOT_IMAGE_DATA_END)) || + (addr.GE(BOOT_IMAGE_CODE_START) && addr.LT(BOOT_IMAGE_CODE_END)); + } +} Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIterator.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIterator.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIterator.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,102 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.compilers.common.CompiledMethod; +import org.jikesrvm.scheduler.RVMThread; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.WordArray; + +/** + * Base class for iterators that identify object references and JSR return addresses + * held in stackframes produced by each of our compilers (baseline, opt, etc.). + * All compiler specific GCMapIterators extend this abstract class. + * + * @see GCMapIteratorGroup + */ +@Uninterruptible +public abstract class GCMapIterator { + + /** thread whose stack is currently being scanned */ + public RVMThread thread; + + /** address of stackframe currently being scanned */ + public Address framePtr; + + /** address where each gpr register was saved by previously scanned stackframe(s) */ + public WordArray registerLocations; + + /** + * Prepare to scan a thread's stack and saved registers for object references. + * + * @param thread Thread whose stack is being scanned + */ + public void newStackWalk(RVMThread thread) { + this.thread = thread; + } + + /** + * Prepare to iterate over object references and JSR return addresses held by a stackframe. + * + * @param compiledMethod method running in the stackframe + * @param instructionOffset offset of current instruction within that method's code + * @param framePtr address of stackframe to be visited + */ + public abstract void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr); + + /** + * Get address of next object reference held by current stackframe. + * Returns zero when there are no more references to report. + * <p> + * Side effect: registerLocations[] updated at end of iteration. + * TODO: registerLocations[] update should be done via separately called + * method instead of as side effect. + * <p> + * + * @return address of word containing an object reference + * zero if no more references to report + */ + public abstract Address getNextReferenceAddress(); + + /** + * Get address of next JSR return address held by current stackframe. + * + * @return address of word containing a JSR return address + * zero if no more return addresses to report + */ + public abstract Address getNextReturnAddressAddress(); + + /** + * Prepare to re-iterate on same stackframe, and to switch between + * "reference" iteration and "JSR return address" iteration. + */ + public abstract void reset(); + + /** + * Iteration is complete, release any internal data structures including + * locks acquired during setupIterator for jsr maps. + */ + public abstract void cleanupPointers(); + + /** + * Get the type of this iterator (BASELINE, OPT, etc.). + * Called from GCMapIteratorGroup to select which iterator + * to use for a stackframe. The possible types are specified + * in CompiledMethod. + * + * @return type code for this iterator + */ + public abstract int getType(); +} Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIteratorGroup.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIteratorGroup.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/GCMapIteratorGroup.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,138 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.ArchitectureSpecific; +import org.jikesrvm.ArchitectureSpecific.BaselineGCMapIterator; +import org.jikesrvm.ArchitectureSpecific.JNIGCMapIterator; +import org.jikesrvm.ArchitectureSpecificOpt.OptGCMapIterator; +import org.jikesrvm.VM; +import org.jikesrvm.SizeConstants; +import org.jikesrvm.compilers.common.CompiledMethod; +import org.jikesrvm.compilers.common.HardwareTrapGCMapIterator; +import org.jikesrvm.scheduler.RVMThread; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.WordArray; + +/** + * Maintains a collection of compiler specific GCMapIterators that are used + * by collection threads when scanning thread stacks to locate object references + * in those stacks. Each collector thread has its own GCMapIteratorGroup. + * + * The group contains a GCMapIterator for each type of stack frame that + * may be found while scanning a stack during garbage collection, including + * frames for baseline compiled methods, OPT compiled methods, and frames + * for transitions from Java into JNI native code. These iterators are + * repsonsible for reporting the location of references in the stack or + * register save areas. + * + * @see GCMapIterator + * @see CompiledMethod + * @see CollectorThread + */ +public final class GCMapIteratorGroup implements SizeConstants { + + /** current location (memory address) of each gpr register */ + private final WordArray registerLocations; + + /** iterator for baseline compiled frames */ + private final GCMapIterator baselineIterator; + + /** iterator for opt compiled frames */ + private final GCMapIterator optIterator; + + /** iterator for HardwareTrap stackframes */ + private final GCMapIterator hardwareTrapIterator; + + /** iterator for JNI Java -> C stackframes */ + private final GCMapIterator jniIterator; + + public GCMapIteratorGroup() { + registerLocations = WordArray.create(ArchitectureSpecific.ArchConstants.NUM_GPRS); + + baselineIterator = new BaselineGCMapIterator(registerLocations); + if (VM.BuildForOptCompiler) { + optIterator = new OptGCMapIterator(registerLocations); + } else { + optIterator = null; + } + jniIterator = new JNIGCMapIterator(registerLocations); + hardwareTrapIterator = new HardwareTrapGCMapIterator(registerLocations); + } + + /** + * Prepare to scan a thread's stack for object references. + * Called by collector threads when beginning to scan a threads stack. + * Calls newStackWalk for each of the contained GCMapIterators. + * <p> + * Assumption: the thread is currently suspended, ie. its saved gprs[] + * contain the thread's full register state. + * <p> + * Side effect: registerLocations[] initialized with pointers to the + * thread's saved gprs[] (in thread.contextRegisters.gprs) + * <p> + * @param thread Thread whose registers and stack are to be scanned + */ + @Uninterruptible + public void newStackWalk(RVMThread thread, Address registerLocation) { + for (int i = 0; i < ArchitectureSpecific.ArchConstants.NUM_GPRS; ++i) { + registerLocations.set(i, registerLocation.toWord()); + registerLocation = registerLocation.plus(BYTES_IN_ADDRESS); + } + baselineIterator.newStackWalk(thread); + if (VM.BuildForOptCompiler) { + optIterator.newStackWalk(thread); + } + hardwareTrapIterator.newStackWalk(thread); + jniIterator.newStackWalk(thread); + } + + /** + * Select iterator for scanning for object references in a stackframe. + * Called by collector threads while scanning a threads stack. + * + * @param compiledMethod CompiledMethod for the method executing + * in the stack frame + * + * @return GCMapIterator to use + */ + @Uninterruptible + public GCMapIterator selectIterator(CompiledMethod compiledMethod) { + switch (compiledMethod.getCompilerType()) { + case CompiledMethod.TRAP: + return hardwareTrapIterator; + case CompiledMethod.BASELINE: + return baselineIterator; + case CompiledMethod.OPT: + return optIterator; + case CompiledMethod.JNI: + return jniIterator; + } + if (VM.VerifyAssertions) { + VM._assert(false, "GCMapIteratorGroup.selectIterator: Unknown type of compiled method"); + } + return null; + } + + /** + * get the GCMapIterator used for scanning JNI native stack frames. + * + * @return jniIterator + */ + @Uninterruptible + public GCMapIterator getJniIterator() { + if (VM.VerifyAssertions) VM._assert(jniIterator != null); + return jniIterator; + } +} Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Handshake.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Handshake.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/Handshake.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,171 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import org.jikesrvm.VM; +import org.jikesrvm.mm.mmtk.Collection; +import org.jikesrvm.mm.mmtk.Lock; +import org.jikesrvm.scheduler.RVMThread; +import org.jikesrvm.scheduler.HeavyCondLock; +import org.vmmagic.pragma.LogicallyUninterruptible; +import org.vmmagic.pragma.Uninterruptible; +import org.mmtk.plan.Plan; + +/** + * Handshake handles mutator requests to initiate a collection, and + * wait for a collection to complete. It implements the process of + * suspending all mutator threads executing in Java and starting all + * the GC threads (CollectorThreads) for the processors that will + * be participating in a collection. This may not be all processors, + * if we exclude those executing in native code. + * + * Because the threading strategy within RVM is currently under + * revision, the logic here is also changing and somewhat "messy". + * + * @see CollectorThread + */ +public class Handshake { + + /*********************************************************************** + * + * Class variables + */ + public static final int verbose = 0; + + /*********************************************************************** + * + * Instance variables + */ + private HeavyCondLock lock; + protected boolean requestFlag; + public int gcTrigger; // reason for this GC + private int collectorThreadsParked; + + public Handshake() { + reset(); + } + + public void boot() { + lock = new HeavyCondLock(); + } + + /** + * Call this if you know that a GC request has already been made and you'd like + * to wait on that GC to finish - presumably because you're trying to allocate + * and cannot reasonably do so before GC is done. Note, there CANNOT be a + * GC safe point between when you realize that there is already a GC request and + * when you call this method! + */ + @Unpreemptible + public void waitForGCToFinish() { + if (verbose >= 1) VM.sysWriteln("GC Message: Handshake.requestAndAwaitCompletion - yielding"); + /* allow a gc thread to run */ + RVMThread.getCurrentThread().block(RVMThread.gcBlockAdapter); + if (verbose >= 1) VM.sysWriteln("GC Message: Handshake.requestAndAwaitCompletion - mutator running"); + } + + /** + * Called by mutators to request a garbage collection and wait for + * it to complete. + * + * Waiting is actually just yielding the processor to schedule the + * collector thread, which will disable further thread switching on + * the processor until it has completed the collection. + */ + @Unpreemptible + public void requestAndAwaitCompletion(int why) { + request(why); + waitForGCToFinish(); + } + + /** + * Called by mutators to request an asynchronous garbage collection. + * After initiating a GC (if one is not already initiated), the + * caller continues until it yields to the GC. It may thus make + * this call at an otherwise unsafe point. + */ + @Unpreemptible("Change state of thread possibly context switching if generating exception") + public void requestAndContinue(int why) { + request(why); + } + + @Unpreemptible + public void reset() { + if (lock!=null) { + lock.lock(); + } + gcTrigger = Collection.UNKNOWN_GC_TRIGGER; + requestFlag = false; + if (lock!=null) { + lock.unlock(); + } + } + + void parkCollectorThread() { + lock.lock(); + collectorThreadsParked++; + lock.broadcast(); + if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," parked."); + while (!requestFlag) { + if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," waiting for request."); + lock.waitNicely(); + } + if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," got request, unparking."); + collectorThreadsParked--; + lock.unlock(); + } + + /** + * Called by mutators to request a garbage collection. + * + * @return true if the completion flag is not already set. + */ + @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") + private boolean request(int why) { + if (verbose>=1) VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot()," is trying to make a GC request"); + lock.lock(); + if (verbose>=1) VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot()," acquired the lock for making a GC request"); + if (why > gcTrigger) gcTrigger = why; + if (requestFlag) { + if (verbose >= 1) { + VM.sysWriteln("GC Message: mutator: already in progress"); + } + } else { + // first mutator initiates collection by making all gc threads + // runnable at high priority + if (verbose >= 1) VM.sysWriteln("GC Message: Handshake - mutator: initiating collection"); + + if (!RVMThread.threadingInitialized) { + VM.sysWrite("GC required before system fully initialized"); + VM.sysWriteln("Specify larger than default heapsize on command line"); + RVMThread.dumpStack(); + VM.shutdown(VM.EXIT_STATUS_MISC_TROUBLE); + } + + requestFlag = true; + + Plan.setCollectionTriggered(); + + lock.broadcast(); + } + lock.unlock(); + return true; + } +} + +/* +Local Variables: + c-basic-offset: 2 +End: +*/ + Added: rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/MemoryManager.java =================================================================== --- rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/MemoryManager.java (rev 0) +++ rvmroot/branches/RVM-PureNativeThread/workingMergeUp/rvm/src/org/jikesrvm/mm/mminterface/MemoryManager.java 2008-11-04 14:59:30 UTC (rev 15137) @@ -0,0 +1,1327 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.mm.mminterface; + +import java.lang.ref.PhantomReference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import org.jikesrvm.ArchitectureSpecific.CodeArray; +import org.jikesrvm.VM; +import org.jikesrvm.HeapLayoutConstants; +import org.jikesrvm.classloader.RVMArray; +import org.jikesrvm.classloader.RVMClass; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.classloader.SpecializedMethod; +import org.jikesrvm.classloader.RVMType; +import org.jikesrvm.classloader.TypeReference; +import org.jikesrvm.mm.mmtk.Collection; +import org.jikesrvm.mm.mmtk.FinalizableProcessor; +import org.jikesrvm.mm.mmtk.ReferenceProcessor; +import org.jikesrvm.mm.mmtk.SynchronizedCounter; +import org.jikesrvm.objectmodel.BootImageInterface; +import org.jikesrvm.objectmodel.IMT; +import org.jikesrvm.objectmodel.ITable; +import org.jikesrvm.objectmodel.ITableArray; +import org.jikesrvm.objectmodel.JavaHeader; +import org.jikesrvm.objectmodel.ObjectModel; +import org.jikesrvm.objectmodel.TIB; +import org.jikesrvm.objectmodel.TIBLayoutConstants; +import org.jikesrvm.options.OptionSet; +import org.jikesrvm.runtime.BootRecord; +import org.jikesrvm.runtime.Magic; +import org.mmtk.plan.Plan; +import org.mmtk.policy.Space; +import org.mmtk.utility.Constants; +import org.mmtk.utility.Memory; +import org.mmtk.utility.alloc.Allocator; +import org.mmtk.utility.gcspy.GCspy; +import org.mmtk.utility.heap.HeapGrowthManager; +import org.mmtk.utility.heap.Mmapper; +import org.mmtk.utility.options.Options; +import org.vmmagic.pragma.Entrypoint; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Pure; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.UnpreemptibleNoWarn; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Extent; +import org.vmmagic.unboxed.ObjectReference; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; +import org.vmmagic.unboxed.WordArray; + +/** + * The interface that the JMTk memory manager presents to the Jikes + * research virtual machine. + */ +@Uninterruptible +public final class MemoryManager implements HeapLayoutConstants, Constants { + + /*********************************************************************** + * + * Class variables + */ + + /** + * <code>true</code> if checking of allocated memory to ensure it is + * zeroed is desired. + */ + private static final boolean CHECK_MEMORY_IS_ZEROED = false; + + private static final boolean traceAllocator = false; + + /** + * Hash the interface been booted yet? + */ + private static boolean booted = false; + + /*********************************************************************** + * + * Initialization + */ + + /** + * Suppress default constructor to enforce noninstantiability. + */ + private MemoryManager() {} // This constructor will never be invoked. + + /** + * Initialization that occurs at <i>build</i> time. The value of + * statics as at the completion of this routine will be reflected in + * the boot image. Any objects referenced by those statics will be + * transitively included in the boot image. + * + * This is the entry point for all build-time activity in the collector. + */ + @Interruptible + public static void init() { + if (VM.VerifyAssertions) VM._assert(!Selected.Constraints.get().needsStaticReadBarrier()); + CollectorThread.init(); + ConcurrentCollectorThread.init(); + org.jikesrvm.mm.mmtk.Collection.init(); + } + + /** + * Initialization that occurs at <i>boot</i> time (runtime + * initialization). This is only executed by one processor (the + * primordial thread). + * @param theBootRecord the boot record. Contains information about + * the heap size. + */ + @Interruptible + public static void boot(BootRecord theBootRecord) { + Mmapper.markAsMapped(BOOT_IMAGE_DATA_START, BOOT_IMAGE_DATA_SIZE); + Mmapper.markAsMapped(BOOT_IMAGE_CODE_START, BOOT_IMAGE_CODE_SIZE); + HeapGrowthManager.boot(theBootRecord.initialHeapSize, theBootRecord.maximumHeapSize); + DebugUtil.boot(theBootRecord); + Selected.Plan.get().boot(); + SynchronizedCounter.boot(); + Monitor.boot(); + booted = true; + } + + /** + * Perform postBoot operations such as dealing with command line + * options (this is called as soon as options have been parsed, + * which is necessarily after the basic allocator boot). + */ + @Interruptible + public static void postBoot() { + Selected.Plan.get().postBoot(); + + if (Options.noReferenceTypes.getValue()) { + RVMType.JavaLangRefReferenceReferenceField.makeTraced(); + } + + if (VM.BuildWithGCSpy) { + // start the GCSpy interpreter server + MemoryManager.startGCspyServer(); + } + } + + /** + * Notify the MM that the host VM is now fully booted. + */ + @Interruptible + public static void fullyBootedVM() { + Selected.Plan.get().fullyBooted(); + } + + /** + * Process GC parameters. + */ + @Interruptible + public static void processCommandLineArg(String arg) { + if (!OptionSet.gc.process(arg)) { + VM.sysWriteln("Unrecognized command line argument: \"" + arg + "\""); + VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); + } + } + + /*********************************************************************** + * + * Write barriers + */ + + /** + * Write barrier for putfield operations. + * + * @param ref the object which is the subject of the putfield + * @param offset the offset of the field to be modified + * @param... [truncated message content] |