improve disassembly somewhat and add dis module

This commit is contained in:
K. Lange 2021-01-05 15:33:33 +09:00
parent 04391ebbaa
commit ab158260f7
5 changed files with 118 additions and 35 deletions

View File

@ -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
View File

@ -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;
}

View File

@ -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
View 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
View File

@ -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