Cosmo/src/cdebug.c

230 lines
7.7 KiB
C

#include "cdebug.h"
#include "cobj.h"
#include "cvalue.h"
void printIndent(int indent)
{
for (int i = 0; i < indent; i++) {
printf("\t");
}
}
static int simpleInstruction(const char *name, int offset)
{
printf("%s", name);
return offset + 1; // consume opcode
}
static int u8OperandInstruction(const char *name, CChunk *chunk, int offset)
{
printf("%-16s [%03d]", name, readu8Chunk(chunk, offset + 1));
return offset + 2;
}
static int u16OperandInstruction(const char *name, CChunk *chunk, int offset)
{
printf("%-16s [%05d]", name, readu16Chunk(chunk, offset + 1));
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
}
static int JumpInstruction(const char *name, CChunk *chunk, int offset, int dir)
{
int jmp = ((int)readu16Chunk(chunk, offset + 1)) * dir;
printf("%-16s [%05d] - jumps to %04d", name, jmp, offset + 3 + jmp);
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
}
static int u8u8OperandInstruction(const char *name, CChunk *chunk, int offset)
{
printf("%-16s [%03d] [%03d]", name, readu8Chunk(chunk, offset + 1),
readu8Chunk(chunk, offset + 2));
return offset + 3; // op + u8 + u8
}
static int u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
{
printf("%-16s [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
readu16Chunk(chunk, offset + 2));
return offset + 4; // op + u8 + u16
}
static int u8u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
{
printf("%-16s [%03d] [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
readu8Chunk(chunk, offset + 2), readu16Chunk(chunk, offset + 3));
return offset + 5; // op + u8 + u8 + u16
}
static int constInstruction(const char *name, CChunk *chunk, int offset)
{
int index = readu16Chunk(chunk, offset + 1);
printf("%-16s [%05d] - ", name, index);
CValue val = chunk->constants.values[index];
cosmoV_printValue(val);
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION)); // consume opcode + uint
}
// public methods in the cdebug.h header
void disasmChunk(CChunk *chunk, const char *name, int indent)
{
printIndent(indent);
printf("===[[ disasm for %s ]]===\n", name);
for (size_t offset = 0; offset < chunk->count;) {
offset = disasmInstr(chunk, offset, indent);
printf("\n");
}
}
int disasmInstr(CChunk *chunk, int offset, int indent)
{
printIndent(indent);
printf("%04d ", offset);
INSTRUCTION i = chunk->buf[offset];
int line = chunk->lineInfo[offset];
if (offset > 0 && line == chunk->lineInfo[offset - 1]) {
printf(" | ");
} else {
printf("%4d ", line);
}
switch (i) {
case OP_LOADCONST:
return constInstruction("OP_LOADCONST", chunk, offset);
case OP_SETGLOBAL:
return constInstruction("OP_SETGLOBAL", chunk, offset);
case OP_GETGLOBAL:
return constInstruction("OP_GETGLOBAL", chunk, offset);
case OP_SETLOCAL:
return u8OperandInstruction("OP_SETLOCAL", chunk, offset);
case OP_GETLOCAL:
return u8OperandInstruction("OP_GETLOCAL", chunk, offset);
case OP_SETUPVAL:
return u8OperandInstruction("OP_SETUPVAL", chunk, offset);
case OP_GETUPVAL:
return u8OperandInstruction("OP_GETUPVAL", chunk, offset);
case OP_PEJMP:
return JumpInstruction("OP_PEJMP", chunk, offset, 1);
case OP_EJMP:
return JumpInstruction("OP_EJMP", chunk, offset, 1);
case OP_JMP:
return JumpInstruction("OP_JMP", chunk, offset, 1);
case OP_JMPBACK:
return JumpInstruction("OP_JMPBACK", chunk, offset, -1);
case OP_POP:
return u8OperandInstruction("OP_POP", chunk, offset);
case OP_CALL:
return u8u8OperandInstruction("OP_CALL", chunk, offset);
case OP_CLOSURE: {
int index = readu16Chunk(chunk, offset + 1);
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
CValue val = chunk->constants.values[index];
CObjFunction *cobjFunc = (CObjFunction *)cosmoV_readRef(val);
offset += 3; // we consumed the opcode + u16
cosmoV_printValue(val);
printf("\n");
// list the upvalues/locals that are captured
for (int i = 0; i < cobjFunc->upvals; i++) {
uint8_t encoding = readu8Chunk(chunk, offset++);
uint8_t index = readu8Chunk(chunk, offset++);
printIndent(indent + 1);
printf("references %s [%d]\n", encoding == OP_GETLOCAL ? "local" : "upvalue", index);
}
// print the chunk
disasmChunk(&cobjFunc->chunk, cobjFunc->name == NULL ? UNNAMEDCHUNK : cobjFunc->name->str,
indent + 1);
return offset;
}
case OP_CLOSE:
return simpleInstruction("OP_CLOSE", offset);
case OP_NEWTABLE:
return u16OperandInstruction("OP_NEWTABLE", chunk, offset);
case OP_NEWARRAY:
return u16OperandInstruction("OP_NEWARRAY", chunk, offset);
case OP_INDEX:
return simpleInstruction("OP_INDEX", offset);
case OP_NEWINDEX:
return simpleInstruction("OP_NEWINDEX", offset);
case OP_NEWOBJECT:
return u16OperandInstruction("OP_NEWOBJECT", chunk, offset);
case OP_SETOBJECT:
return constInstruction("OP_SETOBJECT", chunk, offset);
case OP_GETOBJECT:
return constInstruction("OP_GETOBJECT", chunk, offset);
case OP_GETMETHOD:
return constInstruction("OP_GETMETHOD", chunk, offset);
case OP_INVOKE:
return u8u8u16OperandInstruction("OP_INVOKE", chunk, offset);
case OP_ITER:
return simpleInstruction("OP_ITER", offset);
case OP_NEXT:
return u8u16OperandInstruction("OP_NEXT", chunk, offset);
case OP_ADD:
return simpleInstruction("OP_ADD", offset);
case OP_SUB:
return simpleInstruction("OP_SUB", offset);
case OP_MULT:
return simpleInstruction("OP_MULT", offset);
case OP_DIV:
return simpleInstruction("OP_DIV", offset);
case OP_MOD:
return simpleInstruction("OP_MOD", offset);
case OP_POW:
return simpleInstruction("OP_POW", offset);
case OP_TRUE:
return simpleInstruction("OP_TRUE", offset);
case OP_FALSE:
return simpleInstruction("OP_FALSE", offset);
case OP_NIL:
return simpleInstruction("OP_NIL", offset);
case OP_NOT:
return simpleInstruction("OP_NOT", offset);
case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER:
return simpleInstruction("OP_GREATER", offset);
case OP_GREATER_EQUAL:
return simpleInstruction("OP_GREATER_EQUAL", offset);
case OP_LESS:
return simpleInstruction("OP_LESS", offset);
case OP_LESS_EQUAL:
return simpleInstruction("OP_LESS_EQUAL", offset);
case OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset);
case OP_COUNT:
return simpleInstruction("OP_COUNT", offset);
case OP_CONCAT:
return u8OperandInstruction("OP_CONCAT", chunk, offset);
case OP_INCLOCAL:
return u8u8OperandInstruction("OP_INCLOCAL", chunk, offset);
case OP_INCGLOBAL:
return u8u16OperandInstruction("OP_INCGLOBAL", chunk, offset);
case OP_INCUPVAL:
return u8u8OperandInstruction("OP_INCUPVAL", chunk, offset);
case OP_INCINDEX:
return u8OperandInstruction("OP_INCINDEX", chunk, offset);
case OP_INCOBJECT:
return u8u16OperandInstruction("OP_INCOBJECT", chunk, offset);
case OP_RETURN:
return u8OperandInstruction("OP_RETURN", chunk, offset);
default:
printf("Unknown opcode! [%d]\n", i);
return 1;
}
return 1;
}
void cosmoG_disassemble(CObjClosure *closure)
{
disasmChunk(&closure->function->chunk, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, 0);
}