/*
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.stack;
import com.sun.cri.ci.*;
import com.sun.max.lang.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.code.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.runtime.*;
/**
* An encapsulation of all the state associated with a single stack frame that is needed during a stack walk,
* including the target method, the instruction pointer, stack pointer, frame pointer, register state,
* and whether the frame is the top frame.
* <p>
* As instruction pointers can be either in native code (C functions) or in managed code ({@linkplain TargetMethod
* target methods}), the {@link NativeOrVmIP} abstraction is used to store them.
*
* @see StackFrameWalker
*/
public class StackFrameCursor {
private final StackFrameWalker walker;
public final NativeOrVmIP ip;
Pointer sp = Pointer.zero();
Pointer fp = Pointer.zero();
private CiCalleeSaveLayout csl;
private Pointer csa;
boolean isTopFrame = false;
StackFrameCursor(StackFrameWalker walker) {
this.walker = walker;
this.ip = new NativeOrVmIP();
}
/**
* Alternate constructor that allows subclasses to specify an alternate implementation of code
* pointer to use for the IP, intended for use by the Inspector.
*/
protected StackFrameCursor(StackFrameWalker walker, NativeOrVmIP ip) {
this.walker = walker;
this.ip = ip;
}
/**
* Updates the cursor to point to the next stack frame.
* This method implicitly sets {@link StackFrameCursor#isTopFrame()} of this cursor to {@code false}.
*
* @param tm the new target method (may be {@code null})
* @param pos the instruction offset in the target method (may be 0)
* @param ip the new instruction pointer (may be zero)
* @param sp the new stack pointer
* @param fp the new frame pointer
*/
final StackFrameCursor advance(TargetMethod tm, int pos, Pointer ip, Pointer sp, Pointer fp) {
return setFields(tm, pos, ip, sp, fp, false);
}
final void reset() {
setFields(NativeOrVmIP.ZERO, Pointer.zero(), Pointer.zero(), false);
}
void copyFrom(StackFrameCursor other) {
setFields(other.ip, other.sp, other.fp, other.isTopFrame);
setCalleeSaveArea(other.csl, other.csa);
}
private StackFrameCursor setFields(NativeOrVmIP nojip, Pointer sp, Pointer fp, boolean isTopFrame) {
ip.copyFrom(nojip);
this.sp = sp;
this.fp = fp;
this.isTopFrame = isTopFrame;
this.csl = null;
this.csa = Pointer.zero();
return this;
}
private StackFrameCursor setFields(TargetMethod tm, int pos, Pointer ip, Pointer sp, Pointer fp, boolean isTopFrame) {
this.ip.primitiveSet(tm, pos, ip);
this.sp = sp;
this.fp = fp;
this.isTopFrame = isTopFrame;
this.csl = null;
this.csa = Pointer.zero();
return this;
}
/**
* Sets the callee save details for this frame cursor. This must be called
* while this cursor denotes the "current" frame just before {@link StackFrameWalker#advance(Word, Word, Word)}
* is called (after which this cursor will be the "callee" frame).
*
* @param csl the layout of the callee save area in the frame denoted by this cursor
* @param csa the address of the callee save area in the frame denoted by this cursor
*/
final public void setCalleeSaveArea(CiCalleeSaveLayout csl, Pointer csa) {
FatalError.check((csl == null) == csa.isZero(), "inconsistent callee save area info");
this.csl = csl;
this.csa = csa;
}
/**
* @return the stack frame walker for this cursor
*/
final public StackFrameWalker stackFrameWalker() {
return walker;
}
/**
* @return the target method corresponding to the instruction pointer.
*/
final public TargetMethod targetMethod() {
return ip.targetMethod();
}
/**
* Gets the address of the next instruction that will be executed in this frame.
* If this is not the {@linkplain #isTopFrame() top frame}, then this is the
* return address saved by a call instruction. The exact interpretation of this
* return address depends on the {@linkplain ISA#offsetToReturnPC platform}.
*
* The value returned from this method is valid only if the frame executes a native function.
* Callers must be sure about calling {@link #nativeIP()} and {@link #vmIP()} correctly.
*
* @return the current instruction pointer in a native function.
*/
final public Pointer nativeIP() {
return ip.nativeIP();
}
/**
* Gets the address of the next instruction that will be executed in this frame.
* If this is not the {@linkplain #isTopFrame() top frame}, then this is the
* return address saved by a call instruction. The exact interpretation of this
* return address depends on the {@linkplain ISA#offsetToReturnPC platform}.
*
* The value returned from this method is valid only if the frame executes a target method.
* Callers must be sure about calling {@link #nativeIP()} and {@link #vmIP()} correctly.
*
* @return the current instruction pointer in a target method.
*/
final public CodePointer vmIP() {
return ip.vmIP();
}
final public Pointer ipAsPointer() {
return ip.asPointer();
}
/**
* @return the current stack pointer.
*/
final public Pointer sp() {
return sp;
}
/**
* @return the current frame pointer.
*/
final public Pointer fp() {
return fp;
}
/**
* @return {@code true} if this frame is the top frame
*/
final public boolean isTopFrame() {
return isTopFrame;
}
/**
* Gets the layout of the callee save area in this frame.
*
* @return {@code null} if there is no callee save area in this frame
*/
final public CiCalleeSaveLayout csl() {
return csl;
}
/**
* Gets the address of the callee save area in this frame.
*
* @return {@link Pointer#zero()} if there is no callee save area in this frame
*/
final public Pointer csa() {
return csa;
}
}