/* * 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.jni.ppc; import org.jikesrvm.VM; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.jni.VM_JNIEnvironment; import org.jikesrvm.memorymanagers.mminterface.VM_GCMapIterator; import org.jikesrvm.ppc.VM_BaselineConstants; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.scheduler.VM_Thread; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.AddressArray; import org.vmmagic.unboxed.LocalAddress; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.WordArray; /** * Iterator for stack frames inserted at the transition from Java to * JNI Native C. It will report JREFs associated with the executing * C frames which are in the "JREFs stack" attached to the executing * Threads JNIEnvironment. It will update register location addresses * for the non-votatile registers to point to the register save area * in the transition frame. * * If GC happens, the saved non-volatile regs may get modified (ex. a ref * to a live object that gets moved), and a restore flag in the frame is * set to cause the returning Native code to restore those registers from * this save area. If GC does not occur, the Native C code has restored * these regs, and the transition return code does not do the restore. */ @Uninterruptible public abstract class VM_JNIGCMapIterator extends VM_GCMapIterator implements VM_BaselineConstants, VM_JNIStackframeLayoutConstants { // non-volitile regs are saved at the end of the transition frame, // after the saved JTOC and SP, and preceeded by a GC flag. // // JNI Java to Native C transition frame... // // <-- | saved FP | <- this.framePtr // | | ... | // | | ... | // | | GC flag | // | | saved affinity | // | | proc reg | // | | non vol 17 | // | | ... | // | | non vol 31 | // | | saved SP | // | | saved JTOC | // --> | | <- callers FP // // The following constant is the offset from the callers FP to // the GC flag at the beginning of this area. // public static int verbose = 0; // additional instance fields added by this subclass of VM_GCMapIterator private AddressArray jniRefs; private int jniNextRef; private int jniFramePtr; private LocalAddress jniSavedReturnAddr; public VM_JNIGCMapIterator(WordArray registerLocations) { this.registerLocations = registerLocations; } // Override newStackWalk() in parent class VM_GCMapIterator to // initialize iterator for scan of JNI JREFs stack of refs // Taken: thread // Returned: nothing // public void newStackWalk(VM_Thread thread) { super.newStackWalk(thread); // sets this.thread VM_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.JNIRefs; this.jniNextRef = env.JNIRefsTop; this.jniFramePtr = env.JNIRefsSavedFP; } } public void setupIterator(VM_CompiledMethod compiledMethod, Offset instructionOffset, LocalAddress framePtr) { this.framePtr = framePtr; // processor reg (R16) was saved in reg save area at offset -72 // from callers frameptr, and after GC will be used to set // processor reg upon return to java. it must be reported // so it will be relocated, if necessary // LocalAddress callers_fp = this.framePtr.loadLocalAddress(); if (VM.BuildForPowerOpenABI) { jniSavedReturnAddr = callers_fp.minus(JNI_PROLOG_RETURN_ADDRESS_OFFSET); } else { if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI || VM.BuildForMachOABI); // ScanThread calls getReturnAddressLocation() to get this stack frame // it is already processed jniSavedReturnAddr = LocalAddress.zero(); } // set the GC flag in the Java to C frame to indicate GC occurred // this forces saved non volatile regs to be restored from save area // where those containing refs have been relocated if necessary // callers_fp.minus(JNI_GC_FLAG_OFFSET).store(1); } // return (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. // public LocalAddress getNextReferenceAddress() { if (jniNextRef > jniFramePtr) { LocalAddress ref_address = VM_Magic.objectAsLocalAddress(jniRefs).plus(jniNextRef); jniNextRef = jniNextRef - BYTES_IN_ADDRESS; if (verbose > 0) VM.sysWriteln("JNI iterator returning JNI ref: ", ref_address); return ref_address; } // 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; } // set register locations for non-volatiles to point to registers saved in // the JNI transition frame at a fixed negative offset from the callers FP. LocalAddress registerLocation = this.framePtr.loadLocalAddress().minus(JNI_RVM_NONVOLATILE_OFFSET); for (int i = LAST_NONVOLATILE_GPR; i >= FIRST_NONVOLATILE_GPR - 1; --i) { registerLocations.set(i, registerLocation.toWord()); registerLocation = registerLocation.minus(BYTES_IN_ADDRESS); } if (verbose > 1) VM.sysWriteln("JNI iterator returning 0"); return LocalAddress.zero(); // no more refs to report } public LocalAddress getNextReturnAddressAddress() { if (!jniSavedReturnAddr.isZero()) { LocalAddress ref_address = jniSavedReturnAddr; jniSavedReturnAddr = LocalAddress.zero(); if (verbose > 0) { VM.sysWriteln("JNI getNextReturnAddressAddress returning ", ref_address); } return ref_address; } return LocalAddress.zero(); } public void reset() {} public void cleanupPointers() {} public int getType() { return VM_CompiledMethod.JNI; } }