Debug GC crashes, add (gc-stats), add support for libedit to lisp
diff --git a/share/jmk/jmk.tcl b/share/jmk/jmk.tcl
index 89e775c..ae114dc 100644
--- a/share/jmk/jmk.tcl
+++ b/share/jmk/jmk.tcl
@@ -161,7 +161,7 @@
 				rule $obj $src {}
 			}
 
-			log CC [file normalize $src]
+			log CC $src
 			cc "-c $::first_src -o $::target"
 			puts ""
 		}
@@ -220,7 +220,7 @@
 
 	rule .s.o {} {
 		log ASM $::first_src
-		asm "\$(ASMFLAGS) $::first_src -o $::target"
+		asm "\ $::first_src -o $::target"
 	}
 
 	rule clean {} {
diff --git a/src/libsys/sys.inc b/src/libsys/sys.inc
new file mode 100644
index 0000000..53c2666
--- /dev/null
+++ b/src/libsys/sys.inc
@@ -0,0 +1,2 @@
+%define SYS_GIVEUP 0x100
+%define SYS_INT 0x80
diff --git a/src/lisp/Jmk2 b/src/lisp/Jmk2
index e9f31b2..1f4e6b1 100644
--- a/src/lisp/Jmk2
+++ b/src/lisp/Jmk2
@@ -2,37 +2,39 @@
 
 init lisp
 
-presets 32 debug warn nasm
-cflags -Ivendor/luajit/dynasm -O0
-
-option NO_READLINE 0
-
-srcs main.c lisp.c compiler.c lib/std.c plat/linux.c istream.c gc.c \
-	call_list.s error.c
+# Make this `readline', `edit', or `none'
+option READLINE readline
 
 set lisp_libpath "$::root/lib/lisp"
 
-if {$options(NO_READLINE) == 0} {
-	cflags -lreadline
-} else {
+if {$options(READLINE) == "none"} {
 	cflags -DNO_READLINE
+} else {
+	cflags -L/usr/lib/i386-linux-gnu -l$options(READLINE)
 }
 
-set lua vendor/luajit/src/host/minilua
+presets 32 debug warn nasm
+cflags -Ivendor/luajit/dynasm -O0
+asmflags -felf32
+
+set lua [pwd]/vendor/luajit/src/host/minilua
 
 rule $lua ${lua}.c {
 	log CC $::src
 	cc "$::src -o $::target -lm"
 }
 
-rule compiler.c "compiler.dasc $lua" {
+rule [pwd]/compiler.c "[pwd]/compiler.dasc $lua" {
 	log DYNASM $::first_src
 	shell "$::lua vendor/luajit/dynasm/dynasm.lua -o $::target $::first_src"
 }
 
-rule repl lisp {
+rule repl [pwd]/lisp {
 	log LISP repl
 	shell "LISP_LIBRARY_PATH=$::lisp_libpath ./lisp $::root/lib/lisp/repl/repl.lisp"
 }
 
+srcs main.c lisp.c compiler.c lib/std.c plat/linux.c istream.c gc.c \
+	call_list.s error.c
+
 type executable
diff --git a/src/lisp/gc.c b/src/lisp/gc.c
index 9a9610d..06d8a07 100644
--- a/src/lisp/gc.c
+++ b/src/lisp/gc.c
@@ -4,6 +4,7 @@
 
 value_t *gc_base;
 THREAD_LOCAL static unsigned int gc_mark;
+THREAD_LOCAL static unsigned long gc_runs = 0;
 
 void __attribute__((noinline)) gc_set_base_here()
 {
@@ -20,6 +21,15 @@
 		void *pointer = (void *)(value & ~HEAP_MASK);
 		struct alloc *alloc = pointer - sizeof(struct alloc);
 
+		if (!pointer)
+		{
+			// TODO: Where are these coming from? Maybe this is a C
+			// stack variable that we are interpreting as beign in
+			// Lisp stack space on accident?
+			fprintf(stderr, "lisp:gc:warning: value %x is a null pointer\n", value);
+			return;
+		}
+
 		// Only recursively mark if this hasn't been marked yet. i.e. prevent
 		// marking circular references twice
 		if (alloc->mark != gc_mark)
@@ -64,6 +74,9 @@
 {
 	for (struct alloc *a = first_a; a;)
 	{
+		// fprintf(stderr, "[ GC ] %s %p pool? %d\n", (a->mark != gc_mark) ? "Unmarked" : "Marked", a, pool_alive(a->pool));
+		// printval(alloc_to_value(a), 2);
+		
 		if (pool_alive(a->pool) || a->mark == gc_mark)
 		{
 			// Marked or in living pool
@@ -71,6 +84,8 @@
 		}
 		else
 		{
+			fprintf(stderr, "[ GC ] freeing: ");
+			printval(alloc_to_value(a), 1);
 			// Free and remove from allocation list
 			struct alloc *p = a->prev, *n = a->next;
 			free_aligned(a);
@@ -86,6 +101,20 @@
 	}
 }
 
+struct gc_stats gc_get_stats()
+{
+	struct gc_stats stats = {0};
+
+	stats.gc_runs = gc_runs;
+
+	for (struct alloc *a = first_a; a; a = a->next)
+	{
+		stats.total_allocs++;
+	}
+
+	return stats;
+}
+
 void _do_gc(unsigned int esp, unsigned int ebp)
 {
 	value_t *esp_p = (value_t *)esp,
@@ -94,6 +123,7 @@
 	unsigned int num_marked = 0;
 
 	gc_mark++;
+	gc_runs++;
 
 	// For every stack frame until the base of the stack
 	while (esp_p < gc_base)
diff --git a/src/lisp/gc.h b/src/lisp/gc.h
index 8623cba..789e124 100644
--- a/src/lisp/gc.h
+++ b/src/lisp/gc.h
@@ -5,6 +5,18 @@
 // I hate this
 extern value_t *gc_base;
 
+struct gc_stats
+{
+	// bytes currently used
+	unsigned long bytes_used;
+	// bytes ever freed by the GC
+	unsigned long bytes_freed;
+	// how many total allocations are currently alive
+	unsigned long total_allocs;
+	// how many times has the GC ever been run
+	unsigned long gc_runs;
+};
+
 void gc_set_base_here();
 
 value_t alloc_to_value(struct alloc *a);
@@ -12,3 +24,4 @@
 void _mark(value_t value, unsigned int *marked);
 void _sweep();
 void free_all();
+struct gc_stats gc_get_stats();
diff --git a/src/lisp/lib/std.c b/src/lisp/lib/std.c
index 224c086..1afe993 100644
--- a/src/lisp/lib/std.c
+++ b/src/lisp/lib/std.c
@@ -1,4 +1,5 @@
 #include "std.h"
+#include "../gc.h"
 #include "../plat/plat.h"
 #include <stdlib.h>
 #include <string.h>
@@ -98,7 +99,6 @@
 
 value_t l_read_stdin()
 {
-#ifndef NO_READLINE
 	char *string = read_input_line("lisp> ");
 	if (!string)
 		return nil;
@@ -122,9 +122,6 @@
 	free(string);
 
 	return val;
-#else
-	return nil;
-#endif
 }
 
 value_t l_num_eq(value_t a, value_t b)
@@ -194,6 +191,15 @@
 	return first;
 }
 
+value_t l_gc_stats()
+{
+	struct gc_stats stats = gc_get_stats();
+
+	return cons(intval(stats.total_allocs),
+				cons(intval(stats.gc_runs),
+					 nil));
+}
+
 #define LISP_PREDICATE(name) value_t l_##name(value_t v) { return name(v) ? t : nil; }
 
 LISP_PREDICATE(listp)
@@ -235,6 +241,8 @@
 	
 	add_c_function(env, "elt", l_elt, 2);
 
+	add_c_function(env, "gc-stats", l_gc_stats, 0);
+
 	if (!load_library(env, "std"))
 	{
 		fprintf(stderr, "Not found std\n");
diff --git a/src/lisp/lisp.h b/src/lisp/lisp.h
index 64de5b9..e41ebff 100644
--- a/src/lisp/lisp.h
+++ b/src/lisp/lisp.h
@@ -112,7 +112,7 @@
 	/**
 	 * Reserved for the GC.
 	 */
-	unsigned int mark : 24;   // + 2 = 16
+	unsigned int mark : 24;   // + 3 = 16
 
 	// Whatever else
 };
diff --git a/src/lisp/lispbugs b/src/lisp/lispbugs
new file mode 100644
index 0000000..67ac030
--- /dev/null
+++ b/src/lisp/lispbugs
@@ -0,0 +1,8 @@
+BUG: "random" segfault in lisp (gc) calls.
+
+Theory: the values we're walking on the stack are garbage, i.e. coming
+from C.
+
+Looks like the GCSegments code got lost, I need to readd that and it
+should fix this. `eval' in `compiler.dasc' is getting it's local
+variables inspected by _do_gc.
\ No newline at end of file
diff --git a/src/lisp/plat/linux.c b/src/lisp/plat/linux.c
index ad7f873..f3ad032 100644
--- a/src/lisp/plat/linux.c
+++ b/src/lisp/plat/linux.c
@@ -51,8 +51,12 @@
 #ifndef NO_READLINE
 	return readline(prompt);
 #else
-	UNUSED(prompt);
-	return "";
+	fprintf(stdout, "%s", prompt);
+	fflush(stdout);
+	char *buffer = malloc(512);
+	fgets(buffer, 512, stdin);
+
+	return buffer;
 #endif
 }
 
diff --git a/src/lisp/test-gc.lisp b/src/lisp/test-gc.lisp
new file mode 100644
index 0000000..a41e146
--- /dev/null
+++ b/src/lisp/test-gc.lisp
@@ -0,0 +1,11 @@
+(defun main ()
+  ;; Allocate some garbage
+  (let1 (used "this should NOT be freed")
+	    (list 1 2 3 4)
+        (list "this" "is" "a" "list")
+        (gc)
+        (print (list "Current allocations" "GC runs"))
+        (print (gc-stats))))
+
+;; Note: This should print that it is freeing both lists, but not the
+;; string