dvander@47: /* vim: set ts=4 sw=4 tw=99 et: dvander@47: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@54: #include dvander@0: #include "Opcodes.h" dvander@0: #include "Utility.h" dvander@0: #include "Code.h" dvander@12: #include "Zone.h" dvander@12: #include "Array.h" dvander@54: #include "Strings.h" dvander@70: #include "CompactBuffer.h" dvander@12: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@59: OpInfo ke::OpcodeInfo[] = dvander@0: { dvander@0: #define OPDEF(name, number, text, length, uses, defs) \ dvander@0: {text, length, uses, defs}, dvander@0: #include "Opcodes.tbl" dvander@0: #undef OPDEF dvander@0: }; dvander@0: dvander@12: Code * dvander@34: Code::New(Zone *zone, Handle bytecode, Handle locals, dvander@47: Handle objects, unsigned maxStackDepth, Handle module, dvander@70: Handle safepoints, Handle sourcemap, dvander@70: unsigned lineNumber) dvander@12: { dvander@34: Local code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old))); dvander@34: if (!code) dvander@12: return NULL; dvander@12: dvander@13: code->bytecode_ = bytecode; dvander@13: code->locals_ = locals; dvander@21: code->objects_ = objects; dvander@13: code->maxStackDepth_ = maxStackDepth; dvander@13: code->module_ = module; dvander@47: code->safepoints_ = safepoints; dvander@70: code->sourcemap_ = sourcemap; dvander@70: code->lineNumber_ = lineNumber; dvander@12: return code; dvander@12: } dvander@12: dvander@47: static int dvander@47: CompareSafepoints(const void *a, const void *b) dvander@47: { dvander@47: const unsigned *sa = reinterpret_cast(a); dvander@47: const unsigned *sb = reinterpret_cast(b); dvander@47: if (*sa > *sb) dvander@47: return 1; dvander@47: if (*sa == *sb) dvander@47: return 0; dvander@47: return -1; dvander@47: } dvander@47: dvander@47: uint8 * dvander@47: Code::safepointAt(unsigned pcOffset) dvander@47: { dvander@47: // Only specific opcodes may have safepoints. Asking for a safepoint at dvander@47: // any other position indicates a failure to mark that position as a dvander@47: // safepoint, which is a bug. dvander@47: Opcode op = Opcode(*(start() + pcOffset)); dvander@85: assert(op == OP_CALL || op == OP_NEWARRAY || op == OP_VARREF_LIFO || dvander@47: op == OP_ARGREF_LIFO || op == OP_SLOTREF_LIFO || op == OP_ARRAYREF_LIFO || dvander@47: op == OP_ARRAYCOPY); dvander@47: dvander@47: if (!safepoints_) dvander@47: return NULL; dvander@47: dvander@47: size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth()); dvander@47: assert(!(safepoints_->length() % bytesPerSafepoint)); dvander@47: dvander@47: size_t count = safepoints_->length() / bytesPerSafepoint; dvander@47: dvander@47: void *result = bsearch(&pcOffset, dvander@47: safepoints_->raw(), dvander@47: count, dvander@47: bytesPerSafepoint, dvander@47: CompareSafepoints); dvander@47: dvander@47: if (!result) dvander@47: return NULL; dvander@47: dvander@47: assert(*reinterpret_cast(result) == pcOffset); dvander@47: dvander@47: return Address(result) + sizeof(unsigned); dvander@47: } dvander@47: dvander@70: SourcePosition dvander@70: Code::pcToSource(unsigned pc) dvander@70: { dvander@70: assert(pc < bytecode_->length()); dvander@70: dvander@70: CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length()); dvander@70: dvander@70: unsigned line = 1; dvander@70: unsigned col = 0; dvander@70: unsigned curPc = 0; dvander@70: while (!reader.done()) { dvander@70: curPc += reader.readUint32(); dvander@70: if (curPc > pc) dvander@70: break; dvander@70: dvander@70: line = reader.readUint32(); dvander@70: col = reader.readUint32(); dvander@70: } dvander@70: dvander@70: return SourcePosition(lineNumber_ + line, col); dvander@70: } dvander@70: dvander@0: // All jumps must be the same length. dvander@0: STATIC_ASSERT(OP_JL_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JLE_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JG_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JGE_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JEQ_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JNE_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH); dvander@0: STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH); dvander@0: dvander@0: void dvander@59: ke::Disassemble(Code *code, FILE *fp) dvander@0: { dvander@0: bytecode *pc = code->start(); dvander@0: for (;;) { dvander@0: Opcode op = Opcode(*pc); dvander@0: dvander@0: fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name); dvander@0: dvander@0: switch (op) { dvander@0: case OP_NOP: dvander@0: case OP_RETURN: dvander@72: case OP_RETURNVOID: dvander@0: case OP_ADD: dvander@0: case OP_SUB: dvander@0: case OP_MUL: dvander@0: case OP_DIV: dvander@4: case OP_ADD_F: dvander@4: case OP_SUB_F: dvander@4: case OP_MUL_F: dvander@4: case OP_DIV_F: dvander@4: case OP_CVT_I2F: dvander@0: case OP_POP: dvander@6: case OP_GETARRAY_I: dvander@7: case OP_SETARRAY_I: dvander@7: case OP_GETARRAY_F: dvander@7: case OP_SETARRAY_F: dvander@21: case OP_GETARRAY_C: dvander@21: case OP_SETARRAY_C: dvander@19: case OP_GETARRAY_O: dvander@19: case OP_BOUNDS: dvander@8: case OP_SHL: dvander@8: case OP_SHR: dvander@8: case OP_USHR: dvander@8: case OP_BITAND: dvander@8: case OP_BITOR: dvander@8: case OP_BITXOR: dvander@14: case OP_GETREF_I: dvander@14: case OP_SETREF_I: dvander@14: case OP_GETREF_F: dvander@14: case OP_SETREF_F: dvander@16: case OP_SLOTREF_LIFO: dvander@17: case OP_ARRAYREF_LIFO: dvander@21: case OP_ARRAYCOPY: dvander@22: case OP_DUP: dvander@22: case OP_DUP2: dvander@23: case OP_SWAP: dvander@23: case OP_ROLL3: dvander@23: case OP_PICK2: dvander@23: case OP_PICK3: dvander@73: case OP_CALL: dvander@73: case OP_MODULE: dvander@74: case OP_LT: dvander@74: case OP_LE: dvander@74: case OP_GE: dvander@74: case OP_GT: dvander@74: case OP_EQ: dvander@74: case OP_NE: dvander@74: case OP_LT_F: dvander@74: case OP_LE_F: dvander@74: case OP_GE_F: dvander@74: case OP_GT_F: dvander@74: case OP_EQ_F: dvander@74: case OP_NE_F: dvander@78: case OP_BITNOT: dvander@79: case OP_NOT: dvander@79: case OP_NOT_F: dvander@80: case OP_NEG: dvander@80: case OP_NEG_F: dvander@82: case OP_MOD: dvander@0: break; dvander@0: dvander@0: case OP_STOP: dvander@0: fprintf(fp, "\n"); dvander@47: break; dvander@0: dvander@0: case OP_INT: dvander@0: fprintf(fp, "%d", READ_INT32(pc)); dvander@0: break; dvander@0: dvander@4: case OP_FLOAT: dvander@4: fprintf(fp, "%f", READ_FLOAT(pc)); dvander@4: break; dvander@4: dvander@0: case OP_JL: dvander@0: case OP_JLE: dvander@0: case OP_JG: dvander@0: case OP_JGE: dvander@0: case OP_JEQ: dvander@0: case OP_JNE: dvander@0: case OP_JT: dvander@0: case OP_JF: dvander@74: case OP_JL_F: dvander@74: case OP_JLE_F: dvander@74: case OP_JG_F: dvander@74: case OP_JGE_F: dvander@74: case OP_JEQ_F: dvander@74: case OP_JNE_F: dvander@74: case OP_JT_F: dvander@74: case OP_JF_F: dvander@0: case OP_JUMP: dvander@5: fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc)); dvander@0: break; dvander@0: dvander@85: case OP_NEWARRAY: dvander@0: { dvander@85: Heap::Tenure tenure = (Heap::Tenure)pc[1]; dvander@85: ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1))); dvander@12: fprintf(fp, "%s:", map->type()->innermost()->tag() dvander@54: ? map->type()->innermost()->tag()->chars() dvander@12: : "_"); dvander@12: for (; map; map = map->contained()) { dvander@12: Type *type = map->type(); dvander@12: fprintf(fp, "[%d]", type->elements()); dvander@12: } dvander@85: if (tenure == Heap::Tenure_Stack) dvander@85: fprintf(fp, " ; lifo"); dvander@85: else if (tenure == Heap::Tenure_Old) dvander@85: fprintf(fp, " ; pretenured"); dvander@12: break; dvander@0: } dvander@0: dvander@0: case OP_GETLOCAL: dvander@0: case OP_SETLOCAL: dvander@0: case OP_GETARG: dvander@0: case OP_SETARG: dvander@12: case OP_SAVELIFO: dvander@12: case OP_UNWINDLIFO: dvander@14: case OP_VARREF_LIFO: dvander@14: case OP_ARGREF_LIFO: dvander@72: case OP_OBJECT: dvander@73: case OP_GETMODULE_FN: dvander@85: case OP_GETGLOBAL_I: dvander@85: case OP_GETGLOBAL_F: dvander@85: case OP_GETGLOBAL_O: dvander@85: case OP_SETGLOBAL_I: dvander@85: case OP_SETGLOBAL_F: dvander@85: case OP_SETGLOBAL_O: dvander@0: fprintf(fp, "%u", READ_UINT32(pc)); dvander@0: break; dvander@0: dvander@68: case OP_CALLNATIVE: dvander@68: fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4)); dvander@68: break; dvander@68: dvander@0: default: dvander@0: // Unknown opcode! dvander@0: assert(false); dvander@0: return; dvander@0: } dvander@0: dvander@47: if (op == OP_STOP) dvander@47: break; dvander@47: dvander@0: fprintf(fp, "\n"); dvander@0: pc += OpcodeInfo[op].length; dvander@12: assert(pc < code->start() + code->length()); dvander@0: } dvander@47: dvander@47: fprintf(fp, "\nSafepoints:\n"); dvander@47: ByteArray *safepoints = code->safepoints(); dvander@47: if (safepoints) { dvander@47: size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth()); dvander@47: for (size_t i = 0; i < nsafepoints; i++) { dvander@47: Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i; dvander@47: fprintf(fp, "%4d: ", *reinterpret_cast(address)); dvander@47: unsigned char *bits = (unsigned char *)(address + sizeof(unsigned)); dvander@47: for (unsigned j = 0; j < code->maxStackDepth(); j++) { dvander@47: if (bits[j / 8] & (1 << (j % 8))) dvander@47: fprintf(fp, "%d ", j); dvander@47: } dvander@47: fprintf(fp, "\n"); dvander@47: } dvander@47: } dvander@0: }