package nebula.vm; /*** * Excerpted from "Language Implementation Patterns", * published by The Pragmatic Bookshelf. * Copyrights apply to this code. It may not be used to create training material, * courses, books, articles, and the like. Contact us if you are in doubt. * We make no guarantees that this code is fit for any purpose. * Visit http://www.pragmaticprogrammer.com/titles/tpdsl for more book information. ***/ import static nebula.vm.BytecodeDefinition.MASK_XX; import static nebula.vm.BytecodeDefinition.MASK_X_; import static nebula.vm.BytecodeDefinition.OFFSET_AX; import static nebula.vm.BytecodeDefinition.OFFSET_A_; import static nebula.vm.BytecodeDefinition.OFFSET_BX; import static nebula.vm.BytecodeDefinition.OFFSET_B_; import static nebula.vm.BytecodeDefinition.OFFSET_C_; import static nebula.vm.BytecodeDefinition.OFFSET_OP; import static nebula.vm.BytecodeDefinition.REG; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; public class DisAssembler { BytecodeDefinition def; Writer out = null; public DisAssembler() { out = new OutputStreamWriter(System.out); } public DisAssembler(Writer out) { this.out = out; } private void println(String str) { print(str); print("\n"); } private void print(String format, Object... params) { print(String.format(format, params)); } private void print(String str) { try { this.out.write(str); this.out.flush(); } catch (IOException e) { throw new RuntimeException(e); } } public void disassemble(ClassSymbol clz) { println(".class " + clz.name); println(""); for (FieldSymbol f : clz.fields) { println(".field " + f.name); } println(""); for (MethodSymbol f : clz.methods) { this.disassemble(f); } } public void disassemble(MethodSymbol func) { print(".def %s: args=%d, locals=%d\n", func.name, func.nargs, func.nlocals); int i = 0; int[] code = func.code; while (i < func.code.length) { i = disassembleInstruction(code, func.getConstPool(), i); println(""); } println(""); } private static final int OP_CODE(int op) { return (op >>> OFFSET_OP); } private static final int A(int op) { return op >>> OFFSET_A_ & MASK_X_; } private static final int B(int op) { return op >>> OFFSET_B_ & MASK_X_; } private static final int C(int op) { return op >>> OFFSET_C_ & MASK_X_; } private static final int AX(int op) { return op >>> OFFSET_AX & MASK_XX; } private static final int BX(int op) { return op >>> OFFSET_BX & MASK_XX; } public int disassembleInstruction(int[] code, Object[] constPool, int ip) { int op = code[ip]; BytecodeDefinition.Instruction I = BytecodeDefinition.instructions[OP_CODE(op)]; String instrName = I.name.toUpperCase(); String ops = ""; if (I.n > 0) { String[] operands = new String[I.n]; switch (I.n) { case 3: switch (I.type[2]) { case REG: operands[2] = "r" + String.valueOf(C(op)); break; case BytecodeDefinition.FUNC: case BytecodeDefinition.POOL: operands[2] = showConstPoolOperand(constPool, C(op)); break; } case 2: switch (I.type[1]) { case REG: operands[1] = "r" + String.valueOf(B(op)); break; case BytecodeDefinition.FUNC: case BytecodeDefinition.POOL: operands[1] = showConstPoolOperand(constPool, B(op)); break; case BytecodeDefinition.INT: operands[1] = String.valueOf(BX(op)); break; } case 1: switch (I.type[0]) { case REG: operands[0] = "r" + String.valueOf(A(op)); break; case BytecodeDefinition.FUNC: case BytecodeDefinition.POOL: operands[0] = showConstPoolOperand(constPool, A(op)); break; case BytecodeDefinition.INT: operands[0] = String.valueOf(AX(op)); break; } break; } for (int i = 0; i < operands.length; i++) { String s = operands[i]; if (i > 0) ops+=", "; ops += s; } } print(String.format("%04d: %-7s %-12s", ip, instrName,ops)); ip++; return ip; } private String showConstPoolOperand(Object[] constPool, int poolIndex) { StringBuilder buf = new StringBuilder(); buf.append("#"); buf.append(poolIndex); String s = constPool[poolIndex].toString(); if (constPool[poolIndex] instanceof String) s = '"' + s + '"'; else if (constPool[poolIndex] instanceof MethodSymbol) { MethodSymbol fs = (MethodSymbol) constPool[poolIndex]; s = "@" + fs.definedClass.name + "." + fs.name + "()"; } else if (constPool[poolIndex] instanceof FieldSymbol) { FieldSymbol fs = (FieldSymbol) constPool[poolIndex]; s = "@" + fs.definedClass.name + "." + fs.name + ""; } buf.append(":"); buf.append(s); return buf.toString(); } }