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 }