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@147: #include "Structures.h" dvander@12: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@59: OpInfo ke::OpcodeInfo[] = dvander@0: { dvander@195: #define OPDEF(name, 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@195: Handle objects, Handle strings, unsigned maxStackDepth, dvander@195: Handle safepoints, Handle sourcemap) 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@195: code->module_ = NULL; dvander@47: code->safepoints_ = safepoints; dvander@70: code->sourcemap_ = sourcemap; dvander@195: code->lineNumber_ = 0; dvander@195: code->strings_ = strings; 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. danderson@93: #ifndef NDEBUG dvander@47: Opcode op = Opcode(*(start() + pcOffset)); dvander@185: assert(op == OP_CALL || dvander@185: op == OP_NEWFIXED || dvander@185: op == OP_NEWEMPTY || dvander@185: op == OP_NEWSIZED || dvander@185: op == OP_VARREF_LIFO || dvander@185: op == OP_ARGREF_LIFO || dvander@185: op == OP_SLOTREF_LIFO || dvander@195: op == OP_COPYARRAY || dvander@195: op == OP_CALLNATIVE || dvander@195: op == OP_PUBLIC); danderson@93: #endif 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_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@157: case OP_GETELEM: dvander@157: case OP_SETELEM: 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@152: case OP_COPYARRAY: dvander@152: case OP_COPYSTRUCT: 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@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@142: case OP_BITS_I2F: dvander@142: case OP_BITS_F2I: dvander@143: case OP_TRUE: dvander@143: case OP_FALSE: dvander@194: case OP_SIZEOF: dvander@195: case OP_PUBLIC: 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_JT: dvander@0: case OP_JF: 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@185: case OP_NEWFIXED: dvander@185: case OP_NEWEMPTY: dvander@185: case OP_NEWSIZED: dvander@0: { dvander@85: Heap::Tenure tenure = (Heap::Tenure)pc[1]; dvander@154: //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1))); 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@182: else if (tenure == Heap::Tenure_Default) dvander@182: fprintf(fp, " ; newborn"); dvander@12: break; dvander@0: } dvander@0: dvander@147: case OP_NEWSTRUCT: dvander@147: { dvander@147: Heap::Tenure tenure = (Heap::Tenure)pc[1]; dvander@147: StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1))); dvander@147: fprintf(fp, "%s", map->type()->name()->chars()); dvander@147: if (tenure == Heap::Tenure_Stack) dvander@147: fprintf(fp, " ; lifo"); dvander@147: else if (tenure == Heap::Tenure_Old) dvander@147: fprintf(fp, " ; pretenured"); dvander@182: else if (tenure == Heap::Tenure_Default) dvander@182: fprintf(fp, " ; newborn"); dvander@147: break; dvander@147: } dvander@147: 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@148: case OP_GETFIELD: dvander@148: case OP_SETFIELD: dvander@0: fprintf(fp, "%u", READ_UINT32(pc)); dvander@0: break; dvander@0: dvander@68: case OP_CALLNATIVE: dvander@195: { dvander@195: unsigned argc = READ_UINT32(pc); dvander@195: fprintf(fp, " ; %u args", argc); dvander@68: break; dvander@195: } dvander@68: dvander@172: case OP_TABLESWITCH: dvander@172: { dvander@172: int low = READ_TABLESWITCH_LOW(pc); dvander@172: int high = READ_TABLESWITCH_HIGH(pc); dvander@172: fprintf(fp, "%d, %d\n", low, high); dvander@172: break; dvander@172: } dvander@172: dvander@195: case OP_GETGLOBAL: dvander@195: case OP_SETGLOBAL: dvander@195: { dvander@195: unsigned index = READ_UINT32(pc); dvander@195: fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars()); dvander@195: break; dvander@195: } dvander@195: 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: }