/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm; import org.jnode.annotation.MagicPermission; import org.jnode.vm.classmgr.VmCompiledCode; import org.jnode.vm.classmgr.VmMethod; import org.vmmagic.unboxed.Address; @MagicPermission final class VmStackFrameEnumerator { /** * Stack frame reader */ private final VmStackReader reader; /** * Address of current stack frame */ private Address framePtr; /** * Index in address map of current stack frame method (deals with inlined methods) */ private int codeIndex; /** * Compiled code for the current frame */ private VmCompiledCode cc; /** * Initialize this instance. * * @param reader * @param framePtr * @param instrPtr */ public VmStackFrameEnumerator(VmStackReader reader, Address framePtr, Address instrPtr) { this.reader = reader; reset(framePtr, instrPtr); } /** * Initialize this instance. * Set the enumerator to enumerate the stack of the current thread. * * @param reader */ public VmStackFrameEnumerator(VmStackReader reader) { this.reader = reader; final Address curFrame = VmMagic.getCurrentFrame(); reset(reader.getPrevious(curFrame), reader.getReturnAddress(curFrame)); } /** * Reset the enumerator to the given pointers. * * @param framePtr * @param instrPtr */ public final void reset(Address framePtr, Address instrPtr) { this.framePtr = framePtr; initializeCodeIndex(instrPtr); } /** * Is the current frameptr valid. * * @return */ public final boolean isValid() { return reader.isValid(framePtr); } /** * Move to the next stack position. */ public final void next() { if (reader.isValid(framePtr)) { if (cc != null) { final int newIndex = cc.getAddressMap().getCallSiteIndex(codeIndex); if (newIndex >= 0) { codeIndex = newIndex; return; } } final Address nextIP = reader.getReturnAddress(framePtr).add(-1); this.framePtr = reader.getPrevious(framePtr); initializeCodeIndex(nextIP); } } /** * Gets the method at the current stack position. * * @return */ public final VmMethod getMethod() { VmMethod m = null; if (cc != null) { m = cc.getAddressMap().getMethodAtIndex(codeIndex); } if (m == null) { m = cc.getMethod(); } if (m == null) { m = reader.getMethod(framePtr); } return m; } /** * Gets the method at the current stack position. * * @return */ public final int getProgramCounter() { if (cc != null) { return cc.getAddressMap().getProgramCounterAtIndex(codeIndex); } else { return -1; } } /** * Gets the line number at the current stack position. * * @return */ public final int getLineNumber() { return getMethod().getBytecode().getLineNr(getProgramCounter()); } private void initializeCodeIndex(Address instrPtr) { cc = reader.getCompiledCode(framePtr); if (cc != null) { codeIndex = cc.getAddressMapIndex(instrPtr); } else { codeIndex = -1; } } }