diff --git a/makefile b/makefile index 0f768ac8fd..07633f834f 100755 --- a/makefile +++ b/makefile @@ -1125,6 +1125,7 @@ embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed)) compiler-sources = \ $(src)/codegen/compiler.cpp \ $(wildcard $(src)/codegen/compiler/*.cpp) \ + $(src)/debug-util.cpp \ $(src)/codegen/registers.cpp \ $(src)/codegen/runtime.cpp \ $(src)/codegen/targets.cpp \ diff --git a/src/compile.cpp b/src/compile.cpp index 925b182333..03fb7e070c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -27,6 +27,8 @@ #include #include +#include "debug-util.h" + using namespace vm; extern "C" uint64_t @@ -56,6 +58,7 @@ const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; const bool DebugFrameMaps = false; +const bool DebugInstructions = false; const bool CheckArrayBounds = true; @@ -4189,9 +4192,35 @@ compile(MyThread* t, Frame* initialFrame, unsigned initialIp, 1, c->threadRegister()); } - + // fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map)); + if (DebugInstructions) { + unsigned startingIp = ip; + // TODO: fix stack printing + fprintf(stderr, " stack: ["); + for (size_t i = frame->localSize(); i < frame->sp; i++) { + switch (frame->get(i)) { + case Frame::Integer: + fprintf(stderr, "I"); + break; + case Frame::Long: + fprintf(stderr, "L"); + break; + case Frame::Object: + fprintf(stderr, "O"); + break; + default: + fprintf(stderr, "?"); + break; + } + } + fprintf(stderr, "]\n"); + fprintf(stderr, "% 5d: ", startingIp); + avian::jvm::debug::printInstruction(&codeBody(t, code, 0), startingIp); + fprintf(stderr, "\n"); + } + unsigned instruction = codeBody(t, code, ip++); switch (instruction) { diff --git a/src/debug-util.cpp b/src/debug-util.cpp new file mode 100644 index 0000000000..03a3c9540e --- /dev/null +++ b/src/debug-util.cpp @@ -0,0 +1,620 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include + +#include "debug-util.h" + +namespace avian { +namespace jvm { +namespace debug { + +uint16_t read16(uint8_t* code, unsigned& ip) +{ + uint16_t a = code[ip++]; + uint16_t b = code[ip++]; + return (a << 8) | b; +} + +uint32_t read32(uint8_t* code, unsigned& ip) +{ + uint32_t b = code[ip++]; + uint32_t a = code[ip++]; + uint32_t c = code[ip++]; + uint32_t d = code[ip++]; + return (a << 24) | (b << 16) | (c << 8) | d; +} + +using namespace vm; + +int printInstruction(uint8_t* code, unsigned& ip, const char* prefix) +{ + unsigned startIp = ip; + + uint8_t instr = code[ip++]; + switch (instr) { + case aaload: + return fprintf(stderr, "aaload"); + case aastore: + return fprintf(stderr, "aastore"); + + case aconst_null: + return fprintf(stderr, "aconst_null"); + + case aload: + return fprintf(stderr, "aload %2d", code[ip++]); + case aload_0: + return fprintf(stderr, "aload_0"); + case aload_1: + return fprintf(stderr, "aload_1"); + case aload_2: + return fprintf(stderr, "aload_2"); + case aload_3: + return fprintf(stderr, "aload_3"); + + case anewarray: + return fprintf(stderr, "anewarray %4d", read16(code, ip)); + case areturn: + return fprintf(stderr, "areturn"); + case arraylength: + return fprintf(stderr, "arraylength"); + + case astore: + return fprintf(stderr, "astore %2d", code[ip++]); + case astore_0: + return fprintf(stderr, "astore_0"); + case astore_1: + return fprintf(stderr, "astore_1"); + case astore_2: + return fprintf(stderr, "astore_2"); + case astore_3: + return fprintf(stderr, "astore_3"); + + case athrow: + return fprintf(stderr, "athrow"); + case baload: + return fprintf(stderr, "baload"); + case bastore: + return fprintf(stderr, "bastore"); + + case bipush: + return fprintf(stderr, "bipush %2d", code[ip++]); + case caload: + return fprintf(stderr, "caload"); + case castore: + return fprintf(stderr, "castore"); + case checkcast: + return fprintf(stderr, "checkcast %4d", read16(code, ip)); + case d2f: + return fprintf(stderr, "d2f"); + case d2i: + return fprintf(stderr, "d2i"); + case d2l: + return fprintf(stderr, "d2l"); + case dadd: + return fprintf(stderr, "dadd"); + case daload: + return fprintf(stderr, "daload"); + case dastore: + return fprintf(stderr, "dastore"); + case dcmpg: + return fprintf(stderr, "dcmpg"); + case dcmpl: + return fprintf(stderr, "dcmpl"); + case dconst_0: + return fprintf(stderr, "dconst_0"); + case dconst_1: + return fprintf(stderr, "dconst_1"); + case ddiv: + return fprintf(stderr, "ddiv"); + case dmul: + return fprintf(stderr, "dmul"); + case dneg: + return fprintf(stderr, "dneg"); + case vm::drem: + return fprintf(stderr, "drem"); + case dsub: + return fprintf(stderr, "dsub"); + case dup: + return fprintf(stderr, "dup"); + case dup_x1: + return fprintf(stderr, "dup_x1"); + case dup_x2: + return fprintf(stderr, "dup_x2"); + case dup2: + return fprintf(stderr, "dup2"); + case dup2_x1: + return fprintf(stderr, "dup2_x1"); + case dup2_x2: + return fprintf(stderr, "dup2_x2"); + case f2d: + return fprintf(stderr, "f2d"); + case f2i: + return fprintf(stderr, "f2i"); + case f2l: + return fprintf(stderr, "f2l"); + case fadd: + return fprintf(stderr, "fadd"); + case faload: + return fprintf(stderr, "faload"); + case fastore: + return fprintf(stderr, "fastore"); + case fcmpg: + return fprintf(stderr, "fcmpg"); + case fcmpl: + return fprintf(stderr, "fcmpl"); + case fconst_0: + return fprintf(stderr, "fconst_0"); + case fconst_1: + return fprintf(stderr, "fconst_1"); + case fconst_2: + return fprintf(stderr, "fconst_2"); + case fdiv: + return fprintf(stderr, "fdiv"); + case fmul: + return fprintf(stderr, "fmul"); + case fneg: + return fprintf(stderr, "fneg"); + case frem: + return fprintf(stderr, "frem"); + case fsub: + return fprintf(stderr, "fsub"); + + case getfield: + return fprintf(stderr, "getfield %4d", read16(code, ip)); + case getstatic: + return fprintf(stderr, "getstatic %4d", read16(code, ip)); + case goto_: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "goto %4d", offset + ip - 3); + } + case goto_w: { + int32_t offset = read32(code, ip); + return fprintf(stderr, "goto_w %08x", offset + ip - 5); + } + + case i2b: + return fprintf(stderr, "i2b"); + case i2c: + return fprintf(stderr, "i2c"); + case i2d: + return fprintf(stderr, "i2d"); + case i2f: + return fprintf(stderr, "i2f"); + case i2l: + return fprintf(stderr, "i2l"); + case i2s: + return fprintf(stderr, "i2s"); + case iadd: + return fprintf(stderr, "iadd"); + case iaload: + return fprintf(stderr, "iaload"); + case iand: + return fprintf(stderr, "iand"); + case iastore: + return fprintf(stderr, "iastore"); + case iconst_m1: + return fprintf(stderr, "iconst_m1"); + case iconst_0: + return fprintf(stderr, "iconst_0"); + case iconst_1: + return fprintf(stderr, "iconst_1"); + case iconst_2: + return fprintf(stderr, "iconst_2"); + case iconst_3: + return fprintf(stderr, "iconst_3"); + case iconst_4: + return fprintf(stderr, "iconst_4"); + case iconst_5: + return fprintf(stderr, "iconst_5"); + case idiv: + return fprintf(stderr, "idiv"); + + case if_acmpeq: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_acmpeq %4d", offset + ip - 3); + } + case if_acmpne: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_acmpne %4d", offset + ip - 3); + } + case if_icmpeq: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmpeq %4d", offset + ip - 3); + } + case if_icmpne: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmpne %4d", offset + ip - 3); + } + + case if_icmpgt: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmpgt %4d", offset + ip - 3); + } + case if_icmpge: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmpge %4d", offset + ip - 3); + } + case if_icmplt: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmplt %4d", offset + ip - 3); + } + case if_icmple: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "if_icmple %4d", offset + ip - 3); + } + + case ifeq: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifeq %4d", offset + ip - 3); + } + case ifne: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifne %4d", offset + ip - 3); + } + case ifgt: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifgt %4d", offset + ip - 3); + } + case ifge: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifge %4d", offset + ip - 3); + } + case iflt: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "iflt %4d", offset + ip - 3); + } + case ifle: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifle %4d", offset + ip - 3); + } + + case ifnonnull: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifnonnull %4d", offset + ip - 3); + } + case ifnull: { + int16_t offset = read16(code, ip); + return fprintf(stderr, "ifnull %4d", offset + ip - 3); + } + + case iinc: { + uint8_t a = code[ip++]; + uint8_t b = code[ip++]; + return fprintf(stderr, "iinc %2d %2d", a, b); + } + + case iload: + return fprintf(stderr, "iload %2d", code[ip++]); + case fload: + return fprintf(stderr, "fload %2d", code[ip++]); + + case iload_0: + return fprintf(stderr, "iload_0"); + case fload_0: + return fprintf(stderr, "fload_0"); + case iload_1: + return fprintf(stderr, "iload_1"); + case fload_1: + return fprintf(stderr, "fload_1"); + + case iload_2: + return fprintf(stderr, "iload_2"); + case fload_2: + return fprintf(stderr, "fload_2"); + case iload_3: + return fprintf(stderr, "iload_3"); + case fload_3: + return fprintf(stderr, "fload_3"); + + case imul: + return fprintf(stderr, "imul"); + case ineg: + return fprintf(stderr, "ineg"); + + case instanceof: + return fprintf(stderr, "instanceof %4d", read16(code, ip)); + case invokeinterface: + return fprintf(stderr, "invokeinterface %4d", read16(code, ip)); + case invokespecial: + return fprintf(stderr, "invokespecial %4d", read16(code, ip)); + case invokestatic: + return fprintf(stderr, "invokestatic %4d", read16(code, ip)); + case invokevirtual: + return fprintf(stderr, "invokevirtual %4d", read16(code, ip)); + + case ior: + return fprintf(stderr, "ior"); + case irem: + return fprintf(stderr, "irem"); + case ireturn: + return fprintf(stderr, "ireturn"); + case freturn: + return fprintf(stderr, "freturn"); + case ishl: + return fprintf(stderr, "ishl"); + case ishr: + return fprintf(stderr, "ishr"); + + case istore: + return fprintf(stderr, "istore %2d", code[ip++]); + case fstore: + return fprintf(stderr, "fstore %2d", code[ip++]); + + case istore_0: + return fprintf(stderr, "istore_0"); + case fstore_0: + return fprintf(stderr, "fstore_0"); + case istore_1: + return fprintf(stderr, "istore_1"); + case fstore_1: + return fprintf(stderr, "fstore_1"); + case istore_2: + return fprintf(stderr, "istore_2"); + case fstore_2: + return fprintf(stderr, "fstore_2"); + case istore_3: + return fprintf(stderr, "istore_3"); + case fstore_3: + return fprintf(stderr, "fstore_3"); + + case isub: + return fprintf(stderr, "isub"); + case iushr: + return fprintf(stderr, "iushr"); + case ixor: + return fprintf(stderr, "ixor"); + + case jsr: + return fprintf(stderr, "jsr %4d", read16(code, ip) + startIp); + case jsr_w: + return fprintf(stderr, "jsr_w %08x", read32(code, ip) + startIp); + + case l2d: + return fprintf(stderr, "l2d"); + case l2f: + return fprintf(stderr, "l2f"); + case l2i: + return fprintf(stderr, "l2i"); + case ladd: + return fprintf(stderr, "ladd"); + case laload: + return fprintf(stderr, "laload"); + + case land: + return fprintf(stderr, "land"); + case lastore: + return fprintf(stderr, "lastore"); + + case lcmp: + return fprintf(stderr, "lcmp"); + case lconst_0: + return fprintf(stderr, "lconst_0"); + case lconst_1: + return fprintf(stderr, "lconst_1"); + + case ldc: + return fprintf(stderr, "ldc %4d", read16(code, ip)); + case ldc_w: + return fprintf(stderr, "ldc_w %08x", read32(code, ip)); + case ldc2_w: + return fprintf(stderr, "ldc2_w %4d", read16(code, ip)); + + case ldiv_: + return fprintf(stderr, "ldiv_"); + + case lload: + return fprintf(stderr, "lload %2d", code[ip++]); + case dload: + return fprintf(stderr, "dload %2d", code[ip++]); + + case lload_0: + return fprintf(stderr, "lload_0"); + case dload_0: + return fprintf(stderr, "dload_0"); + case lload_1: + return fprintf(stderr, "lload_1"); + case dload_1: + return fprintf(stderr, "dload_1"); + case lload_2: + return fprintf(stderr, "lload_2"); + case dload_2: + return fprintf(stderr, "dload_2"); + case lload_3: + return fprintf(stderr, "lload_3"); + case dload_3: + return fprintf(stderr, "dload_3"); + + case lmul: + return fprintf(stderr, "lmul"); + case lneg: + return fprintf(stderr, "lneg"); + + case lookupswitch: { + while (ip & 0x3) { + ip++; + } + int32_t default_ = read32(code, ip) + startIp; + int32_t pairCount = read32(code, ip); + fprintf( + stderr, "lookupswitch default: %d pairCount: %d", default_, pairCount); + + bool good = true; + if (pairCount >= 1000) { + pairCount = 1; + good = false; + } + + for (int i = 0; i < pairCount; i++) { + int32_t k = read32(code, ip); + int32_t d = read32(code, ip) + startIp; + fprintf(stderr, "\n%s key: %2d dest: %d", prefix, k, d); + } + fprintf(stderr, "\n"); + fflush(stderr); + if (!good) + asm("int3"); + return 0; + } + + case lor: + return fprintf(stderr, "lor"); + case lrem: + return fprintf(stderr, "lrem"); + case lreturn: + return fprintf(stderr, "lreturn"); + case dreturn: + return fprintf(stderr, "dreturn"); + case lshl: + return fprintf(stderr, "lshl"); + case lshr: + return fprintf(stderr, "lshr"); + + case lstore: + return fprintf(stderr, "lstore %2d", code[ip++]); + case dstore: + return fprintf(stderr, "dstore %2d", code[ip++]); + + case lstore_0: + return fprintf(stderr, "lstore_0"); + case dstore_0: + return fprintf(stderr, "dstore_0"); + case lstore_1: + return fprintf(stderr, "lstore_1"); + case dstore_1: + return fprintf(stderr, "dstore_1"); + case lstore_2: + return fprintf(stderr, "lstore_2"); + case dstore_2: + return fprintf(stderr, "dstore_2"); + case lstore_3: + return fprintf(stderr, "lstore_3"); + case dstore_3: + return fprintf(stderr, "dstore_3"); + + case lsub: + return fprintf(stderr, "lsub"); + case lushr: + return fprintf(stderr, "lushr"); + case lxor: + return fprintf(stderr, "lxor"); + + case monitorenter: + return fprintf(stderr, "monitorenter"); + case monitorexit: + return fprintf(stderr, "monitorexit"); + + case multianewarray: { + unsigned type = read16(code, ip); + return fprintf(stderr, "multianewarray %4d %2d", type, code[ip++]); + } + + case new_: + return fprintf(stderr, "new %4d", read16(code, ip)); + + case newarray: + return fprintf(stderr, "newarray %2d", code[ip++]); + + case nop: + return fprintf(stderr, "nop"); + case pop_: + return fprintf(stderr, "pop"); + case pop2: + return fprintf(stderr, "pop2"); + + case putfield: + return fprintf(stderr, "putfield %4d", read16(code, ip)); + case putstatic: + return fprintf(stderr, "putstatic %4d", read16(code, ip)); + + case ret: + return fprintf(stderr, "ret %2d", code[ip++]); + + case return_: + return fprintf(stderr, "return_"); + case saload: + return fprintf(stderr, "saload"); + case sastore: + return fprintf(stderr, "sastore"); + + case sipush: + return fprintf(stderr, "sipush %4d", read16(code, ip)); + + case swap: + return fprintf(stderr, "swap"); + + case tableswitch: { + while (ip & 0x3) { + ip++; + } + int32_t default_ = read32(code, ip) + startIp; + int32_t bottom = read32(code, ip); + int32_t top = read32(code, ip); + fprintf(stderr, + "tableswitch default: %d bottom: %d top: %d", + default_, + bottom, + top); + + for (int i = 0; i < top - bottom + 1; i++) { + int32_t d = read32(code, ip) + startIp; + fprintf(stderr, "%s key: %d dest: %d", prefix, i + bottom, d); + } + return 0; + } + + case wide: { + switch (code[ip++]) { + case aload: + return fprintf(stderr, "wide aload %4d", read16(code, ip)); + + case astore: + return fprintf(stderr, "wide astore %4d", read16(code, ip)); + case iinc: + fprintf(stderr, "wide iinc %4d %4d", read16(code, ip), read16(code, ip)); + case iload: + return fprintf(stderr, "wide iload %4d", read16(code, ip)); + case istore: + return fprintf(stderr, "wide istore %4d", read16(code, ip)); + case lload: + return fprintf(stderr, "wide lload %4d", read16(code, ip)); + case lstore: + return fprintf(stderr, "wide lstore %4d", read16(code, ip)); + case ret: + return fprintf(stderr, "wide ret %4d", read16(code, ip)); + + default: { + fprintf( + stderr, "unknown wide instruction %2d %4d", instr, read16(code, ip)); + } + } + } + + default: { + return fprintf(stderr, "unknown instruction %2d", instr); + } + } + return ip; +} + +void disassembleCode(const char* prefix, uint8_t* code, unsigned length) +{ + unsigned ip = 0; + + while (ip < length) { + fprintf(stderr, "%s%x:\t", prefix, ip); + printInstruction(code, ip, prefix); + fprintf(stderr, "\n"); + } +} + +} // namespace debug +} // namespace jvm +} // namespace avian diff --git a/src/debug-util.h b/src/debug-util.h new file mode 100644 index 0000000000..bb981baa10 --- /dev/null +++ b/src/debug-util.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include + +namespace avian { +namespace jvm { +namespace debug { + +// print out a single instruction (no newline) +// returns number of characters printed +int printInstruction(uint8_t* code, unsigned& ip, const char* prefix = ""); +void disassembleCode(const char* prefix, uint8_t* code, unsigned length); + +} // namespace debug +} // namespace jvm +} // namespace avian