/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.runtime;
import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.VM_Class;
import org.jikesrvm.classloader.VM_Method;
import org.jikesrvm.compilers.common.VM_CompiledMethod;
import org.jikesrvm.compilers.common.VM_CompiledMethods;
import org.vmmagic.pragma.NoInline;
import org.vmmagic.unboxed.LocalAddress;
import org.vmmagic.unboxed.Offset;
/**
* Use this class to explore the stack. It is sometimes necessary to
* find out the current context class loader, and other things like that.
*/
public final class VM_StackBrowser implements ArchitectureSpecific.VM_StackframeLayoutConstants {
/** Method associated with current stack location */
private VM_Method currentMethod;
/** Bytecode associated with current stack location */
private int currentBytecodeIndex;
/** The frame pointer for the current stack location */
private LocalAddress currentFramePointer;
/** The offset of the current instruction within its method */
private Offset currentInstructionPointer;
/** The current compiled method */
private VM_CompiledMethod currentCompiledMethod;
/** The current inline encoding index for opt compiled methods */
private int currentInlineEncodingIndex;
/** Initialise state of browser */
@NoInline
public void init() {
currentFramePointer = VM_Magic.getFramePointer();
upOneFrame();
}
/**
* Browse up one frame
* @param set should the state of the stack browser be effected?
* @return do more frames exist?
*/
private boolean upOneFrameInternal(boolean set) {
LocalAddress fp;
if (currentMethod != null && currentMethod.getDeclaringClass().hasBridgeFromNativeAnnotation()) {
// Elide native frames
fp = VM_Runtime.unwindNativeStackFrame(currentFramePointer);
} else {
fp = currentFramePointer;
}
LocalAddress prevFP = fp;
LocalAddress newFP = VM_Magic.getCallerFramePointer(fp);
if (newFP.EQ(VM_Magic.addressAsLocalAddress(STACKFRAME_SENTINEL_FP))) {
return false;
}
// getReturnAddress has to be put here, consider the case
// on ppc, when fp is the frame above SENTINEL FP
LocalAddress newIP = VM_Magic.getReturnAddress(prevFP);
int cmid = VM_Magic.getCompiledMethodID(newFP);
while (cmid == INVISIBLE_METHOD_ID) {
prevFP = newFP;
newFP = VM_Magic.getCallerFramePointer(newFP);
if (newFP.EQ(VM_Magic.addressAsLocalAddress(STACKFRAME_SENTINEL_FP))) {
return false;
}
newIP = VM_Magic.getReturnAddress(prevFP);
cmid = VM_Magic.getCompiledMethodID(newFP);
}
if (set) {
VM_CompiledMethod cm = VM_CompiledMethods.getCompiledMethod(cmid);
currentFramePointer = newFP;
currentInstructionPointer = cm.getInstructionOffset(newIP);
cm.set(this, currentInstructionPointer);
}
return true;
}
/** Browse up one frame failing if we fall off the stack */
private void upOneFrame() {
boolean ok = upOneFrameInternal(true);
if (VM.VerifyAssertions) VM._assert(ok, "tried to browse off stack");
}
/** Are there more stack frames? */
public boolean hasMoreFrames() {
return upOneFrameInternal(false);
}
/** Browse up one frame eliding native frames */
public void up() {
if (!currentCompiledMethod.up(this)) {
upOneFrame();
}
}
/** Set the current bytecode index, called only by the appropriate compiled method code */
public void setBytecodeIndex(int bytecodeIndex) {
currentBytecodeIndex = bytecodeIndex;
}
/** Set the current method, called only by the appropriate compiled method code */
public void setMethod(VM_Method method) {
currentMethod = method;
}
/** Set the current compiled method, called only by the appropriate compiled method code */
public void setCompiledMethod(VM_CompiledMethod cm) {
currentCompiledMethod = cm;
}
/** Set the inline encoding for opt compiled methods only */
public void setInlineEncodingIndex(int index) {
currentInlineEncodingIndex = index;
}
/** The bytecode index associated with the current stack frame */
public int getBytecodeIndex() {
return currentBytecodeIndex;
}
/** The method associated with the current stack frame */
public VM_Method getMethod() {
return currentMethod;
}
/** The compiled method associated with the current stack frame */
public VM_CompiledMethod getCompiledMethod() {
return currentCompiledMethod;
}
/** The class of the method associated with the current stack frame */
public VM_Class getCurrentClass() {
return getMethod().getDeclaringClass();
}
/** The class loader of the method associated with the current stack frame */
public ClassLoader getClassLoader() {
return getCurrentClass().getClassLoader();
}
/** Get the inline encoding associated with the current stack location, called only by opt compiled methods */
public int getInlineEncodingIndex() {
return currentInlineEncodingIndex;
}
}