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.runtime;
014    
015    import org.jikesrvm.ArchitectureSpecific;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.classloader.RVMClass;
018    import org.jikesrvm.classloader.RVMMethod;
019    import org.jikesrvm.compilers.common.CompiledMethod;
020    import org.jikesrvm.compilers.common.CompiledMethods;
021    import org.vmmagic.pragma.NoInline;
022    import org.vmmagic.unboxed.Address;
023    import org.vmmagic.unboxed.Offset;
024    
025    /**
026     *  Use this class to explore the stack.  It is sometimes necessary to
027     *  find out the current context class loader, and other things like that.
028     */
029    public final class StackBrowser implements ArchitectureSpecific.StackframeLayoutConstants {
030    
031      /** Method associated with current stack location */
032      private RVMMethod currentMethod;
033      /** Bytecode associated with current stack location */
034      private int currentBytecodeIndex;
035    
036      /** The frame pointer for the current stack location */
037      private Address currentFramePointer;
038      /** The offset of the current instruction within its method */
039      private Offset currentInstructionPointer;
040      /** The current compiled method */
041      private CompiledMethod currentCompiledMethod;
042      /** The current inline encoding index for opt compiled methods */
043      private int currentInlineEncodingIndex;
044    
045      /** Initialise state of browser */
046      @NoInline
047      public void init() {
048        currentFramePointer = Magic.getFramePointer();
049        upOneFrame();
050      }
051    
052      /**
053       * Browse up one frame
054       * @param set should the state of the stack browser be effected?
055       * @return do more frames exist?
056       */
057      private boolean upOneFrameInternal(boolean set) {
058        Address fp;
059        if (currentMethod != null && currentMethod.getDeclaringClass().hasBridgeFromNativeAnnotation()) {
060          // Elide native frames
061          fp = RuntimeEntrypoints.unwindNativeStackFrame(currentFramePointer);
062        } else {
063            fp = currentFramePointer;
064        }
065    
066        Address prevFP = fp;
067        Address newFP = Magic.getCallerFramePointer(fp);
068        if (newFP.EQ(STACKFRAME_SENTINEL_FP)) {
069          return false;
070        }
071        // getReturnAddress has to be put here, consider the case
072        // on ppc, when fp is the frame above SENTINEL FP
073        Address newIP = Magic.getReturnAddress(prevFP);
074    
075        int cmid = Magic.getCompiledMethodID(newFP);
076    
077        while (cmid == INVISIBLE_METHOD_ID) {
078          prevFP = newFP;
079          newFP = Magic.getCallerFramePointer(newFP);
080          if (newFP.EQ(STACKFRAME_SENTINEL_FP)) {
081            return false;
082          }
083          newIP = Magic.getReturnAddress(prevFP);
084          cmid = Magic.getCompiledMethodID(newFP);
085        }
086    
087        if (set) {
088          CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid);
089          currentFramePointer = newFP;
090          currentInstructionPointer = cm.getInstructionOffset(newIP);
091          cm.set(this, currentInstructionPointer);
092        }
093        return true;
094      }
095    
096      /** Browse up one frame failing if we fall off the stack */
097      private void upOneFrame() {
098        boolean ok = upOneFrameInternal(true);
099        if (VM.VerifyAssertions) VM._assert(ok, "tried to browse off stack");
100      }
101    
102      /** Are there more stack frames? */
103      public boolean hasMoreFrames() {
104        return upOneFrameInternal(false);
105      }
106    
107      /** Browse up one frame eliding native frames */
108      public void up() {
109        if (!currentCompiledMethod.up(this)) {
110          upOneFrame();
111        }
112      }
113    
114      /** Set the current bytecode index, called only by the appropriate compiled method code */
115      public void setBytecodeIndex(int bytecodeIndex) {
116        currentBytecodeIndex = bytecodeIndex;
117      }
118    
119      /** Set the current method, called only by the appropriate compiled method code */
120      public void setMethod(RVMMethod method) {
121        currentMethod = method;
122      }
123    
124      /** Set the current compiled method, called only by the appropriate compiled method code */
125      public void setCompiledMethod(CompiledMethod cm) {
126        currentCompiledMethod = cm;
127      }
128    
129      /** Set the inline encoding for opt compiled methods only */
130      public void setInlineEncodingIndex(int index) {
131        currentInlineEncodingIndex = index;
132      }
133    
134      /** The bytecode index associated with the current stack frame */
135      public int getBytecodeIndex() {
136        return currentBytecodeIndex;
137      }
138    
139      /** The method associated with the current stack frame */
140      public RVMMethod getMethod() {
141        return currentMethod;
142      }
143    
144      /** The compiled method associated with the current stack frame */
145      public CompiledMethod getCompiledMethod() {
146        return currentCompiledMethod;
147      }
148    
149      /** The class of the method associated with the current stack frame */
150      public RVMClass getCurrentClass() {
151        return getMethod().getDeclaringClass();
152      }
153    
154      /** The class loader of the method associated with the current stack frame */
155      public ClassLoader getClassLoader() {
156        return getCurrentClass().getClassLoader();
157      }
158    
159      /** Get the inline encoding associated with the current stack location, called only by opt compiled methods */
160      public int getInlineEncodingIndex() {
161        return currentInlineEncodingIndex;
162      }
163    }