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