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 }