/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * 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/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.jni; import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.jikesrvm.compilers.common.CompiledMethod; import org.jikesrvm.mm.mminterface.GCMapIterator; import org.jikesrvm.runtime.Magic; import org.jikesrvm.scheduler.RVMThread; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.AddressArray; import org.vmmagic.unboxed.Offset; /** * This class implements the architecture-independent functionality that is used * by all currently implemented JNI GC map iterators. */ @Uninterruptible public abstract class AbstractJNIGCMapIterator extends GCMapIterator { protected AddressArray jniRefs; protected int jniNextRef; protected int jniFramePtr; public static final int verbose = 0; public AbstractJNIGCMapIterator(AddressArray registerLocations) { super(registerLocations); } @Override public final void newStackWalk(RVMThread thread) { super.newStackWalk(thread); JNIEnvironment env = this.thread.getJNIEnv(); // the "primordial" thread, created by JDK in the bootimage, does not have // a JniEnv object, all threads created by the VM will. if (env != null) { this.jniRefs = env.refsArray(); this.jniNextRef = env.refsTop(); this.jniFramePtr = env.savedRefsFP(); } } @Override public final void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr) { this.framePtr = framePtr; setupIteratorForArchitecture(); } protected abstract void setupIteratorForArchitecture(); /** * Returns (address of) next ref in the current "frame" on the * threads JNIEnvironment stack of refs. When at the end of the current frame, * update register locations to point to the non-volatile registers saved in * the JNI transition frame. */ @Override public final Address getNextReferenceAddress() { // first report JNI refs in the current frame in the jniRef side stack // until all in the frame are reported // if (jniNextRef > jniFramePtr) { Address ref_address = Magic.objectAsAddress(jniRefs).plus(jniNextRef); jniNextRef -= BYTES_IN_ADDRESS; if (verbose > 0) VM.sysWriteln("JNI iterator returning JNI ref: ", ref_address); return ref_address; } // no more refs to report, before returning 0, setup for processing // the next JNI frame, if any // jniNextRef -> savedFramePtr for another "frame" of refs for another // sequence of Native C frames lower in the stack, or to 0 if this is the // last JNI frame in the JNIRefs stack. If more frames, initialize for a // later scan of those refs. // if (jniFramePtr > 0) { jniFramePtr = jniRefs.get(jniFramePtr >> LOG_BYTES_IN_ADDRESS).toInt(); jniNextRef = jniNextRef - BYTES_IN_ADDRESS; } setRegisterLocations(); if (verbose > 1) VM.sysWriteln("JNI iterator returning 0"); return Address.zero(); // no more refs to report } protected abstract void setRegisterLocations(); @Override public final void reset() { // resetting is completely handled by iterator setup for the // currently implemented architectures } @Override public final void cleanupPointers() { // no cleanup necessary for current architectures } /** * @return {@link CompiledMethod#JNI JNI} */ @Override public final int getType() { return CompiledMethod.JNI; } }