001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.mm.mmtk;
014    
015    import org.mmtk.plan.CollectorContext;
016    import org.mmtk.plan.MutatorContext;
017    
018    import org.jikesrvm.ArchitectureSpecific;
019    import org.jikesrvm.VM;
020    import org.jikesrvm.mm.mminterface.MemoryManager;
021    import org.jikesrvm.mm.mminterface.Selected;
022    import org.jikesrvm.mm.mminterface.CollectorThread;
023    import org.jikesrvm.runtime.SysCall;
024    import org.jikesrvm.scheduler.RVMThread;
025    import org.jikesrvm.scheduler.FinalizerThread;
026    
027    import org.vmmagic.pragma.Interruptible;
028    import org.vmmagic.pragma.Uninterruptible;
029    import org.vmmagic.pragma.UninterruptibleNoWarn;
030    import org.vmmagic.pragma.Unpreemptible;
031    import org.vmmagic.unboxed.Address;
032    
033    @Uninterruptible
034    public class Collection extends org.mmtk.vm.Collection implements org.mmtk.utility.Constants,
035                                                                      org.jikesrvm.Constants {
036    
037      /****************************************************************************
038       *
039       * Class variables
040       */
041    
042      /**
043       * {@inheritDoc}
044       */
045      @Override
046      @Interruptible
047      public void spawnCollectorContext(CollectorContext context) {
048        byte[] stack = MemoryManager.newStack(ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_COLLECTOR);
049        CollectorThread t = new CollectorThread(stack, context);
050        t.start();
051      }
052    
053      @Override
054      public int getDefaultThreads() {
055        return SysCall.sysCall.sysNumProcessors();
056      }
057    
058      @Override
059      public int getActiveThreads() {
060        return RVMThread.getNumActiveThreads() - RVMThread.getNumActiveDaemons();
061      }
062    
063      @Override
064      @Unpreemptible
065      public void blockForGC() {
066        RVMThread t=RVMThread.getCurrentThread();
067        t.assertAcceptableStates(RVMThread.IN_JAVA, RVMThread.IN_JAVA_TO_BLOCK);
068        RVMThread.observeExecStatusAtSTW(t.getExecStatus());
069        RVMThread.getCurrentThread().block(RVMThread.gcBlockAdapter);
070      }
071    
072      /***********************************************************************
073       *
074       * Initialization
075       */
076    
077      /**
078       * {@inheritDoc}
079       */
080      @Override
081      @UninterruptibleNoWarn
082      public void outOfMemory() {
083        throw RVMThread.getOutOfMemoryError();
084      }
085    
086      @Override
087      public final void prepareMutator(MutatorContext m) {
088        /*
089         * The collector threads of processors currently running threads
090         * off in JNI-land cannot run.
091         */
092        RVMThread t = ((Selected.Mutator) m).getThread();
093        t.monitor().lockNoHandshake();
094        // are these the only unexpected states?
095        t.assertUnacceptableStates(RVMThread.IN_JNI,RVMThread.IN_NATIVE);
096        int execStatus = t.getExecStatus();
097        // these next assertions are not redundant given the ability of the
098        // states to change asynchronously, even when we're holding the lock, since
099        // the thread may change its own state.  of course that shouldn't happen,
100        // but having more assertions never hurts...
101        if (VM.VerifyAssertions) VM._assert(execStatus != RVMThread.IN_JNI);
102        if (VM.VerifyAssertions) VM._assert(execStatus != RVMThread.IN_NATIVE);
103        if (execStatus == RVMThread.BLOCKED_IN_JNI) {
104          if (false) {
105            VM.sysWriteln("for thread #",t.getThreadSlot()," setting up JNI stack scan");
106            VM.sysWriteln("thread #",t.getThreadSlot()," has top java fp = ",t.getJNIEnv().topJavaFP());
107          }
108    
109          /* thread is blocked in C for this GC.
110           Its stack needs to be scanned, starting from the "top" java
111           frame, which has been saved in the running threads JNIEnv.  Put
112           the saved frame pointer into the threads saved context regs,
113           which is where the stack scan starts. */
114          t.contextRegisters.setInnermost(Address.zero(), t.getJNIEnv().topJavaFP());
115        }
116        t.monitor().unlock();
117      }
118    
119      @Override
120      @Unpreemptible
121      public void stopAllMutators() {
122        RVMThread.blockAllMutatorsForGC();
123      }
124    
125      @Override
126      @Unpreemptible
127      public void resumeAllMutators() {
128        RVMThread.unblockAllMutatorsForGC();
129      }
130    
131      private static RVMThread.SoftHandshakeVisitor mutatorFlushVisitor =
132        new RVMThread.SoftHandshakeVisitor() {
133          @Override
134          @Uninterruptible
135          public boolean checkAndSignal(RVMThread t) {
136            t.flushRequested = true;
137            return true;
138          }
139          @Override
140          @Uninterruptible
141          public void notifyStuckInNative(RVMThread t) {
142            t.flush();
143            t.flushRequested = false;
144          }
145          @Override
146          @Uninterruptible
147          public boolean includeThread(RVMThread t) {
148            return !t.isCollectorThread();
149          }
150        };
151    
152      @Override
153      @UninterruptibleNoWarn("This method is really unpreemptible, since it involves blocking")
154      public void requestMutatorFlush() {
155        Selected.Mutator.get().flush();
156        RVMThread.softHandshake(mutatorFlushVisitor);
157      }
158    
159      /***********************************************************************
160       *
161       * Finalizers
162       */
163    
164      /**
165       * Schedule the finalizerThread, if there are objects to be
166       * finalized and the finalizerThread is on its queue (ie. currently
167       * idle).  Should be called at the end of GC after moveToFinalizable
168       * has been called, and before mutators are allowed to run.
169       */
170      @Uninterruptible
171      public static void scheduleFinalizerThread() {
172        int finalizedCount = FinalizableProcessor.countReadyForFinalize();
173        if (finalizedCount > 0) {
174          FinalizerThread.schedule();
175        }
176      }
177    }
178