Skip to content

Commit

Permalink
lam_hooks becomes abstract class.
Browse files Browse the repository at this point in the history
Add skeleton of mem leak debugging.
  • Loading branch information
CaptainZippy committed Aug 26, 2024
1 parent 7726075 commit a58e581
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 21 deletions.
29 changes: 17 additions & 12 deletions src/littlelambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,26 @@ static bool _try_parse_as(const char* start, const char* end, T& out, V... v) {
return false;
}

lam_hooks::~lam_hooks() = default;

struct lam_vm {
ugc_t gc;
lam_hooks hooks;
lam_env* root;
std::unordered_map<std::string, lam_value> imports;
ugc_t gc{};
lam_hooks* hooks{};
lam_env* root{};
std::unordered_map<std::string, lam_value> imports{};
struct {
lam_u64 alloc_count;
lam_u64 free_count;
lam_u64 gc_iter_count;
lam_u64 alloc_count{};
lam_u64 free_count{};
lam_u64 gc_iter_count{};
} gc_stats;
};

// Allocate and zero "sizeof(T) + extra" bytes
// Register T with the garbage collector
template <typename T>
static T* callocPlus(lam_vm* vm, size_t extra) {
void* p = calloc(1, sizeof(T) + extra);
void* p = vm->hooks->mem_alloc(sizeof(T) + extra);
memset(p, 0, sizeof(T) + extra);
auto o = reinterpret_cast<T*>(p);
ugc_register(&vm->gc, &o->header);
vm->gc_stats.alloc_count += 1;
Expand Down Expand Up @@ -351,7 +354,7 @@ struct lam_env_impl : lam_env {

static lam_env* lam_new_env(lam_vm* vm, lam_env* parent, const char* name) {
assert(parent == nullptr || vm == static_cast<lam_env_impl*>(parent)->vm);
auto* d = callocPlus<lam_env_impl>(vm, sizeof(lam_env_impl));
auto* d = callocPlus<lam_env_impl>(vm, 0);
return new (d) lam_env_impl(vm, parent, name);
}

Expand Down Expand Up @@ -744,7 +747,7 @@ static lam_env* lam_make_env_builtin(lam_vm* vm) {
auto modname = a[0].as_symbol();
auto it = env->vm->imports.find(modname->val());
if (it == env->vm->imports.end()) {
lam_result result = env->vm->hooks.import(env->vm, modname->val());
lam_result result = env->vm->hooks->import(env->vm, modname->val());
if (result.code == 0) {
return result.value;
} else {
Expand Down Expand Up @@ -1221,15 +1224,17 @@ lam_result lam_vm_import(lam_vm* vm, const char* name, const void* data, size_t
}

lam_vm* lam_vm_new(lam_hooks* hooks) {
void* addr = hooks->alloc(sizeof(lam_vm));
hooks->init();
void* addr = hooks->mem_alloc(sizeof(lam_vm));
lam_vm* vm = new (addr) lam_vm;
ugc_init(&vm->gc, &lam_ugc_visit, &lam_ugc_free);
vm->gc.userdata = vm;
memcpy(&vm->hooks, hooks, sizeof(lam_hooks));
vm->hooks = hooks;
vm->root = lam_make_env_builtin(vm);
return vm;
}

void lam_vm_delete(lam_vm* vm) {
vm->hooks->quit();
// TODO
}
13 changes: 6 additions & 7 deletions src/littlelambda.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,12 @@ void lam_print(lam_value val, const char* end = nullptr);

/// Functionality provided by external systems.
struct lam_hooks {
using alloc_func = void*(size_t);
using free_func = void(void*);
using import_func = lam_result(lam_vm* vm, const char* modname);

alloc_func* alloc;
free_func* free;
import_func* import;
virtual ~lam_hooks();
virtual void* mem_alloc(size_t size) =0;
virtual void mem_free(void* addr) = 0;
virtual void init() = 0;
virtual void quit() = 0;
virtual lam_result import(lam_vm* vm, const char* modname) = 0;
};

/// Initialize a vm.
Expand Down
48 changes: 46 additions & 2 deletions src/test.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <string>
#include <format>
#include <string>
#include <unordered_map>
#include <vector>
#if __cpp_lib_stacktrace >= 202011L
#include <stacktrace> // C++23 feature
#else
namespace std {
struct stacktrace_entry {
std::string description() { return ""; }
};
struct stacktrace {
static stacktrace current() { return {}; }
struct stacktrace_entry* begin() { return nullptr; }
stacktrace_entry* end() { return nullptr; }
};
} // namespace std
#endif
#include "littlelambda.h"

static int slurp_file(const char* path, std::vector<char>& buf) {
Expand Down Expand Up @@ -63,10 +77,40 @@ static lam_result import_impl(lam_vm* vm, const char* modname) {
return lam_result::fail(1, "Import failed");
}

struct DebugHooks : lam_hooks {
DebugHooks() {}

void* mem_alloc(size_t size) override {
void* p = malloc(size);
assert(allocs.find(p) == allocs.end());
allocs[p] = std::stacktrace::current();
return p;
}
void mem_free(void* addr) override {
auto it = allocs.find(addr);
assert(it != allocs.end());
allocs.erase(it);
free(addr);
}
void init() override {
//assert(allocs.empty());
allocs.clear();
}
void quit() override {
/*for (auto it : allocs) {
printf("%p\n", it.first);
for (auto p : it.second) {
printf("\t%s\n", p.description().c_str());
}
}*/
}
lam_result import(lam_vm* vm, const char* modname) override { return import_impl(vm, modname); }

std::unordered_map<void*, std::stacktrace> allocs;
};

int main() {
lam_hooks hooks = {&malloc, &free, &import_impl};
DebugHooks hooks;
if (1) {
lam_vm* vm = lam_vm_new(&hooks);
read_and_eval(vm, "module.ll");
Expand Down

0 comments on commit a58e581

Please sign in to comment.