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      @Override
073      public void newStackWalk(RVMThread thread) {
074        super.newStackWalk(thread);   // sets this.thread, inits registerLocations[]
075        JNIEnvironment env = this.thread.getJNIEnv();
076        // the "primordial" thread, created by JDK in the bootimage, does not have
077        // a JniEnv object, all threads created by the VM will.
078        if (env != null) {
079          this.jniRefs = env.refsArray();
080          this.jniNextRef = env.refsTop();
081          this.jniFramePtr = env.savedRefsFP();
082        }
083      }
084    
085      @Override
086      public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr) {
087        this.framePtr = framePtr;
088      }
089    
090      // return (address of) next ref in the current "frame" on the
091      // threads JNIEnvironment stack of refs
092      // When at the end of the current frame, update register locations to point
093      // to the non-volatile registers saved in the JNI transition frame.
094      //
095      @Override
096      public Address getNextReferenceAddress() {
097        // first report jni refs in the current frame in the jniRef side stack
098        // until all in the frame are reported
099        //
100        if (jniNextRef > jniFramePtr) {
101          Address ref_address = Magic.objectAsAddress(jniRefs).plus(jniNextRef);
102          jniNextRef -= BYTES_IN_ADDRESS;
103          return ref_address;
104        }
105    
106        // no more refs to report, before returning 0, setup for processing
107        // the next jni frame, if any
108    
109        // jniNextRef -> savedFramePtr for another "frame" of refs for another
110        // sequence of Native C frames lower in the stack, or to 0 if this is the
111        // last jni frame in the JNIRefs stack.  If more frames, initialize for a
112        // later scan of those refs.
113        //
114        if (jniFramePtr > 0) {
115          jniFramePtr = jniRefs.get(jniFramePtr >> LOG_BYTES_IN_ADDRESS).toInt();
116          jniNextRef = jniNextRef - BYTES_IN_ADDRESS;
117        }
118    
119        // set register locations for non-volatiles to point to registers saved in
120        // the JNI transition frame at a fixed negative offset from the callers FP.
121        // the save non-volatiles are EBX EBP and EDI.
122        //
123        registerLocations.set(EDI.value(), framePtr.plus(JNICompiler.EDI_SAVE_OFFSET).toWord());
124        registerLocations.set(EBX.value(), framePtr.plus(JNICompiler.EBX_SAVE_OFFSET).toWord());
125        registerLocations.set(EBP.value(), framePtr.plus(JNICompiler.EBP_SAVE_OFFSET).toWord());
126    
127        return Address.zero();  // no more refs to report
128      }
129    
130      @Override
131      public Address getNextReturnAddressAddress() {
132        return Address.zero();
133      }
134    
135      @Override
136      public void reset() { }
137    
138      @Override
139      public void cleanupPointers() { }
140    
141      @Override
142      public int getType() {
143        return CompiledMethod.JNI;
144      }
145    }