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.jni.ia32;
014
015 import org.jikesrvm.compilers.common.CompiledMethod;
016 import org.jikesrvm.ia32.BaselineConstants;
017 import org.jikesrvm.jni.JNIEnvironment;
018 import org.jikesrvm.mm.mminterface.GCMapIterator;
019 import org.jikesrvm.runtime.Magic;
020 import org.jikesrvm.scheduler.RVMThread;
021 import org.vmmagic.pragma.Uninterruptible;
022 import org.vmmagic.unboxed.Address;
023 import org.vmmagic.unboxed.AddressArray;
024 import org.vmmagic.unboxed.Offset;
025 import org.vmmagic.unboxed.WordArray;
026
027 /**
028 * Iterator for stack frames inserted at the transition from Java to
029 * JNI Native C. It will report JREFs associated with the executing
030 * C frames which are in the "JREFs stack" attached to the executing
031 * Threads JNIEnvironment. It will update register location addresses
032 * for the non-volatile registers to point to the registers saved
033 * in the transition frame.
034 *
035 * @see JNICompiler
036 */
037 @Uninterruptible
038 public abstract class JNIGCMapIterator extends GCMapIterator implements BaselineConstants {
039
040 // Java to Native C transition frame...(see JNICompiler)
041 //
042 // 0 + saved FP + <---- FP for Java to Native C glue frame
043 // -4 | methodID |
044 // -8 | saved EDI | non-volatile GPR
045 // -C | saved EBX | non-volatile GPR
046 // -10 | saved EBP | non-volatile GPR
047 // -14 | returnAddr | (for return from OutOfLineMachineCode)
048 // -18 | saved PR |
049 // -1C | arg n-1 | reordered arguments to native method
050 // -20 | ... | ...
051 // -24 | arg 1 | ...
052 // -28 | arg 0 | ...
053 // -2C | class/obj | required 2nd argument to all native methods
054 // -30 | jniEnv | required 1st argument to all native methods
055 // -34 | returnAddr | return address pushed by call to native method
056 // + saved FP + <---- FP for called native method
057
058 // additional instance fields added by this subclass of GCMapIterator
059 AddressArray jniRefs;
060 int jniNextRef;
061 int jniFramePtr;
062
063 public JNIGCMapIterator(WordArray registerLocations) {
064 this.registerLocations = registerLocations;
065 }
066
067 // Override newStackWalk() in parent class GCMapIterator to
068 // initialize iterator for scan of JNI JREFs stack of refs
069 // Taken: thread
070 // Returned: nothing
071 //
072 public void newStackWalk(RVMThread thread) {
073 super.newStackWalk(thread); // sets this.thread, inits registerLocations[]
074 JNIEnvironment env = this.thread.getJNIEnv();
075 // the "primordial" thread, created by JDK in the bootimage, does not have
076 // a JniEnv object, all threads created by the VM will.
077 if (env != null) {
078 this.jniRefs = env.refsArray();
079 this.jniNextRef = env.refsTop();
080 this.jniFramePtr = env.savedRefsFP();
081 }
082 }
083
084 public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr) {
085 this.framePtr = framePtr;
086 }
087
088 // return (address of) next ref in the current "frame" on the
089 // threads JNIEnvironment stack of refs
090 // When at the end of the current frame, update register locations to point
091 // to the non-volatile registers saved in the JNI transition frame.
092 //
093 public Address getNextReferenceAddress() {
094 // first report jni refs in the current frame in the jniRef side stack
095 // until all in the frame are reported
096 //
097 if (jniNextRef > jniFramePtr) {
098 Address ref_address = Magic.objectAsAddress(jniRefs).plus(jniNextRef);
099 jniNextRef -= BYTES_IN_ADDRESS;
100 return ref_address;
101 }
102
103 // no more refs to report, before returning 0, setup for processing
104 // the next jni frame, if any
105
106 // jniNextRef -> savedFramePtr for another "frame" of refs for another
107 // sequence of Native C frames lower in the stack, or to 0 if this is the
108 // last jni frame in the JNIRefs stack. If more frames, initialize for a
109 // later scan of those refs.
110 //
111 if (jniFramePtr > 0) {
112 jniFramePtr = jniRefs.get(jniFramePtr >> LOG_BYTES_IN_ADDRESS).toInt();
113 jniNextRef = jniNextRef - BYTES_IN_ADDRESS;
114 }
115
116 // set register locations for non-volatiles to point to registers saved in
117 // the JNI transition frame at a fixed negative offset from the callers FP.
118 // the save non-volatiles are EBX EBP and EDI.
119 //
120 registerLocations.set(EDI.value(), framePtr.plus(JNICompiler.EDI_SAVE_OFFSET).toWord());
121 registerLocations.set(EBX.value(), framePtr.plus(JNICompiler.EBX_SAVE_OFFSET).toWord());
122 registerLocations.set(EBP.value(), framePtr.plus(JNICompiler.EBP_SAVE_OFFSET).toWord());
123
124 return Address.zero(); // no more refs to report
125 }
126
127 public Address getNextReturnAddressAddress() {
128 return Address.zero();
129 }
130
131 public void reset() { }
132
133 public void cleanupPointers() { }
134
135 public int getType() {
136 return CompiledMethod.JNI;
137 }
138 }