package com.aaront.exercise.jvm.engine; import com.aaront.exercise.jvm.ClassFile; import com.aaront.exercise.jvm.commands.AbstractCommand; import com.aaront.exercise.jvm.method.Method; import java.util.List; import java.util.Stack; /** * @author tonyhui * @since 17/6/19 */ public class ExecutionEngine { private ClassFile classFile; private MethodArea methodArea; public ExecutionEngine(ClassFile classFile, MethodArea methodArea) { this.classFile = classFile; this.methodArea = methodArea; } public void execute() { Method mainMethod = methodArea.queryMainMethod(classFile).orElseThrow(() -> new RuntimeException("没有可执行的main方法")); Stack<StackFrame> frames = new Stack<>(); frames.add(new StackFrame(mainMethod)); List<AbstractCommand> commands = mainMethod.getCodeAttribute().getCommands(); StackFrame frame = frames.peek(); for (int i = frame.getIndex(); i < commands.size(); ) { AbstractCommand command = commands.get(i); ExecutionResult result = new ExecutionResult(); command.execute(frame, result); if (result.isRunNextCmd()) { // 运行下一条指令 frame.setIndex(i++); } else if (result.isPauseAndRunNewFrame()) { // 调用另一个函数 // 保存当前函数下一条要执行的命令 frame.setIndex(i + 1); frame = _generateStackFrame(frame, frame.getOperandStack(), result.getNextMethod()); frames.push(frame); commands = frame.getCommands(); i = frame.getIndex(); } else if (result.isExitCurrentFrame()) { frames.pop(); if (frames.isEmpty()) return; frame = frames.peek(); commands = frame.getCommands(); i = frame.getIndex(); } else if(result.isJump()) { frame.setIndex(result.getNextCmdOffset()); i = result.getNextCmdOffset(); } } } private StackFrame _generateStackFrame(StackFrame callerFrame, Stack<JavaObject> operandStack, Method method) { StackFrame frame = new StackFrame(method); frame.setCallerStackFrame(callerFrame); int paramSize = method.getParameterList().size() + 1;// 加1是因为还是把对象引用传入(可以理解成把this传入) _setParams(operandStack, frame, paramSize); return frame; } private void _setParams(Stack<JavaObject> operandStack, StackFrame frame, Integer size) { JavaObject[] params = frame.getLocalVariableTable(); for(int i = size - 1;i>=0;i--) { params[i] = operandStack.pop(); } } }