package jvm.engine; import jvm.classfile.method.Method; import jvm.command.item.ByteCodeCommand; import jvm.command.item.TwoOperandCmd; import jvm.exception.ReadClassException; import java.util.ArrayList; import java.util.List; import java.util.Stack; public class StackFrame { private List<JavaObject> localVariableTable = new ArrayList<>(); private Stack<JavaObject> operandStack = new Stack<>(); private int index = 0; private Method method = null; private StackFrame callerFrame = null; private StackFrame(Method method) { this.method = method; } public ExecutionResult execute() throws ReadClassException { ByteCodeCommand[] commands = getMethod().getCommands(); while (index < commands.length) { ByteCodeCommand cmd = commands[index]; ExecutionResult result = new ExecutionResult(); cmd.execute(this, result); if (result.isExitCurrentFrame()) { return result; } else if (result.isPauseAndRunNewFrame()) { index++; return result; } else if (result.isJump()) { int offset = result.getNextCmdOffset(); index = getNextCommandIndex(offset); } else { index++; } } ExecutionResult frameResult = new ExecutionResult(); frameResult.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME); return frameResult; } public StackFrame getCallerFrame() { return callerFrame; } public void setCallerFrame(StackFrame callerFrame) { this.callerFrame = callerFrame; } public static StackFrame create(Method m) { return new StackFrame(m); } public JavaObject getLocalVariableValue(int index) { return this.localVariableTable.get(index); } public Stack<JavaObject> getOperandStack() { return this.operandStack; } public int getNextCommandIndex(int offset) { ByteCodeCommand[] commands = method.getCommands(); for (int i = 0; i < commands.length; i++) { if (commands[i].getOffset() == offset) { return i; } } throw new RuntimeException("Can't find next command"); } public void setLocalVariableTable(List<JavaObject> values) { this.localVariableTable = values; } public void setLocalVariableValue(int index, JavaObject jo) { if (this.localVariableTable.size() - 1 < index) { for (int i = this.localVariableTable.size(); i <= index; i++) { this.localVariableTable.add(null); } } this.localVariableTable.set(index, jo); } public Method getMethod() { return method; } @Override public String toString() { return getMethod().toString(); } }