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 */ 013package org.jikesrvm.runtime; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.architecture.StackFrameLayout; 017import org.jikesrvm.classloader.RVMClass; 018import org.jikesrvm.classloader.RVMMethod; 019import org.jikesrvm.compilers.common.CompiledMethod; 020import org.jikesrvm.compilers.common.CompiledMethods; 021import org.vmmagic.pragma.NoInline; 022import org.vmmagic.unboxed.Address; 023import 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 */ 029public final class StackBrowser { 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(StackFrameLayout.getStackFrameSentinelFP())) { 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 == StackFrameLayout.getInvisibleMethodID()) { 078 prevFP = newFP; 079 newFP = Magic.getCallerFramePointer(newFP); 080 if (newFP.EQ(StackFrameLayout.getStackFrameSentinelFP())) { 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 /** @return whether there are 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 public void setBytecodeIndex(int bytecodeIndex) { 115 currentBytecodeIndex = bytecodeIndex; 116 } 117 118 public void setMethod(RVMMethod method) { 119 currentMethod = method; 120 } 121 122 public void setCompiledMethod(CompiledMethod cm) { 123 currentCompiledMethod = cm; 124 } 125 126 /** 127 * Set the inline encoding. This is only necessary for 128 * opt compiled methods. 129 * 130 * @param index the inline encoding index 131 */ 132 public void setInlineEncodingIndex(int index) { 133 currentInlineEncodingIndex = index; 134 } 135 136 /** @return the bytecode index associated with the current stack frame */ 137 public int getBytecodeIndex() { 138 return currentBytecodeIndex; 139 } 140 141 /** @return the method associated with the current stack frame */ 142 public RVMMethod getMethod() { 143 return currentMethod; 144 } 145 146 /** @return the compiled method associated with the current stack frame */ 147 public CompiledMethod getCompiledMethod() { 148 return currentCompiledMethod; 149 } 150 151 /** @return the class of the method associated with the current stack frame */ 152 public RVMClass getCurrentClass() { 153 return getMethod().getDeclaringClass(); 154 } 155 156 /** @return the class loader of the method associated with the current stack frame */ 157 public ClassLoader getClassLoader() { 158 return getCurrentClass().getClassLoader(); 159 } 160 161 /** 162 * Get the inline encoding associated with the current stack location. 163 * This method is called only by opt compiled methods. 164 * 165 * @return the inline encoding associated with the current stack location 166 */ 167 public int getInlineEncodingIndex() { 168 return currentInlineEncodingIndex; 169 } 170}