From 159501168ca794c96da3428a8041884de04f9aea Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Thu, 25 Apr 2024 03:17:03 +0530 Subject: [PATCH] Split vm/runtime.c into two files struct.c is used for the general construction, inspection and deletion of the virtual machine structure (vm_t). runtime defines the execution routines, error enum, lookup tables, etc. --- Makefile | 2 +- vm/main.c | 4 +- vm/runtime.c | 246 ----------------------------------------------- vm/runtime.h | 46 +-------- vm/struct.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++ vm/struct.h | 69 ++++++++++++++ 6 files changed, 338 insertions(+), 291 deletions(-) create mode 100644 vm/struct.c create mode 100644 vm/struct.h diff --git a/Makefile b/Makefile index 121b63a..45468aa 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ LIB_OBJECTS:=$(LIB_CODE:$(LIB_SRC)/%.c=$(LIB_DIST)/%.o) ## VM setup VM_DIST=$(DIST)/vm VM_SRC=vm -VM_CODE:=$(addprefix $(VM_SRC)/, runtime.c) +VM_CODE:=$(addprefix $(VM_SRC)/, struct.c runtime.c) VM_OBJECTS:=$(VM_CODE:$(VM_SRC)/%.c=$(VM_DIST)/%.o) VM_OUT=$(DIST)/avm.out diff --git a/vm/main.c b/vm/main.c index f014325..13c0b1e 100644 --- a/vm/main.c +++ b/vm/main.c @@ -14,9 +14,11 @@ #include #include -#include "./runtime.h" #include +#include "./runtime.h" +#include "./struct.h" + void usage(const char *program_name, FILE *out) { fprintf(out, diff --git a/vm/runtime.c b/vm/runtime.c index 44ef25d..9542176 100644 --- a/vm/runtime.c +++ b/vm/runtime.c @@ -324,252 +324,6 @@ err_t vm_execute_all(vm_t *vm) return err; } -void vm_load_stack(vm_t *vm, byte *bytes, size_t size) -{ - vm->stack.data = bytes; - vm->stack.max = size; - vm->stack.ptr = 0; -} - -void vm_load_program(vm_t *vm, prog_t *program) -{ - vm->program.ptr = 0; - vm->program.data = program; -} - -void vm_load_registers(vm_t *vm, registers_t registers) -{ - vm->registers = registers; -} - -void vm_load_heap(vm_t *vm, heap_t heap) -{ - vm->heap = heap; -} - -void vm_load_call_stack(vm_t *vm, word *buffer, size_t size) -{ - vm->call_stack = - (struct CallStack){.address_pointers = buffer, .ptr = 0, .max = size}; -} - -void vm_stop(vm_t *vm) -{ -#if VERBOSE >= 1 - bool leaks = false; - printf("[" TERM_YELLOW "DATA" TERM_RESET "]: Checking for leaks...\n"); - if (vm->call_stack.ptr > 0) - { - leaks = true; - printf("\t[" TERM_RED "DATA" TERM_RESET "]: Call stack at %lu\n\t[" TERM_RED - "DATA" TERM_RESET "]\n\t[" TERM_RED "DATA" TERM_RESET "]: Call " - "stack trace:", - vm->call_stack.ptr); - for (size_t i = vm->call_stack.ptr; i > 0; --i) - { - word w = vm->call_stack.address_pointers[i - 1]; - printf("\t\t%lu: %lX", vm->call_stack.ptr - i, w); - if (i != 1) - printf(", "); - printf("\n"); - } - } - if (vm->heap.pages > 0) - { - leaks = true; - page_t *cur = vm->heap.beg; - size_t capacities[vm->heap.pages], total_capacity = 0; - for (size_t i = 0; i < vm->heap.pages; ++i) - { - capacities[i] = cur->available; - total_capacity += capacities[i]; - } - printf("\t[" TERM_RED "DATA" TERM_RESET - "]: Heap: %luB (over %lu %s) not reclaimed\n", - total_capacity, vm->heap.pages, - vm->heap.pages == 1 ? "page" : "pages"); - for (size_t i = 0; i < vm->heap.pages; i++) - printf("\t\t[%lu]: %luB lost\n", i, capacities[i]); - } - if (vm->stack.ptr > 0) - { - leaks = true; - printf("\t[" TERM_RED "DATA" TERM_RESET "]: Stack: %luB not reclaimed\n", - vm->stack.ptr); - } - if (leaks) - printf("[" TERM_RED "DATA" TERM_RESET "]: Leaks found\n"); - else - printf("[" TERM_GREEN "DATA" TERM_RESET "]: No leaks found\n"); -#endif - - free(vm->registers.data); - free(vm->program.data); - free(vm->stack.data); - heap_stop(&vm->heap); - free(vm->call_stack.address_pointers); - - vm->registers = (registers_t){0}; - vm->program = (struct Program){0}; - vm->stack = (struct Stack){0}; - vm->heap = (heap_t){0}; -} - -void vm_print_registers(vm_t *vm, FILE *fp) -{ - registers_t reg = vm->registers; - fprintf( - fp, - "Registers.used = %luB/%luH/%luW\nRegisters.available = %luB/%luH/%luW\n", - vm->registers.used, vm->registers.used / HWORD_SIZE, - vm->registers.used / WORD_SIZE, vm->registers.available, - vm->registers.available / HWORD_SIZE, - vm->registers.available / WORD_SIZE); - fprintf(fp, "Registers.reg = ["); - for (size_t i = 0; i < ceil((long double)reg.used / WORD_SIZE); ++i) - { - fprintf(fp, "{%lu:%lX}", i, VM_NTH_REGISTER(reg, i)); - if (i != reg.used - 1) - fprintf(fp, ", "); - } - fprintf(fp, "]\n"); -} - -void vm_print_stack(vm_t *vm, FILE *fp) -{ - struct Stack stack = vm->stack; - fprintf(fp, "Stack.max = %lu\nStack.ptr = %lu\nStack.data = [", stack.max, - stack.ptr); - if (stack.ptr == 0) - { - fprintf(fp, "]\n"); - return; - } - printf("\n"); - for (size_t i = stack.ptr; i > 0; --i) - { - byte b = stack.data[i - 1]; - fprintf(fp, "\t%lu: %X", stack.ptr - i, b); - if (i != 1) - fprintf(fp, ", "); - fprintf(fp, "\n"); - } - fprintf(fp, "]\n"); -} - -void vm_print_program(vm_t *vm, FILE *fp) -{ - struct Program program = vm->program; - const size_t count = program.data->count; - fprintf(fp, - "Program.max = %lu\nProgram.ptr = " - "%lu\nProgram.instructions = [\n", - count, program.ptr); - size_t beg = 0; - if (program.ptr >= VM_PRINT_PROGRAM_EXCERPT) - { - fprintf(fp, "\t...\n"); - beg = program.ptr - VM_PRINT_PROGRAM_EXCERPT; - } - else - beg = 0; - size_t end = MIN(program.ptr + VM_PRINT_PROGRAM_EXCERPT, count); - for (size_t i = beg; i < end; ++i) - { - fprintf(fp, "\t%lu: ", i); - inst_print(program.data->instructions[i], fp); - if (i == program.ptr) - fprintf(fp, " <---"); - fprintf(fp, "\n"); - } - if (end != count) - fprintf(fp, "\t...\n"); - fprintf(fp, "]\n"); -} - -void vm_print_heap(vm_t *vm, FILE *fp) -{ - heap_t heap = vm->heap; - fprintf(fp, "Heap.pages = %lu\nHeap.data = [", heap.pages); - if (heap.pages == 0) - { - fprintf(fp, "]\n"); - return; - } - page_t *cur = heap.beg; - fprintf(fp, "\n"); - for (size_t i = 0; i < heap.pages; ++i) - { - fprintf(fp, "\t[%lu]@%p: ", i, cur); - if (!cur) - fprintf(fp, "\n"); - else - { - fprintf(fp, "{"); - for (size_t j = 0; j < cur->available; ++j) - { - if ((j % 8) == 0) - fprintf(fp, "\n\t\t"); - fprintf(fp, "%x", cur->data[j]); - if (j != cur->available - 1) - fprintf(fp, ",\t"); - } - fprintf(fp, "\n\t}\n"); - cur = cur->next; - } - } - fprintf(fp, "]\n"); -} - -void vm_print_call_stack(vm_t *vm, FILE *fp) -{ - struct CallStack cs = vm->call_stack; - fprintf(fp, "CallStack.max = %lu\nCallStack.ptr = %lu\nCallStack.data = [", - cs.max, cs.ptr); - if (cs.ptr == 0) - { - fprintf(fp, "]\n"); - return; - } - printf("\n"); - for (size_t i = cs.ptr; i > 0; --i) - { - word w = cs.address_pointers[i - 1]; - fprintf(fp, "\t%lu: %lX", cs.ptr - i, w); - if (i != 1) - fprintf(fp, ", "); - fprintf(fp, "\n"); - } - fprintf(fp, "]\n"); -} - -void vm_print_all(vm_t *vm, FILE *fp) -{ - fputs("----------------------------------------------------------------------" - "----------\n", - fp); - vm_print_program(vm, fp); - fputs("----------------------------------------------------------------------" - "----------\n", - fp); - vm_print_call_stack(vm, fp); - fputs("----------------------------------------------------------------------" - "----------\n", - fp); - vm_print_heap(vm, fp); - fputs("----------------------------------------------------------------------" - "----------\n", - fp); - vm_print_registers(vm, fp); - fputs("----------------------------------------------------------------------" - "----------\n", - fp); - vm_print_stack(vm, fp); - fputs("----------------------------------------------------------------------" - "----------\n", - fp); -} - err_t vm_jump(vm_t *vm, word w) { if (w >= vm->program.data->count) diff --git a/vm/runtime.h b/vm/runtime.h index c6b6669..555d407 100644 --- a/vm/runtime.h +++ b/vm/runtime.h @@ -16,9 +16,11 @@ #include #include -#include #include +#include "./runtime.h" +#include "./struct.h" + typedef enum { ERR_OK = 0, @@ -38,51 +40,9 @@ typedef enum const char *err_as_cstr(err_t); -typedef darr_t registers_t; -#define VM_NTH_REGISTER(REGISTERS, N) (((word *)((REGISTERS).data))[N]) -#define VM_REGISTERS_AVAILABLE(REGISTERS) (((REGISTERS).available) / WORD_SIZE) - -typedef struct -{ - registers_t registers; - struct Stack - { - byte *data; - size_t ptr, max; - } stack; - heap_t heap; - struct Program - { - prog_t *data; - word ptr; - } program; - struct CallStack - { - word *address_pointers; - size_t ptr, max; - } call_stack; -} vm_t; - err_t vm_execute(vm_t *); err_t vm_execute_all(vm_t *); -void vm_load_stack(vm_t *, byte *, size_t); -void vm_load_registers(vm_t *, registers_t); -void vm_load_heap(vm_t *, heap_t); -void vm_load_program(vm_t *, prog_t *); -void vm_load_call_stack(vm_t *, word *, size_t); -void vm_stop(vm_t *); - -// Print routines -#define VM_PRINT_PROGRAM_EXCERPT 5 -void vm_print_registers(vm_t *, FILE *); -void vm_print_stack(vm_t *, FILE *); -void vm_print_program(vm_t *, FILE *); -void vm_print_heap(vm_t *, FILE *); -void vm_print_call_stack(vm_t *, FILE *); -void vm_print_all(vm_t *, FILE *); - -// Execution routines err_t vm_jump(vm_t *, word); err_t vm_pop_byte(vm_t *, data_t *); diff --git a/vm/struct.c b/vm/struct.c new file mode 100644 index 0000000..6e01b9a --- /dev/null +++ b/vm/struct.c @@ -0,0 +1,262 @@ +/* Copyright (C) 2024 Aryadev Chavali + + * You may distribute and modify this code under the terms of the + * GPLv2 license. You should have received a copy of the GPLv2 + * license with this file. If not, please write to: + * aryadev@aryadevchavali.com. + + * Created: 2024-04-25 + * Author: Aryadev Chavali + * Description: Virtual machine data structures and some helpers + */ + +#include +#include + +#include "./struct.h" + +void vm_load_stack(vm_t *vm, byte *bytes, size_t size) +{ + vm->stack.data = bytes; + vm->stack.max = size; + vm->stack.ptr = 0; +} + +void vm_load_program(vm_t *vm, prog_t *program) +{ + vm->program.ptr = 0; + vm->program.data = program; +} + +void vm_load_registers(vm_t *vm, registers_t registers) +{ + vm->registers = registers; +} + +void vm_load_heap(vm_t *vm, heap_t heap) +{ + vm->heap = heap; +} + +void vm_load_call_stack(vm_t *vm, word *buffer, size_t size) +{ + vm->call_stack = + (struct CallStack){.address_pointers = buffer, .ptr = 0, .max = size}; +} + +void vm_stop(vm_t *vm) +{ +#if VERBOSE >= 1 + bool leaks = false; + printf("[" TERM_YELLOW "DATA" TERM_RESET "]: Checking for leaks...\n"); + if (vm->call_stack.ptr > 0) + { + leaks = true; + printf("\t[" TERM_RED "DATA" TERM_RESET "]: Call stack at %lu\n\t[" TERM_RED + "DATA" TERM_RESET "]\n\t[" TERM_RED "DATA" TERM_RESET "]: Call " + "stack trace:", + vm->call_stack.ptr); + for (size_t i = vm->call_stack.ptr; i > 0; --i) + { + word w = vm->call_stack.address_pointers[i - 1]; + printf("\t\t%lu: %lX", vm->call_stack.ptr - i, w); + if (i != 1) + printf(", "); + printf("\n"); + } + } + if (vm->heap.pages > 0) + { + leaks = true; + page_t *cur = vm->heap.beg; + size_t capacities[vm->heap.pages], total_capacity = 0; + for (size_t i = 0; i < vm->heap.pages; ++i) + { + capacities[i] = cur->available; + total_capacity += capacities[i]; + } + printf("\t[" TERM_RED "DATA" TERM_RESET + "]: Heap: %luB (over %lu %s) not reclaimed\n", + total_capacity, vm->heap.pages, + vm->heap.pages == 1 ? "page" : "pages"); + for (size_t i = 0; i < vm->heap.pages; i++) + printf("\t\t[%lu]: %luB lost\n", i, capacities[i]); + } + if (vm->stack.ptr > 0) + { + leaks = true; + printf("\t[" TERM_RED "DATA" TERM_RESET "]: Stack: %luB not reclaimed\n", + vm->stack.ptr); + } + if (leaks) + printf("[" TERM_RED "DATA" TERM_RESET "]: Leaks found\n"); + else + printf("[" TERM_GREEN "DATA" TERM_RESET "]: No leaks found\n"); +#endif + + free(vm->registers.data); + free(vm->program.data); + free(vm->stack.data); + heap_stop(&vm->heap); + free(vm->call_stack.address_pointers); + + vm->registers = (registers_t){0}; + vm->program = (struct Program){0}; + vm->stack = (struct Stack){0}; + vm->heap = (heap_t){0}; +} + +void vm_print_registers(vm_t *vm, FILE *fp) +{ + registers_t reg = vm->registers; + fprintf( + fp, + "Registers.used = %luB/%luH/%luW\nRegisters.available = %luB/%luH/%luW\n", + vm->registers.used, vm->registers.used / HWORD_SIZE, + vm->registers.used / WORD_SIZE, vm->registers.available, + vm->registers.available / HWORD_SIZE, + vm->registers.available / WORD_SIZE); + fprintf(fp, "Registers.reg = ["); + for (size_t i = 0; i < ceil((long double)reg.used / WORD_SIZE); ++i) + { + fprintf(fp, "{%lu:%lX}", i, VM_NTH_REGISTER(reg, i)); + if (i != reg.used - 1) + fprintf(fp, ", "); + } + fprintf(fp, "]\n"); +} + +void vm_print_stack(vm_t *vm, FILE *fp) +{ + struct Stack stack = vm->stack; + fprintf(fp, "Stack.max = %lu\nStack.ptr = %lu\nStack.data = [", stack.max, + stack.ptr); + if (stack.ptr == 0) + { + fprintf(fp, "]\n"); + return; + } + printf("\n"); + for (size_t i = stack.ptr; i > 0; --i) + { + byte b = stack.data[i - 1]; + fprintf(fp, "\t%lu: %X", stack.ptr - i, b); + if (i != 1) + fprintf(fp, ", "); + fprintf(fp, "\n"); + } + fprintf(fp, "]\n"); +} + +void vm_print_program(vm_t *vm, FILE *fp) +{ + struct Program program = vm->program; + const size_t count = program.data->count; + fprintf(fp, + "Program.max = %lu\nProgram.ptr = " + "%lu\nProgram.instructions = [\n", + count, program.ptr); + size_t beg = 0; + if (program.ptr >= VM_PRINT_PROGRAM_EXCERPT) + { + fprintf(fp, "\t...\n"); + beg = program.ptr - VM_PRINT_PROGRAM_EXCERPT; + } + else + beg = 0; + size_t end = MIN(program.ptr + VM_PRINT_PROGRAM_EXCERPT, count); + for (size_t i = beg; i < end; ++i) + { + fprintf(fp, "\t%lu: ", i); + inst_print(program.data->instructions[i], fp); + if (i == program.ptr) + fprintf(fp, " <---"); + fprintf(fp, "\n"); + } + if (end != count) + fprintf(fp, "\t...\n"); + fprintf(fp, "]\n"); +} + +void vm_print_heap(vm_t *vm, FILE *fp) +{ + heap_t heap = vm->heap; + fprintf(fp, "Heap.pages = %lu\nHeap.data = [", heap.pages); + if (heap.pages == 0) + { + fprintf(fp, "]\n"); + return; + } + page_t *cur = heap.beg; + fprintf(fp, "\n"); + for (size_t i = 0; i < heap.pages; ++i) + { + fprintf(fp, "\t[%lu]@%p: ", i, cur); + if (!cur) + fprintf(fp, "\n"); + else + { + fprintf(fp, "{"); + for (size_t j = 0; j < cur->available; ++j) + { + if ((j % 8) == 0) + fprintf(fp, "\n\t\t"); + fprintf(fp, "%x", cur->data[j]); + if (j != cur->available - 1) + fprintf(fp, ",\t"); + } + fprintf(fp, "\n\t}\n"); + cur = cur->next; + } + } + fprintf(fp, "]\n"); +} + +void vm_print_call_stack(vm_t *vm, FILE *fp) +{ + struct CallStack cs = vm->call_stack; + fprintf(fp, "CallStack.max = %lu\nCallStack.ptr = %lu\nCallStack.data = [", + cs.max, cs.ptr); + if (cs.ptr == 0) + { + fprintf(fp, "]\n"); + return; + } + printf("\n"); + for (size_t i = cs.ptr; i > 0; --i) + { + word w = cs.address_pointers[i - 1]; + fprintf(fp, "\t%lu: %lX", cs.ptr - i, w); + if (i != 1) + fprintf(fp, ", "); + fprintf(fp, "\n"); + } + fprintf(fp, "]\n"); +} + +void vm_print_all(vm_t *vm, FILE *fp) +{ + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_program(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_call_stack(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_heap(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_registers(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_stack(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); +} diff --git a/vm/struct.h b/vm/struct.h new file mode 100644 index 0000000..47f8a55 --- /dev/null +++ b/vm/struct.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2024 Aryadev Chavali + + * You may distribute and modify this code under the terms of the + * GPLv2 license. You should have received a copy of the GPLv2 + * license with this file. If not, please write to: + * aryadev@aryadevchavali.com. + + * Created: 2024-04-25 + * Author: Aryadev Chavali + * Description: Virtual machine data structures and some helpers + */ + +#ifndef STRUCT_H +#define STRUCT_H + +#include +#include +#include + +typedef darr_t registers_t; +#define VM_NTH_REGISTER(REGISTERS, N) (((word *)((REGISTERS).data))[N]) +#define VM_REGISTERS_AVAILABLE(REGISTERS) (((REGISTERS).available) / WORD_SIZE) + +struct Stack +{ + byte *data; + size_t ptr, max; +}; + +struct Program +{ + prog_t *data; + word ptr; +}; + +struct CallStack +{ + word *address_pointers; + size_t ptr, max; +}; + +typedef struct +{ + registers_t registers; + struct Stack stack; + heap_t heap; + + struct CallStack call_stack; + struct Program program; +} vm_t; + +// Start and stop +void vm_load_stack(vm_t *, byte *, size_t); +void vm_load_registers(vm_t *, registers_t); +void vm_load_heap(vm_t *, heap_t); +void vm_load_program(vm_t *, prog_t *); +void vm_load_call_stack(vm_t *, word *, size_t); +void vm_stop(vm_t *); + +// Printing the VM +#define VM_PRINT_PROGRAM_EXCERPT 5 +void vm_print_registers(vm_t *, FILE *); +void vm_print_stack(vm_t *, FILE *); +void vm_print_program(vm_t *, FILE *); +void vm_print_heap(vm_t *, FILE *); +void vm_print_call_stack(vm_t *, FILE *); +void vm_print_all(vm_t *, FILE *); + +#endif