/* * Copyright (c) 2007, 2011, 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.tele.interpreter; import java.util.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.classfile.*; import com.sun.max.vm.classfile.constant.*; import com.sun.max.vm.value.*; /** * Instances of this class represent individual execution frame entries on a given ExecutionThread's execution stack. */ class ExecutionFrame { private final ClassMethodActor method; private int currentOpcodePosition; private int currentBytePosition; private final Value[] locals; private final Stack<Value> operands; private final ExecutionFrame callersFrame; private final byte[] code; private final int depth; public ExecutionFrame(ExecutionFrame callersFrame, ClassMethodActor method) { this.method = method; this.locals = new Value[method.codeAttribute().maxLocals]; this.operands = new Stack<Value>(); this.callersFrame = callersFrame; this.code = method.codeAttribute().code(); this.depth = callersFrame == null ? 1 : callersFrame.depth + 1; } /** * Computes the number of frames on the call stack up to and including this frame. */ public int depth() { return depth; } public ExecutionFrame callersFrame() { return callersFrame; } public void setLocal(int index, Value value) { locals[index] = value; } public int readOpcode() { currentOpcodePosition = currentBytePosition; return readByte() & 0xff; } public byte readByte() { try { return code[currentBytePosition++]; } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { throw new VerifyError("Ran off end of code"); } } public short readShort() { final int high = readByte(); final int low = readByte() & 0xff; return (short) ((high << 8) | low); } public int readInt() { final int b3 = readByte() << 24; final int b2 = (readByte() & 0xff) << 16; final int b1 = (readByte() & 0xff) << 8; final int b0 = readByte() & 0xff; return b3 | b2 | b1 | b0; } public void skipBytes(int n) { currentBytePosition += n; } public void alignInstructionPosition() { final int remainder = currentBytePosition % 4; if (remainder != 0) { currentBytePosition += 4 - remainder; } } public void jump(int offset) { currentBytePosition = currentOpcodePosition + offset; } public int currentOpcodePosition() { return currentOpcodePosition; } public int currentBytePosition() { return currentBytePosition; } public void setBytecodePosition(int bcp) { currentBytePosition = bcp; } public byte[] code() { return code; } public Value getLocal(int index) { return locals[index]; } public Stack<Value> stack() { return operands; } public ConstantPool constantPool() { return method.codeAttribute().cp; } public ClassMethodActor method() { return method; } @Override public String toString() { return method.format("%H.%n(%p) @ " + currentBytePosition); } /** * Handles an exception at the current execution point in this frame by updating the {@linkplain #setBytecodePosition(int) * instruction pointer} to the matching exception handler in this frame. If no matching exception handler is found * for the current execution point and the given exception type, then the instruction pointer in this frame is left * unmodified. * <p> * The current execution point is derived from the value of {@link ExecutionFrame#currentBytePosition()} which is now at the first * byte passed the instruction currently being executed. That is, an instruction is completely decoded before any * exceptions are thrown while executing it. * * @param throwableClassActor the type of the exception being thrown * @return {@code true} if an exception handler was found, {@code false} otherwise */ public boolean handleException(ClassActor throwableClassActor) { final int bcp = currentOpcodePosition; final ExceptionHandlerEntry[] handlers = method().codeAttribute().exceptionHandlerTable(); for (ExceptionHandlerEntry handler : handlers) { if (bcp >= handler.startBCI() && bcp < handler.endBCI()) { if (handler.catchTypeIndex() == 0) { currentBytePosition = handler.handlerBCI(); return true; } final ClassActor catchType = constantPool().classAt(handler.catchTypeIndex()).resolve(constantPool(), handler.catchTypeIndex()); if (catchType.isAssignableFrom(throwableClassActor)) { currentBytePosition = handler.handlerBCI(); return true; } } } return false; } }