diff -r c4b1341297e5 -r ba85a47ee414 src/Opcodes.cpp --- a/src/Opcodes.cpp Mon Jun 10 00:46:29 2013 +0100 +++ b/src/Opcodes.cpp Mon Jun 10 01:04:43 2013 +0100 @@ -1,350 +1,350 @@ -/* vim: set ts=4 sw=4 tw=99 et: - * - * Copyright (C) 2012 David Anderson - * - * This file is part of JITCraft. - * - * JITCraft is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * JITCraft. If not, see http://www.gnu.org/licenses/. - */ -#include -#include "Opcodes.h" -#include "Utility.h" -#include "Code.h" -#include "Zone.h" -#include "Array.h" -#include "Strings.h" -#include "CompactBuffer.h" -#include "Structures.h" -#include "Modules.h" -#include "Heap-inl.h" - -using namespace ke; - -OpInfo ke::OpcodeInfo[] = -{ -#define OPDEF(name, text, length, uses, defs) \ - {text, length, uses, defs}, -#include "Opcodes.tbl" -#undef OPDEF -}; - -Code * -Code::New(Zone *zone, Handle bytecode, Handle locals, - Handle objects, Handle strings, unsigned maxStackDepth, - unsigned maxLoopDepth, Handle safepoints, Handle sourcemap) -{ - Local code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old))); - if (!code) - return NULL; - - code->bytecode_ = bytecode; - code->locals_ = locals; - code->objects_ = objects; - code->maxStackDepth_ = maxStackDepth; - code->module_ = NULL; - code->safepoints_ = safepoints; - code->sourcemap_ = sourcemap; - code->lineNumber_ = 0; - code->strings_ = strings; - code->maxLoopDepth_ = maxLoopDepth; - return code; -} - -static int -CompareSafepoints(const void *a, const void *b) -{ - const unsigned *sa = reinterpret_cast(a); - const unsigned *sb = reinterpret_cast(b); - if (*sa > *sb) - return 1; - if (*sa == *sb) - return 0; - return -1; -} - -uint8 * -Code::safepointAt(unsigned pcOffset) -{ - // Only specific opcodes may have safepoints. Asking for a safepoint at - // any other position indicates a failure to mark that position as a - // safepoint, which is a bug. -#ifndef NDEBUG - Opcode op = Opcode(*(start() + pcOffset)); - assert(op == OP_CALL || - op == OP_NEWFIXED || - op == OP_NEWEMPTY || - op == OP_NEWSIZED || - op == OP_VARREF_LIFO || - op == OP_ARGREF_LIFO || - op == OP_SLOTREF_LIFO || - op == OP_COPYARRAY || - op == OP_CALLNATIVE || - op == OP_PUBLIC); -#endif - - if (!safepoints_) - return NULL; - - size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth()); - assert(!(safepoints_->length() % bytesPerSafepoint)); - - size_t count = safepoints_->length() / bytesPerSafepoint; - - void *result = bsearch(&pcOffset, - safepoints_->raw(), - count, - bytesPerSafepoint, - CompareSafepoints); - - if (!result) - return NULL; - - assert(*reinterpret_cast(result) == pcOffset); - - return Address(result) + sizeof(unsigned); -} - -SourcePosition -Code::pcToSource(unsigned pc) -{ - assert(pc < bytecode_->length()); - - CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length()); - - unsigned line = 1; - unsigned col = 0; - unsigned curPc = 0; - while (!reader.done()) { - curPc += reader.readUint32(); - if (curPc > pc) - break; - - line = reader.readUint32(); - col = reader.readUint32(); - } - - return SourcePosition(lineNumber_ + line, col); -} - -// All jumps must be the same length. -STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH); -STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH); - -void -ke::Disassemble(Code *code, FILE *fp) -{ - bytecode *pc = code->start(); - for (;;) { - Opcode op = Opcode(*pc); - - fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name); - - switch (op) { - case OP_NOP: - case OP_RETURN: - case OP_RETURNVOID: - case OP_ADD: - case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_ADD_F: - case OP_SUB_F: - case OP_MUL_F: - case OP_DIV_F: - case OP_CVT_I2F: - case OP_CVT_I2B: - case OP_POP: - case OP_GETELEM: - case OP_SETELEM: - case OP_SHL: - case OP_SHR: - case OP_USHR: - case OP_BITAND: - case OP_BITOR: - case OP_BITXOR: - case OP_GETREF_I: - case OP_SETREF_I: - case OP_GETREF_F: - case OP_SETREF_F: - case OP_SLOTREF_LIFO: - case OP_COPYARRAY: - case OP_COPYSTRUCT: - case OP_DUP: - case OP_DUP2: - case OP_SWAP: - case OP_ROLL3: - case OP_PICK2: - case OP_PICK3: - case OP_CALL: - case OP_LT: - case OP_LE: - case OP_GE: - case OP_GT: - case OP_EQ: - case OP_NE: - case OP_LT_F: - case OP_LE_F: - case OP_GE_F: - case OP_GT_F: - case OP_EQ_F: - case OP_NE_F: - case OP_BITNOT: - case OP_NOT: - case OP_NOT_F: - case OP_NEG: - case OP_NEG_F: - case OP_MOD: - case OP_BITCAST: - case OP_TRUE: - case OP_FALSE: - case OP_SIZEOF: - case OP_PUBLIC: - case OP_LEAVELOOP: - case OP_DUPARRAY: - case OP_DEPARRAY: - break; - - case OP_ENTERLOOP: - if (pc[1]) - fprintf(fp, "; lifo region"); - break; - - case OP_STOP: - fprintf(fp, "\n"); - break; - - case OP_INT: - fprintf(fp, "%d", READ_INT32(pc)); - break; - - case OP_FLOAT: - fprintf(fp, "%f", READ_FLOAT(pc)); - break; - - case OP_JT: - case OP_JF: - case OP_JUMP: - case OP_CONTINUE: - case OP_BREAK: - fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc)); - break; - - case OP_NEWFIXED: - case OP_NEWEMPTY: - case OP_NEWSIZED: - { - Heap::Tenure tenure = (Heap::Tenure)pc[1]; - //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1))); - if (tenure == Heap::Tenure_Stack) - fprintf(fp, " ; lifo"); - else if (tenure == Heap::Tenure_Old) - fprintf(fp, " ; pretenured"); - else if (tenure == Heap::Tenure_Default) - fprintf(fp, " ; newborn"); - break; - } - - case OP_NEWSTRUCT: - { - Heap::Tenure tenure = (Heap::Tenure)pc[1]; - StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1))); - fprintf(fp, "%s", StructType::cast(map->type())->name()->chars()); - if (tenure == Heap::Tenure_Stack) - fprintf(fp, " ; lifo"); - else if (tenure == Heap::Tenure_Old) - fprintf(fp, " ; pretenured"); - else if (tenure == Heap::Tenure_Default) - fprintf(fp, " ; newborn"); - break; - } - - case OP_GETLOCAL: - case OP_SETLOCAL: - case OP_GETARG: - case OP_SETARG: - case OP_SAVELIFO: - case OP_UNWINDLIFO: - case OP_VARREF_LIFO: - case OP_ARGREF_LIFO: - case OP_OBJECT: - case OP_GETFIELD: - case OP_SETFIELD: - fprintf(fp, "%u", READ_UINT32(pc)); - break; - - case OP_CALLNATIVE: - { - unsigned argc = READ_UINT32(pc); - fprintf(fp, " ; %u args", argc); - break; - } - - case OP_TABLESWITCH: - { - int low = READ_TABLESWITCH_LOW(pc); - int high = READ_TABLESWITCH_HIGH(pc); - fprintf(fp, "%d, %d\n", low, high); - break; - } - - case OP_GETGLOBAL: - case OP_SETGLOBAL: - { - unsigned index = READ_UINT32(pc); - fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars()); - break; - } - - case OP_IMPORT: - { - unsigned index = READ_UINT32(pc); - FixedArray *path = code->module()->importPathAt(index); - fprintf(fp, " ; "); - for (unsigned i = 0; i < path->length(); i++) { - fprintf(fp, "%s", String::cast(path->at(i))->chars()); - if (i != path->length() - 1) - fprintf(fp, "."); - } - break; - } - - default: - // Unknown opcode! - assert(false); - return; - } - - if (op == OP_STOP) - break; - - fprintf(fp, "\n"); - pc += OpcodeInfo[op].length; - assert(pc < code->start() + code->length()); - } - - fprintf(fp, "\nSafepoints:\n"); - ByteArray *safepoints = code->safepoints(); - if (safepoints) { - size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth()); - for (size_t i = 0; i < nsafepoints; i++) { - Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i; - fprintf(fp, "%4d: ", *reinterpret_cast(address)); - unsigned char *bits = (unsigned char *)(address + sizeof(unsigned)); - for (unsigned j = 0; j < code->maxStackDepth(); j++) { - if (bits[j / 8] & (1 << (j % 8))) - fprintf(fp, "%d ", j); - } - fprintf(fp, "\n"); - } - } -} +/* vim: set ts=4 sw=4 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of JITCraft. + * + * JITCraft is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * JITCraft. If not, see http://www.gnu.org/licenses/. + */ +#include +#include "Opcodes.h" +#include "Utility.h" +#include "Code.h" +#include "Zone.h" +#include "Array.h" +#include "Strings.h" +#include "CompactBuffer.h" +#include "Structures.h" +#include "Modules.h" +#include "Heap-inl.h" + +using namespace ke; + +OpInfo ke::OpcodeInfo[] = +{ +#define OPDEF(name, text, length, uses, defs) \ + {text, length, uses, defs}, +#include "Opcodes.tbl" +#undef OPDEF +}; + +Code * +Code::New(Zone *zone, Handle bytecode, Handle locals, + Handle objects, Handle strings, unsigned maxStackDepth, + unsigned maxLoopDepth, Handle safepoints, Handle sourcemap) +{ + Local code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old))); + if (!code) + return NULL; + + code->bytecode_ = bytecode; + code->locals_ = locals; + code->objects_ = objects; + code->maxStackDepth_ = maxStackDepth; + code->module_ = NULL; + code->safepoints_ = safepoints; + code->sourcemap_ = sourcemap; + code->lineNumber_ = 0; + code->strings_ = strings; + code->maxLoopDepth_ = maxLoopDepth; + return code; +} + +static int +CompareSafepoints(const void *a, const void *b) +{ + const unsigned *sa = reinterpret_cast(a); + const unsigned *sb = reinterpret_cast(b); + if (*sa > *sb) + return 1; + if (*sa == *sb) + return 0; + return -1; +} + +uint8 * +Code::safepointAt(unsigned pcOffset) +{ + // Only specific opcodes may have safepoints. Asking for a safepoint at + // any other position indicates a failure to mark that position as a + // safepoint, which is a bug. +#ifndef NDEBUG + Opcode op = Opcode(*(start() + pcOffset)); + assert(op == OP_CALL || + op == OP_NEWFIXED || + op == OP_NEWEMPTY || + op == OP_NEWSIZED || + op == OP_VARREF_LIFO || + op == OP_ARGREF_LIFO || + op == OP_SLOTREF_LIFO || + op == OP_COPYARRAY || + op == OP_CALLNATIVE || + op == OP_PUBLIC); +#endif + + if (!safepoints_) + return NULL; + + size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth()); + assert(!(safepoints_->length() % bytesPerSafepoint)); + + size_t count = safepoints_->length() / bytesPerSafepoint; + + void *result = bsearch(&pcOffset, + safepoints_->raw(), + count, + bytesPerSafepoint, + CompareSafepoints); + + if (!result) + return NULL; + + assert(*reinterpret_cast(result) == pcOffset); + + return Address(result) + sizeof(unsigned); +} + +SourcePosition +Code::pcToSource(unsigned pc) +{ + assert(pc < bytecode_->length()); + + CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length()); + + unsigned line = 1; + unsigned col = 0; + unsigned curPc = 0; + while (!reader.done()) { + curPc += reader.readUint32(); + if (curPc > pc) + break; + + line = reader.readUint32(); + col = reader.readUint32(); + } + + return SourcePosition(lineNumber_ + line, col); +} + +// All jumps must be the same length. +STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH); +STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH); + +void +ke::Disassemble(Code *code, FILE *fp) +{ + bytecode *pc = code->start(); + for (;;) { + Opcode op = Opcode(*pc); + + fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name); + + switch (op) { + case OP_NOP: + case OP_RETURN: + case OP_RETURNVOID: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_ADD_F: + case OP_SUB_F: + case OP_MUL_F: + case OP_DIV_F: + case OP_CVT_I2F: + case OP_CVT_I2B: + case OP_POP: + case OP_GETELEM: + case OP_SETELEM: + case OP_SHL: + case OP_SHR: + case OP_USHR: + case OP_BITAND: + case OP_BITOR: + case OP_BITXOR: + case OP_GETREF_I: + case OP_SETREF_I: + case OP_GETREF_F: + case OP_SETREF_F: + case OP_SLOTREF_LIFO: + case OP_COPYARRAY: + case OP_COPYSTRUCT: + case OP_DUP: + case OP_DUP2: + case OP_SWAP: + case OP_ROLL3: + case OP_PICK2: + case OP_PICK3: + case OP_CALL: + case OP_LT: + case OP_LE: + case OP_GE: + case OP_GT: + case OP_EQ: + case OP_NE: + case OP_LT_F: + case OP_LE_F: + case OP_GE_F: + case OP_GT_F: + case OP_EQ_F: + case OP_NE_F: + case OP_BITNOT: + case OP_NOT: + case OP_NOT_F: + case OP_NEG: + case OP_NEG_F: + case OP_MOD: + case OP_BITCAST: + case OP_TRUE: + case OP_FALSE: + case OP_SIZEOF: + case OP_PUBLIC: + case OP_LEAVELOOP: + case OP_DUPARRAY: + case OP_DEPARRAY: + break; + + case OP_ENTERLOOP: + if (pc[1]) + fprintf(fp, "; lifo region"); + break; + + case OP_STOP: + fprintf(fp, "\n"); + break; + + case OP_INT: + fprintf(fp, "%d", READ_INT32(pc)); + break; + + case OP_FLOAT: + fprintf(fp, "%f", READ_FLOAT(pc)); + break; + + case OP_JT: + case OP_JF: + case OP_JUMP: + case OP_CONTINUE: + case OP_BREAK: + fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc)); + break; + + case OP_NEWFIXED: + case OP_NEWEMPTY: + case OP_NEWSIZED: + { + Heap::Tenure tenure = (Heap::Tenure)pc[1]; + //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1))); + if (tenure == Heap::Tenure_Stack) + fprintf(fp, " ; lifo"); + else if (tenure == Heap::Tenure_Old) + fprintf(fp, " ; pretenured"); + else if (tenure == Heap::Tenure_Default) + fprintf(fp, " ; newborn"); + break; + } + + case OP_NEWSTRUCT: + { + Heap::Tenure tenure = (Heap::Tenure)pc[1]; + StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1))); + fprintf(fp, "%s", StructType::cast(map->type())->name()->chars()); + if (tenure == Heap::Tenure_Stack) + fprintf(fp, " ; lifo"); + else if (tenure == Heap::Tenure_Old) + fprintf(fp, " ; pretenured"); + else if (tenure == Heap::Tenure_Default) + fprintf(fp, " ; newborn"); + break; + } + + case OP_GETLOCAL: + case OP_SETLOCAL: + case OP_GETARG: + case OP_SETARG: + case OP_SAVELIFO: + case OP_UNWINDLIFO: + case OP_VARREF_LIFO: + case OP_ARGREF_LIFO: + case OP_OBJECT: + case OP_GETFIELD: + case OP_SETFIELD: + fprintf(fp, "%u", READ_UINT32(pc)); + break; + + case OP_CALLNATIVE: + { + unsigned argc = READ_UINT32(pc); + fprintf(fp, " ; %u args", argc); + break; + } + + case OP_TABLESWITCH: + { + int low = READ_TABLESWITCH_LOW(pc); + int high = READ_TABLESWITCH_HIGH(pc); + fprintf(fp, "%d, %d\n", low, high); + break; + } + + case OP_GETGLOBAL: + case OP_SETGLOBAL: + { + unsigned index = READ_UINT32(pc); + fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars()); + break; + } + + case OP_IMPORT: + { + unsigned index = READ_UINT32(pc); + FixedArray *path = code->module()->importPathAt(index); + fprintf(fp, " ; "); + for (unsigned i = 0; i < path->length(); i++) { + fprintf(fp, "%s", String::cast(path->at(i))->chars()); + if (i != path->length() - 1) + fprintf(fp, "."); + } + break; + } + + default: + // Unknown opcode! + assert(false); + return; + } + + if (op == OP_STOP) + break; + + fprintf(fp, "\n"); + pc += OpcodeInfo[op].length; + assert(pc < code->start() + code->length()); + } + + fprintf(fp, "\nSafepoints:\n"); + ByteArray *safepoints = code->safepoints(); + if (safepoints) { + size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth()); + for (size_t i = 0; i < nsafepoints; i++) { + Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i; + fprintf(fp, "%4d: ", *reinterpret_cast(address)); + unsigned char *bits = (unsigned char *)(address + sizeof(unsigned)); + for (unsigned j = 0; j < code->maxStackDepth(); j++) { + if (bits[j / 8] & (1 << (j % 8))) + fprintf(fp, "%d ", j); + } + fprintf(fp, "\n"); + } + } +}