improve disassembly somewhat and add dis module
This commit is contained in:
parent
04391ebbaa
commit
ab158260f7
@ -347,7 +347,7 @@ static KrkFunction * endCompiler() {
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLY
|
||||
if ((vm.flags & KRK_ENABLE_DISASSEMBLY) && !parser.hadError) {
|
||||
krk_disassembleChunk(currentChunk(), function->name ? function->name->chars : "<module>");
|
||||
krk_disassembleChunk(stderr, function, function->name ? function->name->chars : "<module>");
|
||||
fprintf(stderr, "Function metadata: requiredArgs=%d keywordArgs=%d upvalueCount=%d\n",
|
||||
function->requiredArgs, function->keywordArgs, (int)function->upvalueCount);
|
||||
fprintf(stderr, "__doc__: \"%s\"\n", function->docstring ? function->docstring->chars : "");
|
||||
|
80
debug.c
80
debug.c
@ -3,38 +3,45 @@
|
||||
#include "debug.h"
|
||||
#include "vm.h"
|
||||
|
||||
void krk_disassembleChunk(KrkChunk * chunk, const char * name) {
|
||||
fprintf(stderr, "[%s from %s]\n", name, chunk->filename->chars);
|
||||
void krk_disassembleChunk(FILE * f, KrkFunction * func, const char * name) {
|
||||
KrkChunk * chunk = &func->chunk;
|
||||
fprintf(f, "[%s from %s]\n", name, chunk->filename->chars);
|
||||
for (size_t offset = 0; offset < chunk->count;) {
|
||||
offset = krk_disassembleInstruction(chunk, offset);
|
||||
offset = krk_disassembleInstruction(f, func, offset);
|
||||
}
|
||||
}
|
||||
|
||||
#define SIMPLE(opc) case opc: fprintf(stderr, "%s\n", #opc); return offset + 1;
|
||||
static inline const char * opcodeClean(const char * opc) {
|
||||
return &opc[3];
|
||||
}
|
||||
|
||||
#define SIMPLE(opc) case opc: fprintf(f, "%s\n", opcodeClean(#opc)); return offset + 1;
|
||||
#define CONSTANT(opc,more) case opc: { size_t constant = chunk->code[offset + 1]; \
|
||||
fprintf(stderr, "%-16s %4d ", #opc, (int)constant); \
|
||||
krk_printValueSafe(stderr, chunk->constants.values[constant]); \
|
||||
fprintf(stderr," (type=%s)\n", krk_typeName(chunk->constants.values[constant])); \
|
||||
fprintf(f, "%-16s %4d ", opcodeClean(#opc), (int)constant); \
|
||||
krk_printValueSafe(f, chunk->constants.values[constant]); \
|
||||
fprintf(f," (type=%s)\n", krk_typeName(chunk->constants.values[constant])); \
|
||||
more; \
|
||||
return offset + 2; } \
|
||||
case opc ## _LONG: { size_t constant = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); \
|
||||
fprintf(stderr, "%-16s %4d ", #opc "_LONG", (int)constant); \
|
||||
krk_printValueSafe(stderr, chunk->constants.values[constant]); \
|
||||
fprintf(stderr," (type=%s)\n", krk_typeName(chunk->constants.values[constant])); \
|
||||
fprintf(f, "%-16s %4d ", opcodeClean(#opc "_LONG"), (int)constant); \
|
||||
krk_printValueSafe(f, chunk->constants.values[constant]); \
|
||||
fprintf(f," (type=%s)\n", krk_typeName(chunk->constants.values[constant])); \
|
||||
more; \
|
||||
return offset + 4; }
|
||||
#define OPERANDB(opc) case opc: { uint32_t operand = chunk->code[offset + 1]; \
|
||||
fprintf(stderr, "%-16s %4d\n", #opc, (int)operand); \
|
||||
#define OPERANDB(opc,more) case opc: { uint32_t operand = chunk->code[offset + 1]; \
|
||||
fprintf(f, "%-16s %4d", opcodeClean(#opc), (int)operand); \
|
||||
more; fprintf(f,"\n"); \
|
||||
return offset + 2; }
|
||||
#define OPERAND(opc) OPERANDB(opc) \
|
||||
#define OPERAND(opc,more) OPERANDB(opc,more) \
|
||||
case opc ## _LONG: { uint32_t operand = (chunk->code[offset + 1] << 16) | \
|
||||
(chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); \
|
||||
fprintf(stderr, "%-16s %4d\n", #opc "_LONG", (int)operand); \
|
||||
fprintf(f, "%-16s %4d", opcodeClean(#opc "_LONG"), (int)operand); \
|
||||
more; fprintf(f,"\n"); \
|
||||
return offset + 4; }
|
||||
#define JUMP(opc,sign) case opc: { uint16_t jump = (chunk->code[offset + 1] << 8) | \
|
||||
(chunk->code[offset + 2]); \
|
||||
fprintf(stderr, "%-16s %4d -> %d\n", #opc, (int)offset, (int)(offset + 3 sign jump)); \
|
||||
fprintf(f, "%-16s %4d -> %d\n", opcodeClean(#opc), (int)offset, (int)(offset + 3 sign jump)); \
|
||||
return offset + 3; }
|
||||
|
||||
#define CLOSURE_MORE \
|
||||
@ -42,10 +49,20 @@ void krk_disassembleChunk(KrkChunk * chunk, const char * name) {
|
||||
for (size_t j = 0; j < function->upvalueCount; ++j) { \
|
||||
int isLocal = chunk->code[offset++ + 2]; \
|
||||
int index = chunk->code[offset++ + 2]; \
|
||||
fprintf(stderr, "%04d | %s %d\n", \
|
||||
fprintf(f, "%04d | %s %d\n", \
|
||||
(int)offset - 2, isLocal ? "local" : "upvalue", index); \
|
||||
}
|
||||
|
||||
#define EXPAND_ARGS_MORE \
|
||||
fprintf(f, " (%s)", operand == 0 ? "singleton" : (operand == 1 ? "list" : "dict"));
|
||||
|
||||
#define LOCAL_MORE \
|
||||
if ((short int)operand < (func->requiredArgs)) { \
|
||||
fprintf(f, " (%s)", AS_CSTRING(func->requiredArgNames.values[operand])); \
|
||||
} else if ((short int)operand < (func->requiredArgs + func->keywordArgs)) { \
|
||||
fprintf(f, " (%s)", AS_CSTRING(func->keywordArgNames.values[operand-func->requiredArgs])); \
|
||||
}
|
||||
|
||||
size_t krk_lineNumber(KrkChunk * chunk, size_t offset) {
|
||||
size_t line = 0;
|
||||
for (size_t i = 0; i < chunk->linesCount; ++i) {
|
||||
@ -55,12 +72,13 @@ size_t krk_lineNumber(KrkChunk * chunk, size_t offset) {
|
||||
return line;
|
||||
}
|
||||
|
||||
size_t krk_disassembleInstruction(KrkChunk * chunk, size_t offset) {
|
||||
fprintf(stderr, "%04u ", (unsigned int)offset);
|
||||
size_t krk_disassembleInstruction(FILE * f, KrkFunction * func, size_t offset) {
|
||||
KrkChunk * chunk = &func->chunk;
|
||||
fprintf(f, "%04u ", (unsigned int)offset);
|
||||
if (offset > 0 && krk_lineNumber(chunk, offset) == krk_lineNumber(chunk, offset - 1)) {
|
||||
fprintf(stderr, " | ");
|
||||
fprintf(f, " | ");
|
||||
} else {
|
||||
fprintf(stderr, "%4d ", (int)krk_lineNumber(chunk, offset));
|
||||
fprintf(f, "%4d ", (int)krk_lineNumber(chunk, offset));
|
||||
}
|
||||
uint8_t opcode = chunk->code[offset];
|
||||
|
||||
@ -96,8 +114,8 @@ size_t krk_disassembleInstruction(KrkChunk * chunk, size_t offset) {
|
||||
SIMPLE(OP_INVOKE_GETSLICE)
|
||||
SIMPLE(OP_SWAP)
|
||||
SIMPLE(OP_FINALIZE)
|
||||
OPERANDB(OP_DUP)
|
||||
OPERANDB(OP_EXPAND_ARGS)
|
||||
OPERANDB(OP_DUP,(void)0)
|
||||
OPERANDB(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
|
||||
CONSTANT(OP_DEFINE_GLOBAL,(void)0)
|
||||
CONSTANT(OP_CONSTANT,(void)0)
|
||||
CONSTANT(OP_GET_GLOBAL,(void)0)
|
||||
@ -109,21 +127,21 @@ size_t krk_disassembleInstruction(KrkChunk * chunk, size_t offset) {
|
||||
CONSTANT(OP_CLOSURE, CLOSURE_MORE)
|
||||
CONSTANT(OP_IMPORT, (void)0)
|
||||
CONSTANT(OP_GET_SUPER, (void)0)
|
||||
OPERAND(OP_KWARGS)
|
||||
OPERAND(OP_SET_LOCAL)
|
||||
OPERAND(OP_GET_LOCAL)
|
||||
OPERAND(OP_SET_UPVALUE)
|
||||
OPERAND(OP_GET_UPVALUE)
|
||||
OPERAND(OP_CALL)
|
||||
OPERAND(OP_INC)
|
||||
OPERAND(OP_TUPLE)
|
||||
OPERAND(OP_KWARGS, (void)0)
|
||||
OPERAND(OP_SET_LOCAL, LOCAL_MORE)
|
||||
OPERAND(OP_GET_LOCAL, LOCAL_MORE)
|
||||
OPERAND(OP_SET_UPVALUE, (void)0)
|
||||
OPERAND(OP_GET_UPVALUE, (void)0)
|
||||
OPERAND(OP_CALL, (void)0)
|
||||
OPERAND(OP_INC, (void)0)
|
||||
OPERAND(OP_TUPLE, (void)0)
|
||||
JUMP(OP_JUMP,+)
|
||||
JUMP(OP_JUMP_IF_FALSE,+)
|
||||
JUMP(OP_JUMP_IF_TRUE,+)
|
||||
JUMP(OP_LOOP,-)
|
||||
JUMP(OP_PUSH_TRY,+)
|
||||
}
|
||||
fprintf(stderr, "Unknown opcode: %02x\n", opcode);
|
||||
fprintf(f, "Unknown opcode: %02x\n", opcode);
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
|
6
debug.h
6
debug.h
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chunk.h"
|
||||
#include "object.h"
|
||||
|
||||
extern void krk_disassembleChunk(KrkChunk * chunk, const char * name);
|
||||
extern size_t krk_disassembleInstruction(KrkChunk * chunk, size_t offset);
|
||||
extern void krk_disassembleChunk(FILE * f, KrkFunction * func, const char * name);
|
||||
extern size_t krk_disassembleInstruction(FILE * f, KrkFunction * func, size_t offset);
|
||||
extern size_t krk_lineNumber(KrkChunk * chunk, size_t offset);
|
||||
|
61
src/dis.c
Normal file
61
src/dis.c
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Currently just dis().
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../vm.h"
|
||||
#include "../value.h"
|
||||
#include "../object.h"
|
||||
#include "../debug.h"
|
||||
|
||||
#define S(c) (krk_copyString(c,sizeof(c)-1))
|
||||
|
||||
/**
|
||||
* dis.dis(object)
|
||||
*/
|
||||
static KrkValue krk_dis(int argc, KrkValue argv[]) {
|
||||
if (argc < 1) {
|
||||
krk_runtimeError(vm.exceptions.argumentError, "dis() takes ");
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLY
|
||||
if (IS_CLOSURE(argv[0])) {
|
||||
KrkFunction * func = AS_CLOSURE(argv[0])->function;
|
||||
krk_disassembleChunk(stdout, func, func->name ? func->name->chars : "(unnamed)");
|
||||
} else if (IS_BOUND_METHOD(argv[0])) {
|
||||
if (AS_BOUND_METHOD(argv[0])->method->type == OBJ_CLOSURE) {
|
||||
KrkFunction * func = ((KrkClosure*)AS_BOUND_METHOD(argv[0])->method)->function;
|
||||
const char * methodName = func->name ? func->name->chars : "(unnamed)";
|
||||
const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(argv[0])->receiver);
|
||||
char * tmp = malloc(strlen(methodName) + strlen(typeName) + 2);
|
||||
sprintf(tmp, "%s.%s", typeName, methodName);
|
||||
krk_disassembleChunk(stdout, func, tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions.typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver));
|
||||
}
|
||||
} else if (IS_CLASS(argv[0])) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "todo: class disassembly");
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions.typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0]));
|
||||
}
|
||||
#else
|
||||
krk_runtimeError(vm.exceptions.typeError, "Kuroko was built with debug methods stripped; disassembly is not available.");
|
||||
#endif
|
||||
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
KrkValue krk_module_onload_dis(void) {
|
||||
KrkInstance * module = krk_newInstance(vm.objectClass);
|
||||
krk_push(OBJECT_VAL(module));
|
||||
krk_defineNative(&module->fields, "dis", krk_dis);
|
||||
assert(AS_INSTANCE(krk_pop()) == module);
|
||||
return OBJECT_VAL(module);
|
||||
}
|
||||
|
4
vm.c
4
vm.c
@ -971,8 +971,10 @@ _finishArg:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ENABLE_TRACING
|
||||
dumpStack(&vm.frames[vm.frameCount-1]);
|
||||
krk_runtimeError(vm.exceptions.typeError, "Internal error? Item at index %d from %d found is %s", i*2, found, krk_typeName(startOfExtras[i*2]));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -2957,7 +2959,7 @@ static KrkValue run() {
|
||||
#ifdef ENABLE_TRACING
|
||||
if (vm.flags & KRK_ENABLE_TRACING) {
|
||||
dumpStack(frame);
|
||||
krk_disassembleInstruction(&frame->closure->function->chunk,
|
||||
krk_disassembleInstruction(stderr, frame->closure->function,
|
||||
(size_t)(frame->ip - frame->closure->function->chunk.code));
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user