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