/* * 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.ia32; import org.jikesrvm.compilers.common.CompiledMethod; import org.jikesrvm.ia32.BaselineConstants; import org.jikesrvm.jni.JNIEnvironment; 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; 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-volatile registers to point to the registers saved * in the transition frame. * * @see JNICompiler */ @Uninterruptible public abstract class JNIGCMapIterator extends GCMapIterator implements BaselineConstants { // Java to Native C transition frame...(see JNICompiler) // // 0 + saved FP + <---- FP for Java to Native C glue frame // -4 | methodID | // -8 | saved EDI | non-volatile GPR // -C | saved EBX | non-volatile GPR // -10 | saved EBP | non-volatile GPR // -14 | returnAddr | (for return from OutOfLineMachineCode) // -18 | saved PR | // -1C | arg n-1 | reordered arguments to native method // -20 | ... | ... // -24 | arg 1 | ... // -28 | arg 0 | ... // -2C | class/obj | required 2nd argument to all native methods // -30 | jniEnv | required 1st argument to all native methods // -34 | returnAddr | return address pushed by call to native method // + saved FP + <---- FP for called native method // additional instance fields added by this subclass of GCMapIterator AddressArray jniRefs; int jniNextRef; int jniFramePtr; public JNIGCMapIterator(WordArray registerLocations) { this.registerLocations = registerLocations; } // Override newStackWalk() in parent class GCMapIterator to // initialize iterator for scan of JNI JREFs stack of refs // Taken: thread // Returned: nothing // public void newStackWalk(RVMThread thread) { super.newStackWalk(thread); // sets this.thread, inits registerLocations[] 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(); } } public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr) { this.framePtr = framePtr; } // 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 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; 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; } // 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. // the save non-volatiles are EBX EBP and EDI. // registerLocations.set(EDI.value(), framePtr.plus(JNICompiler.EDI_SAVE_OFFSET).toWord()); registerLocations.set(EBX.value(), framePtr.plus(JNICompiler.EBX_SAVE_OFFSET).toWord()); registerLocations.set(EBP.value(), framePtr.plus(JNICompiler.EBP_SAVE_OFFSET).toWord()); return Address.zero(); // no more refs to report } public Address getNextReturnAddressAddress() { return Address.zero(); } public void reset() { } public void cleanupPointers() { } public int getType() { return CompiledMethod.JNI; } }