1
0
forked from Mirror/wren
Files
wren/src/wren_debug.c
Bob Nystrom f3a1f7e677 Fibers!
Still have some edge cases to implement but the basics are in
place and working now.
2014-01-12 11:02:07 -08:00

361 lines
8.2 KiB
C

#include <stdio.h>
#include "wren_debug.h"
void wrenDebugPrintStackTrace(WrenVM* vm, ObjFiber* fiber, Value error)
{
// TODO: Handle error not being a string!
const char* errorMessage = AS_CSTRING(error);
fprintf(stderr, "%s\n", errorMessage);
for (int i = fiber->numFrames - 1; i >= 0; i--)
{
CallFrame* frame = &fiber->frames[i];
ObjFn* fn;
if (frame->fn->type == OBJ_FN)
{
fn = (ObjFn*)frame->fn;
}
else
{
fn = ((ObjClosure*)frame->fn)->fn;
}
// - 1 because IP has advanced past the instruction that it just executed.
int line = fn->debug->sourceLines[frame->ip - fn->bytecode - 1];
fprintf(stderr, "[%s line %d] in %s\n",
fn->debug->sourcePath->value, line, fn->debug->name);
}
}
static void printLine(ObjFn* fn, int i, int* lastLine)
{
int line = fn->debug->sourceLines[i];
if (lastLine == NULL || *lastLine != line)
{
printf("%4d:", line);
if (lastLine != NULL) *lastLine = line;
}
else
{
printf(" ");
}
}
static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
{
int start = i;
uint8_t* bytecode = fn->bytecode;
Code code = bytecode[i++];
printLine(fn, i, lastLine);
printf(" %04d ", i);
#define PRINT_ARG \
printLine(fn, i, lastLine); printf(" %04d ", ++i); printf
// TODO: Come up with a cleaner way of displaying 16-bit args.
switch (code)
{
case CODE_CONSTANT:
{
int constant = (bytecode[i] << 8) | bytecode[i + 1];
printf("CONSTANT '");
wrenPrintValue(fn->constants[constant]);
printf("'\n");
PRINT_ARG("constant %d\n", constant);
PRINT_ARG("\n");
break;
}
case CODE_NULL: printf("NULL\n"); break;
case CODE_FALSE: printf("FALSE\n"); break;
case CODE_TRUE: printf("TRUE\n"); break;
case CODE_LOAD_LOCAL:
{
int local = bytecode[i];
printf("LOAD_LOCAL %d\n", local);
PRINT_ARG("local %d\n", local);
break;
}
case CODE_STORE_LOCAL:
{
int local = bytecode[i];
printf("STORE_LOCAL %d\n", local);
PRINT_ARG("local %d\n", local);
break;
}
case CODE_LOAD_UPVALUE:
{
int upvalue = bytecode[i];
printf("LOAD_UPVALUE %d\n", upvalue);
PRINT_ARG("upvalue %d\n", upvalue);
break;
}
case CODE_STORE_UPVALUE:
{
int upvalue = bytecode[i];
printf("STORE_UPVALUE %d\n", upvalue);
PRINT_ARG("upvalue %d\n", upvalue);
break;
}
case CODE_LOAD_GLOBAL:
{
int global = bytecode[i];
printf("LOAD_GLOBAL \"%s\"\n", vm->globalSymbols.names.data[global]);
PRINT_ARG("global %d\n", global);
break;
}
case CODE_STORE_GLOBAL:
{
int global = bytecode[i];
printf("STORE_GLOBAL \"%s\"\n", vm->globalSymbols.names.data[global]);
PRINT_ARG("global %d\n", global);
break;
}
case CODE_LOAD_FIELD_THIS:
{
int field = bytecode[i];
printf("LOAD_FIELD_THIS %d\n", field);
PRINT_ARG("field %d\n", field);
break;
}
case CODE_STORE_FIELD_THIS:
{
int field = bytecode[i];
printf("STORE_FIELD_THIS %d\n", field);
PRINT_ARG("field %d\n", field);
break;
}
case CODE_LOAD_FIELD:
{
int field = bytecode[i];
printf("LOAD_FIELD %d\n", field);
PRINT_ARG("field %d\n", field);
break;
}
case CODE_STORE_FIELD:
{
int field = bytecode[i];
printf("STORE_FIELD %d\n", field);
PRINT_ARG("field %d\n", field);
break;
}
case CODE_POP: printf("POP\n"); break;
case CODE_CALL_0:
case CODE_CALL_1:
case CODE_CALL_2:
case CODE_CALL_3:
case CODE_CALL_4:
case CODE_CALL_5:
case CODE_CALL_6:
case CODE_CALL_7:
case CODE_CALL_8:
case CODE_CALL_9:
case CODE_CALL_10:
case CODE_CALL_11:
case CODE_CALL_12:
case CODE_CALL_13:
case CODE_CALL_14:
case CODE_CALL_15:
case CODE_CALL_16:
{
int numArgs = bytecode[i - 1] - CODE_CALL_0;
int symbol = (bytecode[i] << 8) | bytecode[i + 1];
printf("CALL_%d \"%s\"\n", numArgs, vm->methods.names.data[symbol]);
PRINT_ARG("symbol %d\n", symbol);
PRINT_ARG("\n");
break;
}
case CODE_SUPER_0:
case CODE_SUPER_1:
case CODE_SUPER_2:
case CODE_SUPER_3:
case CODE_SUPER_4:
case CODE_SUPER_5:
case CODE_SUPER_6:
case CODE_SUPER_7:
case CODE_SUPER_8:
case CODE_SUPER_9:
case CODE_SUPER_10:
case CODE_SUPER_11:
case CODE_SUPER_12:
case CODE_SUPER_13:
case CODE_SUPER_14:
case CODE_SUPER_15:
case CODE_SUPER_16:
{
int numArgs = bytecode[i - 1] - CODE_SUPER_0;
int symbol = (bytecode[i] << 8) | bytecode[i + 1];
printf("SUPER_%d \"%s\"\n", numArgs, vm->methods.names.data[symbol]);
PRINT_ARG("symbol %d\n", symbol);
PRINT_ARG("\n");
break;
}
case CODE_JUMP:
{
int offset = bytecode[i];
printf("JUMP %d\n", offset);
PRINT_ARG("offset %d\n", offset);
break;
}
case CODE_LOOP:
{
int offset = bytecode[i];
printf("LOOP %d\n", offset);
PRINT_ARG("offset -%d\n", offset);
break;
}
case CODE_JUMP_IF:
{
int offset = bytecode[i];
printf("JUMP_IF %d\n", offset);
PRINT_ARG("offset %d\n", offset);
break;
}
case CODE_AND:
{
int offset = bytecode[i];
printf("AND %d\n", offset);
PRINT_ARG("offset %d\n", offset);
break;
}
case CODE_OR:
{
int offset = bytecode[i];
printf("OR %d\n", offset);
PRINT_ARG("offset %d\n", offset);
break;
}
case CODE_IS: printf("CODE_IS\n"); break;
case CODE_CLOSE_UPVALUE: printf("CLOSE_UPVALUE\n"); break;
case CODE_RETURN: printf("CODE_RETURN\n"); break;
case CODE_NEW: printf("CODE_NEW\n"); break;
case CODE_LIST:
{
int count = bytecode[i];
printf("LIST\n");
PRINT_ARG("count %d\n", count);
break;
}
case CODE_CLOSURE:
{
int constant = (bytecode[i] << 8) | bytecode[i + 1];
printf("CLOSURE ");
wrenPrintValue(fn->constants[constant]);
printf("\n");
PRINT_ARG("constant %d\n", constant);
PRINT_ARG("\n");
ObjFn* loadedFn = AS_FN(fn->constants[constant]);
for (int j = 0; j < loadedFn->numUpvalues; j++)
{
int isLocal = bytecode[i];
PRINT_ARG("upvalue %d isLocal %d\n", j, isLocal);
int index = bytecode[i];
PRINT_ARG("upvalue %d index %d\n", j, index);
}
break;
}
case CODE_CLASS:
{
int numFields = bytecode[i];
printf("CLASS\n");
PRINT_ARG("num fields %d\n", numFields);
break;
}
case CODE_SUBCLASS:
{
int numFields = bytecode[i];
printf("SUBCLASS\n");
PRINT_ARG("num fields %d\n", numFields);
break;
}
case CODE_METHOD_INSTANCE:
{
int symbol = (bytecode[i] << 8) | bytecode[i + 1];
printf("METHOD_INSTANCE \"%s\"\n", vm->methods.names.data[symbol]);
PRINT_ARG("symbol %d\n", symbol);
PRINT_ARG("\n");
break;
}
case CODE_METHOD_STATIC:
{
int symbol = (bytecode[i] << 8) | bytecode[i + 1];
printf("METHOD_STATIC \"%s\"\n", vm->methods.names.data[symbol]);
PRINT_ARG("symbol %d\n", symbol);
PRINT_ARG("\n");
break;
}
case CODE_END:
printf("CODE_END\n");
break;
default:
printf("UKNOWN! [%d]\n", bytecode[i - 1]);
break;
}
// Return how many bytes this instruction takes, or -1 if it's an END.
if (code == CODE_END) return -1;
return i - start;
}
int wrenDebugPrintInstruction(WrenVM* vm, ObjFn* fn, int i)
{
return debugPrintInstruction(vm, fn, i, NULL);
}
void wrenDebugPrintCode(WrenVM* vm, ObjFn* fn)
{
printf("%s: %s\n", fn->debug->sourcePath->value, fn->debug->name);
int i = 0;
int lastLine = -1;
for (;;)
{
int offset = debugPrintInstruction(vm, fn, i, &lastLine);
if (offset == -1) break;
i += offset;
}
printf("\n");
}
void wrenDebugPrintStack(ObjFiber* fiber)
{
printf("(fiber %p) ", fiber);
for (int i = 0; i < fiber->stackSize; i++)
{
wrenPrintValue(fiber->stack[i]);
printf(" | ");
}
printf("\n");
}