From 56d46ceaa1413415f25e47e81036426132f99924 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 31 Oct 2016 16:43:44 -0700 Subject: Add first lisp bits Signed-off-by: Keith Packard --- src/lisp/ao_lisp_cons.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/lisp/ao_lisp_cons.c (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c new file mode 100644 index 00000000..60cbb2f3 --- /dev/null +++ b/src/lisp/ao_lisp_cons.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +static void cons_mark(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + ao_lisp_poly_mark(cons->car); + cons = cons->cdr; + if (!cons) + break; + if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) + break; + } +} + +static int cons_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_cons); +} + +static void cons_move(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + struct ao_lisp_cons *cdr; + + cons->car = ao_lisp_poly_move(cons->car); + cdr = ao_lisp_move_memory(cons->cdr, sizeof (struct ao_lisp_cons)); + if (!cdr) + break; + cons->cdr = cdr; + cons = cdr; + } +} + +const struct ao_lisp_mem_type ao_lisp_cons_type = { + .mark = cons_mark, + .size = cons_size, + .move = cons_move, +}; + +struct ao_lisp_cons * +ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr) +{ + struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + if (!cons) + return NULL; + cons->car = car; + cons->cdr = cdr; + return cons; +} + +void +ao_lisp_cons_print(struct ao_lisp_cons *cons) +{ + int first = 1; + printf("("); + while (cons) { + if (!first) + printf(" "); + fflush(stdout); + ao_lisp_poly_print(cons->car); + cons = cons->cdr; + first = 0; + } + printf(")"); +} -- cgit v1.2.3 From d2408e72d1e0d3459918601712b09860ab17e200 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 1 Nov 2016 21:14:45 -0700 Subject: altos/lisp: Change lisp objects to use ao_poly everywhere. Add const This makes all lisp objects use 16-bit ints for references so we can hold more stuff in small amounts of memory. Also adds a separate constant pool of lisp objects for builtins, initial atoms and constant lisp code. Now builds (and runs!) on the nucleo-32 boards. Signed-off-by: Keith Packard --- src/lisp/.gitignore | 2 + src/lisp/Makefile | 32 +++++ src/lisp/ao_lisp.h | 238 ++++++++++++++++++++++----------- src/lisp/ao_lisp_atom.c | 43 +++--- src/lisp/ao_lisp_builtin.c | 189 +++++++++++++++++++++++++- src/lisp/ao_lisp_cons.c | 19 +-- src/lisp/ao_lisp_const.lisp | 1 + src/lisp/ao_lisp_eval.c | 57 ++++++-- src/lisp/ao_lisp_int.c | 3 +- src/lisp/ao_lisp_make_const.c | 90 +++++++++++++ src/lisp/ao_lisp_mem.c | 41 ++++-- src/lisp/ao_lisp_poly.c | 89 +----------- src/lisp/ao_lisp_prim.c | 40 +++--- src/lisp/ao_lisp_read.c | 31 +++-- src/lisp/ao_lisp_rep.c | 40 ++++++ src/lisp/ao_lisp_string.c | 6 +- src/nucleao-32/.gitignore | 2 + src/nucleao-32/Makefile | 11 ++ src/nucleao-32/ao_nucleo.c | 7 + src/nucleao-32/flash-loader/.gitignore | 2 + src/test/Makefile | 8 +- src/test/ao_lisp_test.c | 40 +++--- 22 files changed, 714 insertions(+), 277 deletions(-) create mode 100644 src/lisp/.gitignore create mode 100644 src/lisp/Makefile create mode 100644 src/lisp/ao_lisp_const.lisp create mode 100644 src/lisp/ao_lisp_make_const.c create mode 100644 src/lisp/ao_lisp_rep.c create mode 100644 src/nucleao-32/.gitignore create mode 100644 src/nucleao-32/flash-loader/.gitignore (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/.gitignore b/src/lisp/.gitignore new file mode 100644 index 00000000..76a555ea --- /dev/null +++ b/src/lisp/.gitignore @@ -0,0 +1,2 @@ +ao_lisp_make_const +ao_lisp_const.h diff --git a/src/lisp/Makefile b/src/lisp/Makefile new file mode 100644 index 00000000..e8c3c02c --- /dev/null +++ b/src/lisp/Makefile @@ -0,0 +1,32 @@ +all: ao_lisp_const.h + +clean: + rm -f ao_lisp_const.h $(OBJS) ao_lisp_make_const + +ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const + ./ao_lisp_make_const < ao_lisp_const.lisp > $@ + +SRCS=\ + ao_lisp_make_const.c\ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_poly.c \ + ao_lisp_prim.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c + +OBJS=$(SRCS:.c=.o) + +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g + +HDRS=\ + ao_lisp.h \ + ao_lisp_read.h + +ao_lisp_make_const: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) + +$(OBJS): $(HDRS) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 6667dcc2..4fac861b 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,78 +15,158 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ +#if !defined(AO_LISP_TEST) && !defined(AO_LISP_MAKE_CONST) +#include +#define AO_LISP_ALTOS 1 +#endif + #include #include #include +#ifdef AO_LISP_MAKE_CONST +#define AO_LISP_POOL_CONST 16384 +extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +#else +#include "ao_lisp_const.h" +#endif + +/* Primitive types */ +#define AO_LISP_CONS 0 +#define AO_LISP_INT 1 +#define AO_LISP_STRING 2 +#define AO_LISP_OTHER 3 -# define AO_LISP_CONS 0 -# define AO_LISP_INT 1 -# define AO_LISP_STRING 2 -# define AO_LISP_OTHER 3 +#define AO_LISP_TYPE_MASK 0x0003 +#define AO_LISP_TYPE_SHIFT 2 +#define AO_LISP_REF_MASK 0x7ffc +#define AO_LISP_CONST 0x8000 -# define AO_LISP_ATOM 4 -# define AO_LISP_BUILTIN 5 +/* These have a type value at the start of the struct */ +#define AO_LISP_ATOM 4 +#define AO_LISP_BUILTIN 5 +#define AO_LISP_NUM_TYPE 6 -# define AO_LISP_NIL 0 +#define AO_LISP_NIL 0 #define AO_LISP_POOL 1024 -#define AO_LISP_ROOT 16 -static inline void *ao_lisp_set_ref(void *addr) { - return (void *) ((intptr_t)addr | 1); +extern uint8_t ao_lisp_pool[AO_LISP_POOL]; +extern uint16_t ao_lisp_top; + +#define AO_LISP_OOM 0x01 +#define AO_LISP_DIVIDE_BY_ZERO 0x02 +#define AO_LISP_INVALID 0x04 + +extern uint8_t ao_lisp_exception; + +typedef uint16_t ao_poly; + +static inline void * +ao_lisp_ref(ao_poly poly) { + if (poly == AO_LISP_NIL) + return NULL; + if (poly & AO_LISP_CONST) + return (void *) ((ao_lisp_const - 4) + (poly & AO_LISP_REF_MASK)); + else + return (void *) ((ao_lisp_pool - 4) + (poly & AO_LISP_REF_MASK)); } -static inline void *ao_lisp_clear_ref(void *addr) { - return (void *) ((intptr_t)addr & ~1); +static inline ao_poly +ao_lisp_poly(const void *addr, ao_poly type) { + const uint8_t *a = addr; + if (addr == NULL) + return AO_LISP_NIL; + if (ao_lisp_pool <= a && a < ao_lisp_pool + AO_LISP_POOL) + return (a - (ao_lisp_pool - 4)) | type; + else if (ao_lisp_const <= a && a <= ao_lisp_const + AO_LISP_POOL_CONST) + return AO_LISP_CONST | (a - (ao_lisp_const - 4)) | type; + else { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } } -extern uint8_t ao_lisp_pool[AO_LISP_POOL]; +#define AO_LISP_POLY(addr, type) (((ao_lisp_pool <= ((uint8_t *) (a)) && \ + ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) ? \ + ((uint8_t *) (a) - (ao_lisp_pool - 4)) : \ + (((uint8_t *) (a) - (ao_lisp_const - 4)) | AO_LISP_POOL_CONST)) | \ + (type)) -struct ao_lisp_mem_type { +struct ao_lisp_type { void (*mark)(void *addr); int (*size)(void *addr); void (*move)(void *addr); }; -typedef intptr_t ao_lisp_poly; - struct ao_lisp_cons { - ao_lisp_poly car; - struct ao_lisp_cons *cdr; + ao_poly car; + ao_poly cdr; }; struct ao_lisp_atom { - uint8_t type; - ao_lisp_poly val; - struct ao_lisp_atom *next; - char name[]; + uint8_t type; + uint8_t pad[1]; + ao_poly val; + ao_poly next; + char name[]; }; -#define AO_LISP_ATOM_CONST ((struct ao_lisp_atom *) (intptr_t) 1) - -extern const struct ao_lisp_atom *ao_lisp_builtins[]; +#define AO_LISP_LAMBDA 0 +#define AO_LISP_NLAMBDA 1 +#define AO_LISP_MACRO 2 +#define AO_LISP_LEXPR 3 struct ao_lisp_builtin { - uint8_t type; - ao_lisp_poly (*func)(struct ao_lisp_cons *cons); - char name[]; + uint8_t type; + uint8_t args; + uint16_t func; }; +enum ao_lisp_builtin_id { + builtin_car, + builtin_cdr, + builtin_cons, + builtin_quote, + builtin_print, + builtin_plus, + builtin_minus, + builtin_times, + builtin_divide, + builtin_mod, + builtin_last +}; + +typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons); + +extern ao_lisp_func_t ao_lisp_builtins[]; + +static inline ao_lisp_func_t +ao_lisp_func(struct ao_lisp_builtin *b) +{ + return ao_lisp_builtins[b->func]; +} + static inline void * -ao_lisp_poly_other(ao_lisp_poly poly) { - return (void *) (poly - AO_LISP_OTHER); +ao_lisp_poly_other(ao_poly poly) { + return ao_lisp_ref(poly); } -static const inline ao_lisp_poly +static inline ao_poly ao_lisp_other_poly(const void *other) { - return (ao_lisp_poly) other + AO_LISP_OTHER; + return ao_lisp_poly(other, AO_LISP_OTHER); +} + +static inline int +ao_lisp_mem_round(int size) +{ + return (size + 3) & ~3; } -#define AO_LISP_OTHER_POLY(other) ((ao_lisp_poly)(other) + AO_LISP_OTHER) +#define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) -static inline int ao_lisp_poly_type(ao_lisp_poly poly) { +static inline int ao_lisp_poly_type(ao_poly poly) { int type = poly & 3; if (type == AO_LISP_OTHER) return *((uint8_t *) ao_lisp_poly_other(poly)); @@ -94,75 +174,75 @@ static inline int ao_lisp_poly_type(ao_lisp_poly poly) { } static inline struct ao_lisp_cons * -ao_lisp_poly_cons(ao_lisp_poly poly) +ao_lisp_poly_cons(ao_poly poly) { - return (struct ao_lisp_cons *) (poly - AO_LISP_CONS); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_cons_poly(struct ao_lisp_cons *cons) { - return (ao_lisp_poly) cons + AO_LISP_CONS; + return ao_lisp_poly(cons, AO_LISP_CONS); } static inline int -ao_lisp_poly_int(ao_lisp_poly poly) +ao_lisp_poly_int(ao_poly poly) { - return (int) (poly >> 2); + return (int) poly >> AO_LISP_TYPE_SHIFT; } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_int_poly(int i) { - return ((ao_lisp_poly) i << 2) + AO_LISP_INT; + return ((ao_poly) i << 2) + AO_LISP_INT; } static inline char * -ao_lisp_poly_string(ao_lisp_poly poly) +ao_lisp_poly_string(ao_poly poly) { - return (char *) (poly - AO_LISP_STRING); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly -ao_lisp_string_poly(char *s) { - return (ao_lisp_poly) s + AO_LISP_STRING; +static inline ao_poly +ao_lisp_string_poly(char *s) +{ + return ao_lisp_poly(s, AO_LISP_STRING); } static inline struct ao_lisp_atom * -ao_lisp_poly_atom(ao_lisp_poly poly) +ao_lisp_poly_atom(ao_poly poly) { - return (struct ao_lisp_atom *) (poly - AO_LISP_OTHER); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_atom_poly(struct ao_lisp_atom *a) { - return (ao_lisp_poly) a + AO_LISP_OTHER; + return ao_lisp_poly(a, AO_LISP_OTHER); } static inline struct ao_lisp_builtin * -ao_lisp_poly_builtin(ao_lisp_poly poly) +ao_lisp_poly_builtin(ao_poly poly) { - return (struct ao_lisp_builtin *) (poly - AO_LISP_OTHER); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_builtin_poly(struct ao_lisp_builtin *b) { - return (ao_lisp_poly) b + AO_LISP_OTHER; + return ao_lisp_poly(b, AO_LISP_OTHER); } /* memory functions */ - void -ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ int ao_lisp_mark_memory(void *addr, int size); void * -ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_move(const struct ao_lisp_type *type, void *addr); /* returns NULL if the object was already moved */ void * @@ -172,22 +252,22 @@ void * ao_lisp_alloc(int size); int -ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); void ao_lisp_root_clear(void *addr); /* cons */ -extern const struct ao_lisp_mem_type ao_lisp_cons_type; +extern const struct ao_lisp_type ao_lisp_cons_type; struct ao_lisp_cons * -ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr); +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); void -ao_lisp_cons_print(struct ao_lisp_cons *cons); +ao_lisp_cons_print(ao_poly); /* string */ -extern const struct ao_lisp_mem_type ao_lisp_string_type; +extern const struct ao_lisp_type ao_lisp_string_type; char * ao_lisp_string_new(int len); @@ -199,44 +279,50 @@ char * ao_lisp_string_cat(char *a, char *b); void -ao_lisp_string_print(char *s); +ao_lisp_string_print(ao_poly s); /* atom */ -extern const struct ao_lisp_mem_type ao_lisp_atom_type; +extern const struct ao_lisp_type ao_lisp_atom_type; + +extern struct ao_lisp_atom *ao_lisp_atoms; void ao_lisp_atom_init(void); void -ao_lisp_atom_print(struct ao_lisp_atom *atom); +ao_lisp_atom_print(ao_poly a); struct ao_lisp_atom * ao_lisp_atom_intern(char *name); /* int */ void -ao_lisp_int_print(int i); +ao_lisp_int_print(ao_poly i); /* prim */ -ao_lisp_poly -ao_lisp_poly_print(ao_lisp_poly p); +ao_poly +ao_lisp_poly_print(ao_poly p); void -ao_lisp_poly_mark(ao_lisp_poly p); +ao_lisp_poly_mark(ao_poly p); -ao_lisp_poly -ao_lisp_poly_move(ao_lisp_poly p); +ao_poly +ao_lisp_poly_move(ao_poly p); /* eval */ -ao_lisp_poly -ao_lisp_eval(ao_lisp_poly p); +ao_poly +ao_lisp_eval(ao_poly p); /* builtin */ void -ao_lisp_builtin_print(struct ao_lisp_builtin *b); +ao_lisp_builtin_print(ao_poly b); /* read */ -ao_lisp_poly +ao_poly ao_lisp_read(void); +/* rep */ +ao_poly +ao_lisp_read_eval_print(void); + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 65282142..aaa84b8d 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -34,12 +34,9 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; - if (atom->next == AO_LISP_ATOM_CONST) - return; - for (;;) { ao_lisp_poly_mark(atom->val); - atom = atom->next; + atom = ao_lisp_poly_atom(atom->next); if (!atom) break; if (ao_lisp_mark_memory(atom, atom_size(atom))) @@ -51,49 +48,50 @@ static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; - if (atom->next == AO_LISP_ATOM_CONST) - return; - for (;;) { struct ao_lisp_atom *next; atom->val = ao_lisp_poly_move(atom->val); - next = ao_lisp_move_memory(atom->next, atom_size(atom->next)); + next = ao_lisp_poly_atom(atom->next); + next = ao_lisp_move_memory(next, atom_size(next)); if (!next) break; - atom->next = next; + atom->next = ao_lisp_atom_poly(next); atom = next; } } -const struct ao_lisp_mem_type ao_lisp_atom_type = { +const struct ao_lisp_type ao_lisp_atom_type = { .mark = atom_mark, .size = atom_size, .move = atom_move, }; -struct ao_lisp_atom *atoms; +struct ao_lisp_atom *ao_lisp_atoms; struct ao_lisp_atom * ao_lisp_atom_intern(char *name) { struct ao_lisp_atom *atom; - int b; +// int b; - for (atom = atoms; atom; atom = atom->next) { + for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) { + if (!strcmp(atom->name, name)) + return atom; + } +#ifdef ao_builtin_atoms + for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { if (!strcmp(atom->name, name)) return atom; } - for (b = 0; ao_lisp_builtins[b]; b++) - if (!strcmp(ao_lisp_builtins[b]->name, name)) - return (struct ao_lisp_atom *) ao_lisp_builtins[b]; - if (!atoms) - ao_lisp_root_add(&ao_lisp_atom_type, (void **) &atoms); +#endif + if (!ao_lisp_atoms) + ao_lisp_root_add(&ao_lisp_atom_type, (void **) &ao_lisp_atoms); atom = ao_lisp_alloc(name_size(name)); if (atom) { atom->type = AO_LISP_ATOM; - atom->next = atoms; - atoms = atom; + atom->next = ao_lisp_atom_poly(ao_lisp_atoms); + ao_lisp_atoms = atom; strcpy(atom->name, name); atom->val = AO_LISP_NIL; } @@ -101,7 +99,8 @@ ao_lisp_atom_intern(char *name) } void -ao_lisp_atom_print(struct ao_lisp_atom *a) +ao_lisp_atom_print(ao_poly a) { - fputs(a->name, stdout); + struct ao_lisp_atom *atom = ao_lisp_poly_atom(a); + printf("%s", atom->name); } diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 3752a2c8..e6d55797 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -15,7 +15,192 @@ #include "ao_lisp.h" void -ao_lisp_builtin_print(struct ao_lisp_builtin *b) +ao_lisp_builtin_print(ao_poly b) { - printf("[builtin %s]", b->name); + (void) b; + printf("[builtin]"); } + +enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; + +ao_poly +ao_lisp_car(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (!cons->car) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_poly_cons(cons->car)->car; +} + +ao_poly +ao_lisp_cdr(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (!cons->car) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_poly_cons(cons->car)->cdr; +} + +ao_poly +ao_lisp_cons(struct ao_lisp_cons *cons) +{ + ao_poly car, cdr; + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + car = cons->car; + cdr = cons->cdr; + if (!car || !cdr) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + cdr = ao_lisp_poly_cons(cdr)->car; + if (ao_lisp_poly_type(cdr) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr))); +} + +ao_poly +ao_lisp_quote(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return cons->car; +} + +ao_poly +ao_lisp_print(struct ao_lisp_cons *cons) +{ + ao_poly val = AO_LISP_NIL; + while (cons) { + val = cons->car; + ao_lisp_poly_print(val); + cons = ao_lisp_poly_cons(cons->cdr); + } + return val; +} + +ao_poly +ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +{ + ao_poly ret = AO_LISP_NIL; + + while (cons) { + ao_poly car = cons->car; + uint8_t rt = ao_lisp_poly_type(ret); + uint8_t ct = ao_lisp_poly_type(car); + + cons = ao_lisp_poly_cons(cons->cdr); + + if (rt == AO_LISP_NIL) + ret = car; + + else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { + int r = ao_lisp_poly_int(ret); + int c = ao_lisp_poly_int(car); + + switch(op) { + case math_plus: + r += c; + break; + case math_minus: + r -= c; + break; + case math_times: + r *= c; + break; + case math_divide: + if (c == 0) { + ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; + return AO_LISP_NIL; + } + r /= c; + break; + case math_mod: + if (c == 0) { + ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; + return AO_LISP_NIL; + } + r %= c; + break; + } + ret = ao_lisp_int_poly(r); + } + + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), + ao_lisp_poly_string(car))); + else { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + } + return ret; +} + +ao_poly +ao_lisp_plus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_plus); +} + +ao_poly +ao_lisp_minus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_minus); +} + +ao_poly +ao_lisp_times(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_times); +} + +ao_poly +ao_lisp_divide(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_divide); +} + +ao_poly +ao_lisp_mod(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_mod); +} + +ao_lisp_func_t ao_lisp_builtins[] = { + [builtin_car] = ao_lisp_car, + [builtin_cdr] = ao_lisp_cdr, + [builtin_cons] = ao_lisp_cons, + [builtin_quote] = ao_lisp_quote, + [builtin_print] = ao_lisp_print, + [builtin_plus] = ao_lisp_plus, + [builtin_minus] = ao_lisp_minus, + [builtin_times] = ao_lisp_times, + [builtin_divide] = ao_lisp_divide, + [builtin_mod] = ao_lisp_mod +}; + diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 60cbb2f3..65908e30 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -20,7 +20,7 @@ static void cons_mark(void *addr) for (;;) { ao_lisp_poly_mark(cons->car); - cons = cons->cdr; + cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) @@ -42,42 +42,43 @@ static void cons_move(void *addr) struct ao_lisp_cons *cdr; cons->car = ao_lisp_poly_move(cons->car); - cdr = ao_lisp_move_memory(cons->cdr, sizeof (struct ao_lisp_cons)); + cdr = ao_lisp_poly_cons(cons->cdr); + cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); if (!cdr) break; - cons->cdr = cdr; + cons->cdr = ao_lisp_cons_poly(cdr); cons = cdr; } } -const struct ao_lisp_mem_type ao_lisp_cons_type = { +const struct ao_lisp_type ao_lisp_cons_type = { .mark = cons_mark, .size = cons_size, .move = cons_move, }; struct ao_lisp_cons * -ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr) +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); if (!cons) return NULL; cons->car = car; - cons->cdr = cdr; + cons->cdr = ao_lisp_cons_poly(cdr); return cons; } void -ao_lisp_cons_print(struct ao_lisp_cons *cons) +ao_lisp_cons_print(ao_poly c) { + struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); int first = 1; printf("("); while (cons) { if (!first) printf(" "); - fflush(stdout); ao_lisp_poly_print(cons->car); - cons = cons->cdr; + cons = ao_lisp_poly_cons(cons->cdr); first = 0; } printf(")"); diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp new file mode 100644 index 00000000..aa356d45 --- /dev/null +++ b/src/lisp/ao_lisp_const.lisp @@ -0,0 +1 @@ +cadr (lambda (l) (car (cdr l))) diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 23908e64..b13d4681 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -40,8 +40,8 @@ static uint8_t been_here; #define DBG_POLY(a) #endif -ao_lisp_poly -ao_lisp_eval(ao_lisp_poly v) +ao_poly +ao_lisp_eval(ao_poly v) { struct ao_lisp_cons *formal; int cons = 0; @@ -59,6 +59,7 @@ ao_lisp_eval(ao_lisp_poly v) formals_tail = 0; for (;;) { + restart: /* Build stack frames for each list */ while (ao_lisp_poly_type(v) == AO_LISP_CONS) { if (v == AO_LISP_NIL) @@ -68,8 +69,8 @@ ao_lisp_eval(ao_lisp_poly v) if (cons++) { struct ao_lisp_cons *frame; - frame = ao_lisp_cons(ao_lisp_cons_poly(actuals), formals); - stack = ao_lisp_cons(ao_lisp_cons_poly(frame), stack); + frame = ao_lisp_cons_cons(ao_lisp_cons_poly(actuals), formals); + stack = ao_lisp_cons_cons(ao_lisp_cons_poly(frame), stack); } actuals = ao_lisp_poly_cons(v); formals = NULL; @@ -83,6 +84,8 @@ ao_lisp_eval(ao_lisp_poly v) /* Evaluate primitive types */ + DBG ("actual: "); DBG_POLY(v); DBG("\n"); + switch (ao_lisp_poly_type(v)) { case AO_LISP_INT: case AO_LISP_STRING: @@ -92,16 +95,42 @@ ao_lisp_eval(ao_lisp_poly v) break; } + if (!cons) + break; + for (;;) { DBG("add formal: "); DBG_POLY(v); DBG("\n"); - formal = ao_lisp_cons(v, NULL); + if (formals == NULL) { + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + switch (b->args) { + case AO_LISP_NLAMBDA: + v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + goto done_eval; + + case AO_LISP_MACRO: + v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + if (ao_lisp_poly_type(v) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + + /* Reset frame to the new list */ + actuals = ao_lisp_poly_cons(v); + v = actuals->car; + goto restart; + } + } + } + + formal = ao_lisp_cons_cons(v, NULL); if (formals_tail) - formals_tail->cdr = formal; + formals_tail->cdr = ao_lisp_cons_poly(formal); else formals = formal; formals_tail = formal; - actuals = actuals->cdr; + actuals = ao_lisp_poly_cons(actuals->cdr); DBG("formals: "); DBG_CONS(formals); @@ -113,7 +142,6 @@ ao_lisp_eval(ao_lisp_poly v) /* Process all of the arguments */ if (actuals) { v = actuals->car; - DBG ("actual: "); DBG_POLY(v); DBG("\n"); break; } @@ -123,7 +151,7 @@ ao_lisp_eval(ao_lisp_poly v) if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - v = b->func(formals->cdr); + v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr)); DBG ("eval: "); DBG_CONS(formals); @@ -131,22 +159,23 @@ ao_lisp_eval(ao_lisp_poly v) DBG_POLY(v); DBG ("\n"); } else { - DBG ("invalid eval\n"); + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; } - + done_eval: if (--cons) { struct ao_lisp_cons *frame; /* Pop the previous frame off the stack */ frame = ao_lisp_poly_cons(stack->car); actuals = ao_lisp_poly_cons(frame->car); - formals = frame->cdr; + formals = ao_lisp_poly_cons(frame->cdr); /* Recompute the tail of the formals list */ - for (formal = formals; formal->cdr != NULL; formal = formal->cdr); + for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); formals_tail = formal; - stack = stack->cdr; + stack = ao_lisp_poly_cons(stack->cdr); DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c index 6ee3096d..77f65e95 100644 --- a/src/lisp/ao_lisp_int.c +++ b/src/lisp/ao_lisp_int.c @@ -15,7 +15,8 @@ #include "ao_lisp.h" void -ao_lisp_int_print(int i) +ao_lisp_int_print(ao_poly p) { + int i = ao_lisp_poly_int(p); printf("%d", i); } diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c new file mode 100644 index 00000000..21e000bf --- /dev/null +++ b/src/lisp/ao_lisp_make_const.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include + +static struct ao_lisp_builtin * +ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) { + struct ao_lisp_builtin *b = ao_lisp_alloc(sizeof (struct ao_lisp_builtin)); + + b->type = AO_LISP_BUILTIN; + b->func = func; + b->args = args; + return b; +} + +struct builtin_func { + char *name; + int args; + int func; +}; + +struct builtin_func funcs[] = { + "car", AO_LISP_LEXPR, builtin_car, + "cdr", AO_LISP_LEXPR, builtin_cdr, + "cons", AO_LISP_LEXPR, builtin_cons, + "quote", AO_LISP_NLAMBDA,builtin_quote, + "print", AO_LISP_LEXPR, builtin_print, + "+", AO_LISP_LEXPR, builtin_plus, + "-", AO_LISP_LEXPR, builtin_minus, + "*", AO_LISP_LEXPR, builtin_times, + "/", AO_LISP_LEXPR, builtin_divide, + "%", AO_LISP_LEXPR, builtin_mod +}; + +#define N_FUNC (sizeof funcs / sizeof funcs[0]) + +int +main(int argc, char **argv) +{ + int f, o; + ao_poly atom, val; + + for (f = 0; f < N_FUNC; f++) { + struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); + struct ao_lisp_atom *a = ao_lisp_atom_intern(funcs[f].name); + a->val = ao_lisp_builtin_poly(b); + } + + for (;;) { + atom = ao_lisp_read(); + if (!atom) + break; + val = ao_lisp_read(); + if (!val) + break; + if (ao_lisp_poly_type(atom) != AO_LISP_ATOM) { + fprintf(stderr, "input must be atom val pairs\n"); + exit(1); + } + ao_lisp_poly_atom(atom)->val = val; + } + + printf("/* constant objects, all referenced from atoms */\n\n"); + printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); + printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); + printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + printf("#ifdef AO_LISP_CONST_BITS\n"); + printf("const uint8_t ao_lisp_const[] = {"); + for (o = 0; o < ao_lisp_top; o++) { + if ((o & 0xf) == 0) + printf("\n\t"); + else + printf(" "); + printf("0x%02x,", ao_lisp_const[o]); + } + printf("\n};\n"); + printf("#endif /* AO_LISP_CONST_BITS */\n"); +} diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index d008519b..7295d150 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -12,23 +12,34 @@ * General Public License for more details. */ +#define AO_LISP_CONST_BITS + #include "ao_lisp.h" #include -uint8_t ao_lisp_pool[AO_LISP_POOL]; +uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); + +#ifdef AO_LISP_MAKE_CONST +#include +uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#endif + +uint8_t ao_lisp_exception; struct ao_lisp_root { void **addr; - const struct ao_lisp_mem_type *type; + const struct ao_lisp_type *type; }; +#define AO_LISP_ROOT 16 + static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint16_t ao_lisp_top; +uint16_t ao_lisp_top; static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; @@ -59,9 +70,13 @@ static int mark_object(uint8_t *tag, void *addr, int size) { int base; int bound; + if (!addr) return 1; + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + base = (uint8_t *) addr - ao_lisp_pool; bound = base + size; @@ -150,7 +165,7 @@ collect(void) void -ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (mark_object(ao_lisp_busy, addr, type->size(addr))) return; @@ -175,7 +190,7 @@ check_move(void *addr, int size) } void * -ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_move(const struct ao_lisp_type *type, void *addr) { int size = type->size(addr); @@ -206,19 +221,29 @@ ao_lisp_alloc(int size) { void *addr; - size = (size + 3) & ~3; + size = ao_lisp_mem_round(size); +#ifdef AO_LISP_MAKE_CONST + if (ao_lisp_top + size > AO_LISP_POOL_CONST) { + fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n"); + exit(1); + } + addr = ao_lisp_const + ao_lisp_top; +#else if (ao_lisp_top + size > AO_LISP_POOL) { collect(); - if (ao_lisp_top + size > AO_LISP_POOL) + if (ao_lisp_top + size > AO_LISP_POOL) { + ao_lisp_exception |= AO_LISP_OOM; return NULL; + } } addr = ao_lisp_pool + ao_lisp_top; +#endif ao_lisp_top += size; return addr; } int -ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; for (i = 0; i < AO_LISP_ROOT; i++) { diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index 1855d945..c6ca0a97 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -14,91 +14,7 @@ #include "ao_lisp.h" -enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; - -ao_lisp_poly -ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) -{ - ao_lisp_poly ret = AO_LISP_NIL; - - while (cons) { - ao_lisp_poly car = cons->car; - uint8_t rt = ao_lisp_poly_type(ret); - uint8_t ct = ao_lisp_poly_type(car); - - cons = cons->cdr; - - if (rt == AO_LISP_NIL) - ret = car; - - else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { - int r = ao_lisp_poly_int(ret); - int c = ao_lisp_poly_int(car); - - switch(op) { - case math_plus: - r += c; - break; - case math_minus: - r -= c; - break; - case math_times: - r *= c; - break; - case math_divide: - if (c == 0) - return AO_LISP_NIL; - r /= c; - break; - case math_mod: - if (c == 0) - return AO_LISP_NIL; - r %= c; - break; - } - ret = ao_lisp_int_poly(r); - } - - else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) - ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), - ao_lisp_poly_string(car))); - else { - /* XXX exception */ - return AO_LISP_NIL; - } - } - return ret; -} - -ao_lisp_poly -ao_lisp_plus(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_plus); -} - -ao_lisp_poly -ao_lisp_minus(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_minus); -} - -ao_lisp_poly -ao_lisp_times(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_times); -} - -ao_lisp_poly -ao_lisp_divide(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_divide); -} - -ao_lisp_poly -ao_lisp_mod(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_mod); -} +/* static const struct ao_lisp_builtin builtin_plus = { .type = AO_LISP_BUILTIN, @@ -113,7 +29,6 @@ static const struct ao_lisp_atom atom_plus = { .name = "plus" }; -/* static const struct ao_lisp_builtin builtin_minus = { .type = AO_LISP_BUILTIN, .func = ao_lisp_minus @@ -124,9 +39,9 @@ static const struct ao_lisp_builtin builtin_times = { .func = ao_lisp_times }; -*/ const struct ao_lisp_atom const *ao_lisp_builtins[] = { &atom_plus, 0 }; +*/ diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index ccfd2be4..38dcb961 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -14,31 +14,25 @@ #include "ao_lisp.h" -ao_lisp_poly -ao_lisp_poly_print(ao_lisp_poly p) +static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { + [AO_LISP_CONS] = ao_lisp_cons_print, + [AO_LISP_STRING] = ao_lisp_string_print, + [AO_LISP_INT] = ao_lisp_int_print, + [AO_LISP_ATOM] = ao_lisp_atom_print, + [AO_LISP_BUILTIN] = ao_lisp_builtin_print +}; + +ao_poly +ao_lisp_poly_print(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - ao_lisp_cons_print(ao_lisp_poly_cons(p)); - break; - case AO_LISP_STRING: - ao_lisp_string_print(ao_lisp_poly_string(p)); - break; - case AO_LISP_INT: - ao_lisp_int_print(ao_lisp_poly_int(p)); - break; - case AO_LISP_ATOM: - ao_lisp_atom_print(ao_lisp_poly_atom(p)); - break; - case AO_LISP_BUILTIN: - ao_lisp_builtin_print(ao_lisp_poly_builtin(p)); - break; - } - return AO_LISP_NIL; + void (*print)(ao_poly) = ao_lisp_print_funcs[ao_lisp_poly_type(p)]; + if (print) + print(p); + return p; } void -ao_lisp_poly_mark(ao_lisp_poly p) +ao_lisp_poly_mark(ao_poly p) { switch (ao_lisp_poly_type(p)) { case AO_LISP_CONS: @@ -53,8 +47,8 @@ ao_lisp_poly_mark(ao_lisp_poly p) } } -ao_lisp_poly -ao_lisp_poly_move(ao_lisp_poly p) +ao_poly +ao_lisp_poly_move(ao_poly p) { switch (ao_lisp_poly_type(p)) { case AO_LISP_CONS: diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index ccb4ba3a..ea98b976 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -155,8 +155,21 @@ lex_get() if (lex_unget_c) { c = lex_unget_c; lex_unget_c = 0; - } else + } else { +#if AO_LISP_ALTOS + static uint8_t at_eol; + + if (at_eol) { + ao_cmd_readline(); + at_eol = 0; + } + c = ao_cmd_lex(); + if (c == '\n') + at_eol = 1; +#else c = getchar(); +#endif + } return c; } @@ -362,13 +375,13 @@ static struct ao_lisp_cons *read_cons; static struct ao_lisp_cons *read_cons_tail; static struct ao_lisp_cons *read_stack; -static ao_lisp_poly +static ao_poly read_item(void) { struct ao_lisp_atom *atom; char *string; int cons; - ao_lisp_poly v; + ao_poly v; if (!been_here) { ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); @@ -381,7 +394,7 @@ read_item(void) for (;;) { while (parse_token == OPEN) { if (cons++) - read_stack = ao_lisp_cons(ao_lisp_cons_poly(read_cons), read_stack); + read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), read_stack); read_cons = NULL; read_cons_tail = NULL; parse_token = lex(); @@ -416,10 +429,10 @@ read_item(void) v = AO_LISP_NIL; if (--cons) { read_cons = ao_lisp_poly_cons(read_stack->car); - read_stack = read_stack->cdr; + read_stack = ao_lisp_poly_cons(read_stack->cdr); for (read_cons_tail = read_cons; read_cons_tail && read_cons_tail->cdr; - read_cons_tail = read_cons_tail->cdr) + read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) ; } break; @@ -428,9 +441,9 @@ read_item(void) if (!cons) break; - struct ao_lisp_cons *read = ao_lisp_cons(v, NULL); + struct ao_lisp_cons *read = ao_lisp_cons_cons(v, NULL); if (read_cons_tail) - read_cons_tail->cdr = read; + read_cons_tail->cdr = ao_lisp_cons_poly(read); else read_cons = read; read_cons_tail = read; @@ -440,7 +453,7 @@ read_item(void) return v; } -ao_lisp_poly +ao_poly ao_lisp_read(void) { parse_token = lex(); diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c new file mode 100644 index 00000000..d26d270c --- /dev/null +++ b/src/lisp/ao_lisp_rep.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +ao_poly +ao_lisp_read_eval_print(void) +{ + ao_poly in, out = AO_LISP_NIL; + for(;;) { + in = ao_lisp_read(); + if (!in) + break; + out = ao_lisp_eval(in); + if (ao_lisp_exception) { + if (ao_lisp_exception & AO_LISP_OOM) + printf("out of memory\n"); + if (ao_lisp_exception & AO_LISP_DIVIDE_BY_ZERO) + printf("divide by zero\n"); + if (ao_lisp_exception & AO_LISP_INVALID) + printf("invalid operation\n"); + ao_lisp_exception = 0; + } else { + ao_lisp_poly_print(out); + putchar ('\n'); + } + } + return out; +} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 1ab56933..39c3dc81 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -68,16 +68,18 @@ ao_lisp_string_cat(char *a, char *b) return r; } -const struct ao_lisp_mem_type ao_lisp_string_type = { +const struct ao_lisp_type ao_lisp_string_type = { .mark = string_mark, .size = string_size, .move = string_move, }; void -ao_lisp_string_print(char *s) +ao_lisp_string_print(ao_poly p) { + char *s = ao_lisp_poly_string(p); char c; + putchar('"'); while ((c = *s++)) { switch (c) { diff --git a/src/nucleao-32/.gitignore b/src/nucleao-32/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index a160fd2f..0df44317 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -32,6 +32,17 @@ ALTOS_SRC = \ ao_mutex.c \ ao_usb_stm.c \ ao_serial_stm.c \ + ao_lisp_lex.c \ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_eval.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_prim.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c \ + ao_lisp_rep.c \ ao_exti_stm.c PRODUCT=Nucleo-32 diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c index cda889c6..113e2399 100644 --- a/src/nucleao-32/ao_nucleo.c +++ b/src/nucleao-32/ao_nucleo.c @@ -13,6 +13,7 @@ */ #include +#include static uint16_t blink_delay, blink_running; @@ -41,11 +42,17 @@ static void blink_cmd() { ao_sleep(&blink_running); } +static void lisp_cmd() { + ao_lisp_read_eval_print(); +} + static const struct ao_cmds blink_cmds[] = { { blink_cmd, "b \0Blink the green LED" }, + { lisp_cmd, "l\0Run lisp interpreter" }, { 0, 0 } }; + void main(void) { ao_led_init(LEDS_AVAILABLE); diff --git a/src/nucleao-32/flash-loader/.gitignore b/src/nucleao-32/flash-loader/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/test/Makefile b/src/test/Makefile index e841bfde..6c51c421 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -10,7 +10,7 @@ INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quat KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST all: $(PROGS) ao_aprs_data.wav @@ -89,9 +89,11 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm -AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o +#AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o + +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) -$(AO_LISP_OBJS): ao_lisp.h +$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 96f1fd72..810a1528 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -21,9 +21,9 @@ static char *string; int main (int argc, char **argv) { - int i, j; + int i, j; struct ao_lisp_atom *atom; - ao_lisp_poly poly; + ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); @@ -31,37 +31,35 @@ main (int argc, char **argv) for (j = 0; j < 10; j++) { list = 0; string = ao_lisp_string_new(0); - for (i = 0; i < 7; i++) { + for (i = 0; i < 2; i++) { string = ao_lisp_string_cat(string, "a"); - list = ao_lisp_cons(ao_lisp_string_poly(string), list); - list = ao_lisp_cons(ao_lisp_int_poly(i), list); + list = ao_lisp_cons_cons(ao_lisp_string_poly(string), list); + list = ao_lisp_cons_cons(ao_lisp_int_poly(i), list); atom = ao_lisp_atom_intern("ant"); atom->val = ao_lisp_cons_poly(list); - list = ao_lisp_cons(ao_lisp_atom_poly(atom), list); + list = ao_lisp_cons_cons(ao_lisp_atom_poly(atom), list); } ao_lisp_poly_print(ao_lisp_cons_poly(list)); printf("\n"); } - atom = ao_lisp_atom_intern("ant"); - atom->val = ao_lisp_string_poly(ao_lisp_string_cat("hello world", "")); - - list = ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), - ao_lisp_cons(ao_lisp_cons_poly(ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), - ao_lisp_cons(ao_lisp_int_poly(3), - ao_lisp_cons(ao_lisp_int_poly(4), NULL)))), - ao_lisp_cons(ao_lisp_int_poly(2), NULL))); + for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { + printf("%s = ", atom->name); + ao_lisp_poly_print(atom->val); + printf("\n"); + } +#if 1 + list = ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), + ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), + ao_lisp_cons_cons(ao_lisp_int_poly(3), + ao_lisp_cons_cons(ao_lisp_int_poly(4), NULL)))), + ao_lisp_cons_cons(ao_lisp_int_poly(2), NULL))); printf("list: "); ao_lisp_poly_print(ao_lisp_cons_poly(list)); printf ("\n"); ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); printf ("\n"); - while ((poly = ao_lisp_read())) { - poly = ao_lisp_eval(poly); - ao_lisp_poly_print(poly); - putchar ('\n'); - fflush(stdout); - } - + ao_lisp_read_eval_print(); +#endif } -- cgit v1.2.3 From 11cb03b1d336ee90c422be27588f57be573a9546 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 22:56:01 -0700 Subject: altos/lisp: Separate out values from atoms This enables changing values of atoms declared as constants, should enable lets, and with some work, even lexical scoping. this required changing the constant computation to run ao_lisp_collect() before dumping the block of constant data, and that uncovered some minor memory manager bugs. Signed-off-by: Keith Packard --- src/lisp/Makefile | 3 +- src/lisp/ao_lisp.h | 105 +++++++++++++++++------ src/lisp/ao_lisp_atom.c | 51 +++++++++-- src/lisp/ao_lisp_builtin.c | 37 ++++++-- src/lisp/ao_lisp_cons.c | 27 +++++- src/lisp/ao_lisp_eval.c | 5 +- src/lisp/ao_lisp_frame.c | 191 ++++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_make_const.c | 44 ++++++++-- src/lisp/ao_lisp_mem.c | 168 +++++++++++++++++++++++++++++++------ src/lisp/ao_lisp_prim.c | 41 +++++---- src/lisp/ao_lisp_read.c | 23 ++--- src/nucleao-32/Makefile | 3 + src/test/Makefile | 4 +- src/test/ao_lisp_test.c | 3 +- 14 files changed, 597 insertions(+), 108 deletions(-) create mode 100644 src/lisp/ao_lisp_frame.c (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index e8c3c02c..9e2fb58c 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -16,7 +16,8 @@ SRCS=\ ao_lisp_poly.c \ ao_lisp_prim.c \ ao_lisp_builtin.c \ - ao_lisp_read.c + ao_lisp_read.c \ + ao_lisp_frame.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index d4108662..98e99acb 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,9 +15,12 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ +#include + #if !defined(AO_LISP_TEST) && !defined(AO_LISP_MAKE_CONST) #include #define AO_LISP_ALTOS 1 +#define abort() ao_panic(1) #endif #include @@ -27,9 +30,14 @@ #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +#define ao_lisp_pool ao_lisp_const +#define AO_LISP_POOL AO_LISP_POOL_CONST #define _ao_lisp_atom_quote ao_lisp_atom_poly(ao_lisp_atom_intern("quote")) +#define _ao_lisp_atom_set ao_lisp_atom_poly(ao_lisp_atom_intern("set")) #else #include "ao_lisp_const.h" +#define AO_LISP_POOL 1024 +extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #endif /* Primitive types */ @@ -46,13 +54,11 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; /* These have a type value at the start of the struct */ #define AO_LISP_ATOM 4 #define AO_LISP_BUILTIN 5 -#define AO_LISP_NUM_TYPE 6 +#define AO_LISP_FRAME 6 +#define AO_LISP_NUM_TYPE 7 #define AO_LISP_NIL 0 -#define AO_LISP_POOL 1024 - -extern uint8_t ao_lisp_pool[AO_LISP_POOL]; extern uint16_t ao_lisp_top; #define AO_LISP_OOM 0x01 @@ -68,37 +74,31 @@ ao_lisp_is_const(ao_poly poly) { return poly & AO_LISP_CONST; } +#define AO_LISP_POOL_BASE (ao_lisp_pool - 4) +#define AO_LISP_CONST_BASE (ao_lisp_const - 4) + +#define AO_LISP_IS_CONST(a) (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) +#define AO_LISP_IS_POOL(a) (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) + static inline void * ao_lisp_ref(ao_poly poly) { if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) - return (void *) ((ao_lisp_const - 4) + (poly & AO_LISP_REF_MASK)); - else - return (void *) ((ao_lisp_pool - 4) + (poly & AO_LISP_REF_MASK)); + return (void *) (AO_LISP_CONST_BASE + (poly & AO_LISP_REF_MASK)); + return (void *) (AO_LISP_POOL_BASE + (poly & AO_LISP_REF_MASK)); } static inline ao_poly ao_lisp_poly(const void *addr, ao_poly type) { const uint8_t *a = addr; - if (addr == NULL) + if (a == NULL) return AO_LISP_NIL; - if (ao_lisp_pool <= a && a < ao_lisp_pool + AO_LISP_POOL) - return (a - (ao_lisp_pool - 4)) | type; - else if (ao_lisp_const <= a && a <= ao_lisp_const + AO_LISP_POOL_CONST) - return AO_LISP_CONST | (a - (ao_lisp_const - 4)) | type; - else { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } + if (AO_LISP_IS_CONST(a)) + return AO_LISP_CONST | (a - AO_LISP_CONST_BASE) | type; + return (a - AO_LISP_POOL_BASE) | type; } -#define AO_LISP_POLY(addr, type) (((ao_lisp_pool <= ((uint8_t *) (a)) && \ - ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) ? \ - ((uint8_t *) (a) - (ao_lisp_pool - 4)) : \ - (((uint8_t *) (a) - (ao_lisp_const - 4)) | AO_LISP_POOL_CONST)) | \ - (type)) - struct ao_lisp_type { void (*mark)(void *addr); int (*size)(void *addr); @@ -113,11 +113,32 @@ struct ao_lisp_cons { struct ao_lisp_atom { uint8_t type; uint8_t pad[1]; - ao_poly val; ao_poly next; char name[]; }; +struct ao_lisp_val { + ao_poly atom; + ao_poly val; +}; + +struct ao_lisp_frame { + uint8_t num; + uint8_t readonly; + ao_poly next; + struct ao_lisp_val vals[]; +}; + +static inline struct ao_lisp_frame * +ao_lisp_poly_frame(ao_poly poly) { + return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_frame_poly(struct ao_lisp_frame *frame) { + return ao_lisp_poly(frame, AO_LISP_OTHER); +} + #define AO_LISP_LAMBDA 0 #define AO_LISP_NLAMBDA 1 #define AO_LISP_MACRO 2 @@ -160,6 +181,11 @@ ao_lisp_poly_other(ao_poly poly) { return ao_lisp_ref(poly); } +static inline uint8_t +ao_lisp_other_type(void *other) { + return *((uint8_t *) other); +} + static inline ao_poly ao_lisp_other_poly(const void *other) { @@ -175,9 +201,9 @@ ao_lisp_mem_round(int size) #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) static inline int ao_lisp_poly_type(ao_poly poly) { - int type = poly & 3; + int type = poly & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) - return *((uint8_t *) ao_lisp_poly_other(poly)); + return ao_lisp_other_type(ao_lisp_poly_other(poly)); return type; } @@ -249,6 +275,9 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr); int ao_lisp_mark_memory(void *addr, int size); +void * +ao_lisp_move_map(void *addr); + void * ao_lisp_move(const struct ao_lisp_type *type, void *addr); @@ -259,6 +288,9 @@ ao_lisp_move_memory(void *addr, int size); void * ao_lisp_alloc(int size); +void +ao_lisp_collect(void); + int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); @@ -303,6 +335,12 @@ ao_lisp_atom_print(ao_poly a); struct ao_lisp_atom * ao_lisp_atom_intern(char *name); +ao_poly +ao_lisp_atom_get(ao_poly atom); + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val); + /* int */ void ao_lisp_int_print(ao_poly i); @@ -325,6 +363,8 @@ ao_lisp_eval(ao_poly p); void ao_lisp_builtin_print(ao_poly b); +extern const struct ao_lisp_type ao_lisp_builtin_type; + /* read */ ao_poly ao_lisp_read(void); @@ -333,4 +373,19 @@ ao_lisp_read(void); ao_poly ao_lisp_read_eval_print(void); +/* frame */ +extern const struct ao_lisp_type ao_lisp_frame_type; + +int +ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); + +ao_poly +ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom); + +struct ao_lisp_frame * +ao_lisp_frame_new(int num, int readonly); + +struct ao_lisp_frame * +ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index aaa84b8d..e5d28c3b 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -17,6 +17,12 @@ #include "ao_lisp.h" +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + static int name_size(char *name) { return sizeof(struct ao_lisp_atom) + strlen(name) + 1; @@ -34,31 +40,38 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; + DBG ("\tatom start %s\n", atom->name); for (;;) { - ao_lisp_poly_mark(atom->val); atom = ao_lisp_poly_atom(atom->next); if (!atom) break; + DBG("\t\tatom mark %s %d\n", atom->name, (uint8_t *) atom - ao_lisp_const); if (ao_lisp_mark_memory(atom, atom_size(atom))) break; } + DBG ("\tatom done\n"); } static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; + DBG("\tatom move start %s %d next %s %d\n", + atom->name, ((uint8_t *) atom - ao_lisp_const), + atom->next ? ao_lisp_poly_atom(atom->next)->name : "(none)", + atom->next ? ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const) : 0); for (;;) { struct ao_lisp_atom *next; - atom->val = ao_lisp_poly_move(atom->val); next = ao_lisp_poly_atom(atom->next); next = ao_lisp_move_memory(next, atom_size(next)); if (!next) break; + DBG("\t\tatom move %s %d->%d\n", next->name, ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const), ((uint8_t *) next - ao_lisp_const)); atom->next = ao_lisp_atom_poly(next); atom = next; } + DBG("\tatom move end\n"); } const struct ao_lisp_type ao_lisp_atom_type = { @@ -73,7 +86,6 @@ struct ao_lisp_atom * ao_lisp_atom_intern(char *name) { struct ao_lisp_atom *atom; -// int b; for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) { if (!strcmp(atom->name, name)) @@ -85,19 +97,46 @@ ao_lisp_atom_intern(char *name) return atom; } #endif - if (!ao_lisp_atoms) - ao_lisp_root_add(&ao_lisp_atom_type, (void **) &ao_lisp_atoms); atom = ao_lisp_alloc(name_size(name)); if (atom) { atom->type = AO_LISP_ATOM; atom->next = ao_lisp_atom_poly(ao_lisp_atoms); + if (!ao_lisp_atoms) + ao_lisp_root_add(&ao_lisp_atom_type, &ao_lisp_atoms); ao_lisp_atoms = atom; strcpy(atom->name, name); - atom->val = AO_LISP_NIL; } return atom; } +static struct ao_lisp_frame *globals; + +ao_poly +ao_lisp_atom_get(ao_poly atom) +{ + struct ao_lisp_frame *frame = globals; +#ifdef ao_builtin_frame + if (!frame) + frame = ao_lisp_poly_frame(ao_builtin_frame); +#endif + return ao_lisp_frame_get(frame, atom); +} + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val) +{ + if (!ao_lisp_frame_set(globals, atom, val)) { + globals = ao_lisp_frame_add(globals, atom, val); + if (!globals->next) { + ao_lisp_root_add(&ao_lisp_frame_type, &globals); +#ifdef ao_builtin_frame + globals->next = ao_builtin_frame; +#endif + } + } + return val; +} + void ao_lisp_atom_print(ao_poly a) { diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 63fb69fd..8c481793 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -14,6 +14,31 @@ #include "ao_lisp.h" +static int +builtin_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_builtin); +} + +static void +builtin_mark(void *addr) +{ + (void) addr; +} + +static void +builtin_move(void *addr) +{ + (void) addr; +} + +const struct ao_lisp_type ao_lisp_builtin_type = { + .size = builtin_size, + .mark = builtin_mark, + .move = builtin_move +}; + void ao_lisp_builtin_print(ao_poly b) { @@ -120,20 +145,12 @@ ao_lisp_quote(struct ao_lisp_cons *cons) ao_poly ao_lisp_set(struct ao_lisp_cons *cons) { - ao_poly atom, val; if (!check_argc(cons, 2, 2)) return AO_LISP_NIL; if (!check_argt(cons, 0, AO_LISP_ATOM, 0)) return AO_LISP_NIL; - atom = cons->car; - val = ao_lisp_poly_cons(cons->cdr)->car; - if (ao_lisp_is_const(atom)) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } - ao_lisp_poly_atom(atom)->val = val; - return val; + return ao_lisp_atom_set(cons->car, ao_lisp_poly_cons(cons->cdr)->car); } ao_poly @@ -157,6 +174,8 @@ ao_lisp_print(struct ao_lisp_cons *cons) val = cons->car; ao_lisp_poly_print(val); cons = ao_lisp_poly_cons(cons->cdr); + if (cons) + printf(" "); } return val; } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 65908e30..f8a34ed4 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -14,6 +14,23 @@ #include "ao_lisp.h" +#define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) + +#if 0 +static int cons_depth; +#define DBG(...) do { int d; for (d = 0; d < cons_depth; d++) printf (" "); printf(__VA_ARGS__); } while(0) +#define DBG_IN() (cons_depth++) +#define DBG_OUT() (cons_depth--) +#define DBG_PR(c) ao_lisp_cons_print(ao_lisp_cons_poly(c)) +#define DBG_PRP(p) ao_lisp_poly_print(p) +#else +#define DBG(...) +#define DBG_IN() +#define DBG_OUT() +#define DBG_PR(c) +#define DBG_PRP(p) +#endif + static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -38,17 +55,25 @@ static void cons_move(void *addr) { struct ao_lisp_cons *cons = addr; + DBG_IN(); + DBG("move cons start %d\n", OFFSET(cons)); for (;;) { struct ao_lisp_cons *cdr; + ao_poly car; - cons->car = ao_lisp_poly_move(cons->car); + car = ao_lisp_poly_move(cons->car); + DBG(" moved car %d -> %d\n", OFFSET(ao_lisp_ref(cons->car)), OFFSET(ao_lisp_ref(car))); + cons->car = car; cdr = ao_lisp_poly_cons(cons->cdr); cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); if (!cdr) break; + DBG(" moved cdr %d -> %d\n", OFFSET(ao_lisp_poly_cons(cons->cdr)), OFFSET(cdr)); cons->cdr = ao_lisp_cons_poly(cdr); cons = cdr; } + DBG("move cons end\n"); + DBG_OUT(); } const struct ao_lisp_type ao_lisp_cons_type = { diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 2374fdb2..6eef1f23 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -91,7 +91,7 @@ ao_lisp_eval(ao_poly v) case AO_LISP_STRING: break; case AO_LISP_ATOM: - v = ao_lisp_poly_atom(v)->val; + v = ao_lisp_atom_get(v); break; } @@ -187,6 +187,9 @@ ao_lisp_eval(ao_poly v) DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); } else { + actuals = 0; + formals = 0; + formals_tail = 0; DBG("done func\n"); break; } diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c new file mode 100644 index 00000000..5aa50f6b --- /dev/null +++ b/src/lisp/ao_lisp_frame.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + +static inline int +frame_num_size(int num) +{ + return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val); +} + +static int +frame_size(void *addr) +{ + struct ao_lisp_frame *frame = addr; + return frame_num_size(frame->num); +} + +#define OFFSET(a) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const) + +static void +frame_mark(void *addr) +{ + struct ao_lisp_frame *frame = addr; + int f; + + for (;;) { + if (frame->readonly) + break; + for (f = 0; f < frame->num; f++) { + struct ao_lisp_val *v = &frame->vals[f]; + + ao_lisp_poly_mark(v->atom); + ao_lisp_poly_mark(v->val); + DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); + } + frame = ao_lisp_poly_frame(frame->next); + if (!frame) + break; + if (ao_lisp_mark_memory(frame, frame_size(frame))) + break; + } +} + +static void +frame_move(void *addr) +{ + struct ao_lisp_frame *frame = addr; + int f; + + for (;;) { + struct ao_lisp_frame *next; + if (frame->readonly) + break; + for (f = 0; f < frame->num; f++) { + struct ao_lisp_val *v = &frame->vals[f]; + ao_poly t; + + t = ao_lisp_poly_move(v->atom); + DBG("\t\tatom %s %d -> %d\n", ao_lisp_poly_atom(t)->name, OFFSET(v->atom), OFFSET(t)); + v->atom = t; + t = ao_lisp_poly_move(v->val); + DBG("\t\tval %d -> %d\n", OFFSET(v->val), OFFSET(t)); + v->val = t; + } + next = ao_lisp_poly_frame(frame->next); + if (!next) + break; + next = ao_lisp_move_memory(next, frame_size(next)); + frame->next = ao_lisp_frame_poly(next); + frame = next; + } +} + +const struct ao_lisp_type ao_lisp_frame_type = { + .mark = frame_mark, + .size = frame_size, + .move = frame_move +}; + +static ao_poly * +ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) +{ + int f; + for (f = 0; f < frame->num; f++) + if (frame->vals[f].atom == atom) + return &frame->vals[f].val; + return NULL; +} + +int +ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +{ + while (frame) { + if (!frame->readonly) { + ao_poly *ref = ao_lisp_frame_ref(frame, atom); + if (ref) { + *ref = val; + return 1; + } + } + frame = ao_lisp_poly_frame(frame->next); + } + return 0; +} + +ao_poly +ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) +{ + while (frame) { + ao_poly *ref = ao_lisp_frame_ref(frame, atom); + if (ref) + return *ref; + frame = ao_lisp_poly_frame(frame->next); + } + return AO_LISP_NIL; +} + +struct ao_lisp_frame * +ao_lisp_frame_new(int num, int readonly) +{ + struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num)); + + if (!frame) + return NULL; + frame->num = num; + frame->readonly = readonly; + frame->next = AO_LISP_NIL; + memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); + return frame; +} + +static struct ao_lisp_frame * +ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num, int readonly) +{ + struct ao_lisp_frame *new; + int copy; + + if (new_num == frame->num) + return frame; + new = ao_lisp_frame_new(new_num, readonly); + if (!new) + return NULL; + copy = new_num; + if (copy > frame->num) + copy = frame->num; + memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); + if (frame) + new->next = frame->next; + return new; +} + +struct ao_lisp_frame * +ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +{ + ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL; + if (!ref) { + int f; + if (frame) { + f = frame->num; + frame = ao_lisp_frame_realloc(frame, f + 1, frame->readonly); + } else { + f = 0; + frame = ao_lisp_frame_new(1, 0); + } + if (!frame) + return NULL; + DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); + frame->vals[f].atom = atom; + ref = &frame->vals[f].val; + } + *ref = val; + return frame; +} diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 8d3e03a9..6b603979 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -49,19 +49,43 @@ struct builtin_func funcs[] = { #define N_FUNC (sizeof funcs / sizeof funcs[0]) +struct ao_lisp_frame *globals; + +static int +is_atom(int offset) +{ + struct ao_lisp_atom *a; + + for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) + if (((uint8_t *) a->name - ao_lisp_const) == offset) + return strlen(a->name); + return 0; +} + int main(int argc, char **argv) { int f, o; ao_poly atom, val; struct ao_lisp_atom *a; + int in_atom; + printf("/*\n"); + printf(" * Generated file, do not edit\n"); + ao_lisp_root_add(&ao_lisp_frame_type, &globals); + globals = ao_lisp_frame_new(0, 0); for (f = 0; f < N_FUNC; f++) { struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); struct ao_lisp_atom *a = ao_lisp_atom_intern(funcs[f].name); - a->val = ao_lisp_builtin_poly(b); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_builtin_poly(b)); } + /* boolean constants */ + a = ao_lisp_atom_intern("nil"); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), AO_LISP_NIL); + a = ao_lisp_atom_intern("t"); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_atom_poly(a)); + for (;;) { atom = ao_lisp_read(); if (!atom) @@ -73,13 +97,19 @@ main(int argc, char **argv) fprintf(stderr, "input must be atom val pairs\n"); exit(1); } - ao_lisp_poly_atom(atom)->val = val; + globals = ao_lisp_frame_add(globals, atom, val); } - printf("/* constant objects, all referenced from atoms */\n\n"); + /* Reduce to referenced values */ + ao_lisp_collect(); + printf(" */\n"); + + globals->readonly = 1; + printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(globals)); for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { char *n = a->name, c; @@ -101,10 +131,14 @@ main(int argc, char **argv) else printf(" "); c = ao_lisp_const[o]; - if (' ' < c && c <= '~' && c != '\'') + if (!in_atom) + in_atom = is_atom(o); + if (in_atom) { printf (" '%c',", c); - else + in_atom--; + } else { printf("0x%02x,", c); + } } printf("\n};\n"); printf("#endif /* AO_LISP_CONST_BITS */\n"); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 7295d150..27f5b666 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -17,11 +17,32 @@ #include "ao_lisp.h" #include -uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); - #ifdef AO_LISP_MAKE_CONST #include uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#define ao_lisp_pool ao_lisp_const +#undef AO_LISP_POOL +#define AO_LISP_POOL AO_LISP_POOL_CONST +#else +uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); +#endif + +#if 0 +#define DBG_DUMP +#define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) +#define DBG(...) printf(__VA_ARGS__) +static int move_dump; +static int move_depth; +#define DBG_RESET() (move_depth = 0) +#define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define DBG_MOVE_IN() (move_depth++) +#define DBG_MOVE_OUT() (move_depth--) +#else +#define DBG(...) +#define DBG_RESET() +#define DBG_MOVE(...) +#define DBG_MOVE_IN() +#define DBG_MOVE_OUT() #endif uint8_t ao_lisp_exception; @@ -112,6 +133,23 @@ clear_object(uint8_t *tag, void *addr, int size) { return 0; } +static int +busy_object(uint8_t *tag, void *addr) { + int base; + + if (!addr) + return 1; + + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + base = limit(base); + if (busy(tag, base)) + return 1; + return 0; +} + static void *move_old, *move_new; static int move_size; @@ -120,53 +158,96 @@ move_object(void) { int i; + DBG_RESET(); + DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); + DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr) { + if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { void *new; + DBG_MOVE("root %d\n", DBG_OFFSET(*ao_lisp_root[i].addr)); new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); if (new) *ao_lisp_root[i].addr = new; } + DBG_MOVE_OUT(); + DBG_MOVE("move done\n"); } +#ifdef DBG_DUMP static void -collect(void) +dump_busy(void) +{ + int i; + printf("busy:"); + for (i = 0; i < ao_lisp_top; i += 4) { + if ((i & 0xff) == 0) + printf("\n"); + else if ((i & 0x1f) == 0) + printf(" "); + if (busy(ao_lisp_busy, i)) + putchar('*'); + else + putchar('-'); + } + printf ("\n"); +} +#define DUMP_BUSY() dump_busy() +#else +#define DUMP_BUSY() +#endif + +void +ao_lisp_collect(void) { int i; + int top; /* Mark */ memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + DBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr) + if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { + DBG("root %p\n", *ao_lisp_root[i].addr); ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + } + DUMP_BUSY(); /* Compact */ - ao_lisp_top = 0; - for (i = 0; i < AO_LISP_POOL; i += 4) { + DBG("find first busy\n"); + for (i = 0; i < ao_lisp_top; i += 4) { if (!busy(ao_lisp_busy, i)) break; } - ao_lisp_top = i; - while(i < AO_LISP_POOL) { + top = i; + while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { + DBG("busy %d -> %d\n", i, top); move_old = &ao_lisp_pool[i]; - move_new = &ao_lisp_pool[ao_lisp_top]; + move_new = &ao_lisp_pool[top]; move_size = 0; move_object(); + DBG("\tbusy size %d\n", move_size); + if (move_size == 0) + abort(); clear_object(ao_lisp_busy, move_old, move_size); + mark_object(ao_lisp_busy, move_new, move_size); i += move_size; - ao_lisp_top += move_size; + top += move_size; + DUMP_BUSY(); } else { i += 4; } } + ao_lisp_top = top; } void ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { + if (!addr) + return; if (mark_object(ao_lisp_busy, addr, type->size(addr))) return; type->mark(addr); @@ -178,12 +259,32 @@ ao_lisp_mark_memory(void *addr, int size) return mark_object(ao_lisp_busy, addr, size); } +/* + * After the object has been moved, we have to reference it + * in the new location. This is only relevant for ao_lisp_poly_move + * as it needs to fetch the type byte from the object, which + * may have been overwritten by the copy + */ +void * +ao_lisp_move_map(void *addr) +{ + if (addr == move_old) { + if (busy_object(ao_lisp_moving, addr)) + return move_new; + } + return addr; +} + static void * check_move(void *addr, int size) { if (addr == move_old) { - memmove(move_new, move_old, size); - move_size = (size + 3) & ~3; + DBG_MOVE("mapping %d -> %d\n", DBG_OFFSET(addr), DBG_OFFSET(move_new)); + if (!busy_object(ao_lisp_moving, addr)) { + DBG_MOVE(" copy %d\n", size); + memmove(move_new, move_old, size); + move_size = (size + 3) & ~3; + } addr = move_new; } return addr; @@ -192,15 +293,32 @@ check_move(void *addr, int size) void * ao_lisp_move(const struct ao_lisp_type *type, void *addr) { + uint8_t *a = addr; int size = type->size(addr); if (!addr) return NULL; +#ifndef AO_LISP_MAKE_CONST + if (AO_LISP_IS_CONST(addr)) + return addr; +#endif + DBG_MOVE("object %d\n", DBG_OFFSET(addr)); + if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) + abort(); + DBG_MOVE_IN(); addr = check_move(addr, size); - if (mark_object(ao_lisp_moving, addr, size)) + if (mark_object(ao_lisp_moving, addr, size)) { + DBG_MOVE("already moved\n"); + DBG_MOVE_OUT(); return addr; + } + DBG_MOVE_OUT(); + DBG_MOVE("recursing...\n"); + DBG_MOVE_IN(); type->move(addr); + DBG_MOVE_OUT(); + DBG_MOVE("done %d\n", DBG_OFFSET(addr)); return addr; } @@ -210,9 +328,15 @@ ao_lisp_move_memory(void *addr, int size) if (!addr) return NULL; + DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); + DBG_MOVE_IN(); addr = check_move(addr, size); - if (mark_object(ao_lisp_moving, addr, size)) - return NULL; + if (mark_object(ao_lisp_moving, addr, size)) { + DBG_MOVE("already moved\n"); + DBG_MOVE_OUT(); + return addr; + } + DBG_MOVE_OUT(); return addr; } @@ -222,22 +346,14 @@ ao_lisp_alloc(int size) void *addr; size = ao_lisp_mem_round(size); -#ifdef AO_LISP_MAKE_CONST - if (ao_lisp_top + size > AO_LISP_POOL_CONST) { - fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n"); - exit(1); - } - addr = ao_lisp_const + ao_lisp_top; -#else if (ao_lisp_top + size > AO_LISP_POOL) { - collect(); + ao_lisp_collect(); if (ao_lisp_top + size > AO_LISP_POOL) { ao_lisp_exception |= AO_LISP_OOM; return NULL; } } addr = ao_lisp_pool + ao_lisp_top; -#endif ao_lisp_top += size; return addr; } @@ -246,6 +362,7 @@ int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; + DBG("add root type %p addr %p\n", type, addr); for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) { ao_lisp_root[i].addr = addr; @@ -253,6 +370,7 @@ ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) return 1; } } + abort(); return 0; } diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 38dcb961..e9367553 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -31,35 +31,32 @@ ao_lisp_poly_print(ao_poly p) return p; } +static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_ATOM] = &ao_lisp_atom_type, + [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, +}; + void ao_lisp_poly_mark(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - ao_lisp_mark(&ao_lisp_cons_type, ao_lisp_poly_cons(p)); - break; - case AO_LISP_STRING: - ao_lisp_mark(&ao_lisp_string_type, ao_lisp_poly_string(p)); - break; - case AO_LISP_ATOM: - ao_lisp_mark(&ao_lisp_atom_type, ao_lisp_poly_atom(p)); - break; - } + const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (lisp_type) + ao_lisp_mark(lisp_type, ao_lisp_ref(p)); } ao_poly ao_lisp_poly_move(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - p = ao_lisp_cons_poly(ao_lisp_move(&ao_lisp_cons_type, ao_lisp_poly_cons(p))); - break; - case AO_LISP_STRING: - p = ao_lisp_string_poly(ao_lisp_move(&ao_lisp_string_type, ao_lisp_poly_string(p))); - break; - case AO_LISP_ATOM: - p = ao_lisp_atom_poly(ao_lisp_move(&ao_lisp_atom_type, ao_lisp_poly_atom(p))); - break; - } + uint8_t type = p & AO_LISP_TYPE_MASK; + const struct ao_lisp_type *lisp_type; + + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + + lisp_type = ao_lisp_types[type]; + if (lisp_type) + p = ao_lisp_poly(ao_lisp_move(lisp_type, ao_lisp_ref(p)), p & AO_LISP_TYPE_MASK); return p; } diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index 8fc134e5..bc1eb36b 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -188,8 +188,6 @@ lex_quoted (void) int count; c = lex_get(); -// if (jumping) -// return nil; if (c == EOF) return EOF; c &= 0x7f; @@ -218,8 +216,6 @@ lex_quoted (void) count = 1; while (count <= 3) { c = lex_get(); -// if (jumping) -// return nil; if (c == EOF) return EOF; c &= 0x7f; @@ -288,11 +284,17 @@ lex(void) if (lex_class & ENDOFFILE) return AO_LISP_NIL; -// if (jumping) -// return nil; if (lex_class & WHITE) continue; + if (lex_class & COMMENT) { + while ((c = lexc()) != '\n') { + if (lex_class & ENDOFFILE) + return AO_LISP_NIL; + } + continue; + } + if (lex_class & (BRA|KET|QUOTEC)) { add_token(c); end_token(); @@ -312,8 +314,6 @@ lex(void) if (lex_class & STRINGC) { for (;;) { c = lexc(); -// if (jumping) -// return nil; if (lex_class & (STRINGC|ENDOFFILE)) { end_token(); return STRING; @@ -349,8 +349,6 @@ lex(void) } add_token (c); c = lexc (); -// if (jumping) -// return nil; if (lex_class & (NOTNAME)) { // if (lex_class & ENDOFFILE) // clearerr (f); @@ -403,6 +401,10 @@ pop_read_stack(int cons) read_cons_tail && read_cons_tail->cdr; read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) ; + } else { + read_cons = 0; + read_cons_tail = 0; + read_stack = 0; } return in_quote; } @@ -420,6 +422,7 @@ ao_lisp_read(void) ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); + been_here = 1; } parse_token = lex(); diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index 0df44317..1b7e0bb0 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -13,6 +13,8 @@ INC = \ ao_pins.h \ ao_product.h \ ao_task.h \ + ao_lisp.h \ + ao_lisp_const.h \ stm32f0.h \ Makefile @@ -43,6 +45,7 @@ ALTOS_SRC = \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ + ao_lisp_frame.c \ ao_exti_stm.c PRODUCT=Nucleo-32 diff --git a/src/test/Makefile b/src/test/Makefile index 6c51c421..bd195161 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -91,7 +91,9 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h #AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o -AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ + ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o \ + ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 810a1528..e303869f 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -36,7 +36,6 @@ main (int argc, char **argv) list = ao_lisp_cons_cons(ao_lisp_string_poly(string), list); list = ao_lisp_cons_cons(ao_lisp_int_poly(i), list); atom = ao_lisp_atom_intern("ant"); - atom->val = ao_lisp_cons_poly(list); list = ao_lisp_cons_cons(ao_lisp_atom_poly(atom), list); } ao_lisp_poly_print(ao_lisp_cons_poly(list)); @@ -45,7 +44,7 @@ main (int argc, char **argv) for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { printf("%s = ", atom->name); - ao_lisp_poly_print(atom->val); + ao_lisp_poly_print(ao_lisp_atom_get(ao_lisp_atom_poly(atom))); printf("\n"); } #if 1 -- cgit v1.2.3 From 3366efb139653939f053c1fe4aba352ba3b66c94 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Nov 2016 14:51:58 -0700 Subject: altos/lisp: Change GC move API Pass reference to move API so it can change the values in-place, then let it return '1' when the underlying object has already been moved to shorten GC times. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 38 +++-- src/lisp/ao_lisp_atom.c | 26 +--- src/lisp/ao_lisp_builtin.c | 142 +++++++++++++++-- src/lisp/ao_lisp_cons.c | 37 +---- src/lisp/ao_lisp_const.lisp | 3 + src/lisp/ao_lisp_eval.c | 349 ++++++++++++------------------------------ src/lisp/ao_lisp_frame.c | 48 +++--- src/lisp/ao_lisp_make_const.c | 11 +- src/lisp/ao_lisp_mem.c | 169 ++++++++++++++++---- src/lisp/ao_lisp_prim.c | 44 +++++- 10 files changed, 464 insertions(+), 403 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 9a5cc63e..27174e13 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -46,7 +46,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL -#define AO_LISP_POOL 1024 +#define AO_LISP_POOL 16384 #endif extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #endif @@ -94,6 +94,8 @@ ao_lisp_is_const(ao_poly poly) { static inline void * ao_lisp_ref(ao_poly poly) { + if (poly == 0xBEEF) + abort(); if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) @@ -135,8 +137,8 @@ struct ao_lisp_val { }; struct ao_lisp_frame { + uint8_t type; uint8_t num; - uint8_t readonly; ao_poly next; struct ao_lisp_val vals[]; }; @@ -176,6 +178,11 @@ enum ao_lisp_builtin_id { builtin_times, builtin_divide, builtin_mod, + builtin_equal, + builtin_less, + builtin_greater, + builtin_less_equal, + builtin_greater_equal, builtin_last }; @@ -281,7 +288,8 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) } /* memory functions */ -void +/* returns 1 if the object was already marked */ +int ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ @@ -291,12 +299,13 @@ ao_lisp_mark_memory(void *addr, int size); void * ao_lisp_move_map(void *addr); -void * -ao_lisp_move(const struct ao_lisp_type *type, void *addr); +/* returns 1 if the object was already moved */ +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref); -/* returns NULL if the object was already moved */ -void * -ao_lisp_move_memory(void *addr, int size); +/* returns 1 if the object was already moved */ +int +ao_lisp_move_memory(void **ref, int size); void * ao_lisp_alloc(int size); @@ -307,6 +316,9 @@ ao_lisp_collect(void); int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); +int +ao_lisp_root_poly_add(ao_poly *p); + void ao_lisp_root_clear(void *addr); @@ -361,13 +373,15 @@ ao_lisp_int_print(ao_poly i); ao_poly ao_lisp_poly_print(ao_poly p); -void +int ao_lisp_poly_mark(ao_poly p); -ao_poly -ao_lisp_poly_move(ao_poly p); +/* returns 1 if the object has already been moved */ +int +ao_lisp_poly_move(ao_poly *p); /* eval */ + ao_poly ao_lisp_eval(ao_poly p); @@ -407,7 +421,7 @@ ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * -ao_lisp_frame_new(int num, int readonly); +ao_lisp_frame_new(int num); struct ao_lisp_frame * ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index ea04741e..5f1bcda0 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -17,12 +17,6 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf(__VA_ARGS__) -#else -#define DBG(...) -#endif - static int name_size(char *name) { return sizeof(struct ao_lisp_atom) + strlen(name) + 1; @@ -40,38 +34,24 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; - DBG ("\tatom start %s\n", atom->name); for (;;) { atom = ao_lisp_poly_atom(atom->next); if (!atom) break; - DBG("\t\tatom mark %s %d\n", atom->name, (uint8_t *) atom - ao_lisp_const); if (ao_lisp_mark_memory(atom, atom_size(atom))) break; } - DBG ("\tatom done\n"); } static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; - DBG("\tatom move start %s %d next %s %d\n", - atom->name, ((uint8_t *) atom - ao_lisp_const), - atom->next ? ao_lisp_poly_atom(atom->next)->name : "(none)", - atom->next ? ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const) : 0); for (;;) { - struct ao_lisp_atom *next; - - next = ao_lisp_poly_atom(atom->next); - next = ao_lisp_move_memory(next, atom_size(next)); - if (!next) + if (ao_lisp_poly_move(&atom->next)) break; - DBG("\t\tatom move %s %d->%d\n", next->name, ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const), ((uint8_t *) next - ao_lisp_const)); - atom->next = ao_lisp_atom_poly(next); - atom = next; + atom = ao_lisp_poly_atom(atom->next); } - DBG("\tatom move end\n"); } const struct ao_lisp_type ao_lisp_atom_type = { @@ -116,7 +96,7 @@ static void ao_lisp_atom_init(void) { if (!ao_lisp_frame_global) { - ao_lisp_frame_global = ao_lisp_frame_new(0, 0); + ao_lisp_frame_global = ao_lisp_frame_new(0); ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_global); ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_current); } diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index fe729f20..0ad1f464 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -63,6 +63,8 @@ ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max) ao_poly ao_lisp_arg(struct ao_lisp_cons *cons, int argc) { + if (!cons) + return AO_LISP_NIL; while (argc--) { if (!cons) return AO_LISP_NIL; @@ -81,8 +83,6 @@ ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, return _ao_lisp_atom_t; } -enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; - ao_poly ao_lisp_car(struct ao_lisp_cons *cons) { @@ -175,11 +175,12 @@ ao_lisp_print(struct ao_lisp_cons *cons) if (cons) printf(" "); } + printf("\n"); return val; } ao_poly -ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) { ao_poly ret = AO_LISP_NIL; @@ -198,30 +199,32 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) int c = ao_lisp_poly_int(car); switch(op) { - case math_plus: + case builtin_plus: r += c; break; - case math_minus: + case builtin_minus: r -= c; break; - case math_times: + case builtin_times: r *= c; break; - case math_divide: + case builtin_divide: if (c == 0) return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero"); r /= c; break; - case math_mod: + case builtin_mod: if (c == 0) return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero"); r %= c; break; + default: + break; } ret = ao_lisp_int_poly(r); } - else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus) ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), ao_lisp_poly_string(car))); else @@ -233,31 +236,135 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) ao_poly ao_lisp_plus(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_plus); + return ao_lisp_math(cons, builtin_plus); } ao_poly ao_lisp_minus(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_minus); + return ao_lisp_math(cons, builtin_minus); } ao_poly ao_lisp_times(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_times); + return ao_lisp_math(cons, builtin_times); } ao_poly ao_lisp_divide(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_divide); + return ao_lisp_math(cons, builtin_divide); } ao_poly ao_lisp_mod(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_mod); + return ao_lisp_math(cons, builtin_mod); +} + +ao_poly +ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) +{ + ao_poly left; + + if (!cons) + return _ao_lisp_atom_t; + + left = cons->car; + cons = ao_lisp_poly_cons(cons->cdr); + while (cons) { + ao_poly right = cons->car; + + if (op == builtin_equal) { + if (left != right) + return AO_LISP_NIL; + } else { + uint8_t lt = ao_lisp_poly_type(left); + uint8_t rt = ao_lisp_poly_type(right); + if (lt == AO_LISP_INT && rt == AO_LISP_INT) { + int l = ao_lisp_poly_int(left); + int r = ao_lisp_poly_int(right); + + switch (op) { + case builtin_less: + if (!(l < r)) + return AO_LISP_NIL; + break; + case builtin_greater: + if (!(l > r)) + return AO_LISP_NIL; + break; + case builtin_less_equal: + if (!(l <= r)) + return AO_LISP_NIL; + break; + case builtin_greater_equal: + if (!(l >= r)) + return AO_LISP_NIL; + break; + default: + break; + } + } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) { + int c = strcmp(ao_lisp_poly_string(left), + ao_lisp_poly_string(right)); + switch (op) { + case builtin_less: + if (!(c < 0)) + return AO_LISP_NIL; + break; + case builtin_greater: + if (!(c > 0)) + return AO_LISP_NIL; + break; + case builtin_less_equal: + if (!(c <= 0)) + return AO_LISP_NIL; + break; + case builtin_greater_equal: + if (!(c >= 0)) + return AO_LISP_NIL; + break; + default: + break; + } + } + } + left = right; + cons = ao_lisp_poly_cons(cons->cdr); + } + return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_equal); +} + +ao_poly +ao_lisp_less(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_less); +} + +ao_poly +ao_lisp_greater(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_greater); +} + +ao_poly +ao_lisp_less_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_less_equal); +} + +ao_poly +ao_lisp_greater_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_greater_equal); } ao_lisp_func_t ao_lisp_builtins[] = { @@ -273,6 +380,11 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_minus] = ao_lisp_minus, [builtin_times] = ao_lisp_times, [builtin_divide] = ao_lisp_divide, - [builtin_mod] = ao_lisp_mod + [builtin_mod] = ao_lisp_mod, + [builtin_equal] = ao_lisp_equal, + [builtin_less] = ao_lisp_less, + [builtin_greater] = ao_lisp_greater, + [builtin_less_equal] = ao_lisp_less_equal, + [builtin_greater_equal] = ao_lisp_greater_equal }; diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index f8a34ed4..4929b91c 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -16,21 +16,6 @@ #define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) -#if 0 -static int cons_depth; -#define DBG(...) do { int d; for (d = 0; d < cons_depth; d++) printf (" "); printf(__VA_ARGS__); } while(0) -#define DBG_IN() (cons_depth++) -#define DBG_OUT() (cons_depth--) -#define DBG_PR(c) ao_lisp_cons_print(ao_lisp_cons_poly(c)) -#define DBG_PRP(p) ao_lisp_poly_print(p) -#else -#define DBG(...) -#define DBG_IN() -#define DBG_OUT() -#define DBG_PR(c) -#define DBG_PRP(p) -#endif - static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -55,25 +40,15 @@ static void cons_move(void *addr) { struct ao_lisp_cons *cons = addr; - DBG_IN(); - DBG("move cons start %d\n", OFFSET(cons)); - for (;;) { - struct ao_lisp_cons *cdr; - ao_poly car; + if (!cons) + return; - car = ao_lisp_poly_move(cons->car); - DBG(" moved car %d -> %d\n", OFFSET(ao_lisp_ref(cons->car)), OFFSET(ao_lisp_ref(car))); - cons->car = car; - cdr = ao_lisp_poly_cons(cons->cdr); - cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); - if (!cdr) + for (;;) { + (void) ao_lisp_poly_move(&cons->car); + if (ao_lisp_poly_move(&cons->cdr)) break; - DBG(" moved cdr %d -> %d\n", OFFSET(ao_lisp_poly_cons(cons->cdr)), OFFSET(cdr)); - cons->cdr = ao_lisp_cons_poly(cdr); - cons = cdr; + cons = ao_lisp_poly_cons(cons->cdr); } - DBG("move cons end\n"); - DBG_OUT(); } const struct ao_lisp_type ao_lisp_cons_type = { diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 5ee15899..5ca89bd4 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -1,4 +1,7 @@ cadr (lambda (l) (car (cdr l))) +caddr (lambda (l) (car (cdr (cdr l)))) list (lexpr (l) l) 1+ (lambda (x) (+ x 1)) 1- (lambda (x) (- x 1)) +last (lambda (x) (cond ((cdr x) (last (cdr x))) ((car x)))) +prog* (lexpr (l) (last l)) diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 2b2cfee7..b7e7b972 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -37,8 +37,11 @@ static int stack_depth; enum eval_state { eval_sexpr, eval_val, + eval_formal, eval_exec, - eval_exec_direct + eval_exec_direct, + eval_cond, + eval_cond_test }; struct ao_lisp_stack { @@ -84,20 +87,26 @@ stack_mark(void *addr) } } +static const struct ao_lisp_type ao_lisp_stack_type; + static void stack_move(void *addr) { struct ao_lisp_stack *stack = addr; - for (;;) { - struct ao_lisp_stack *prev; - stack->actuals = ao_lisp_poly_move(stack->actuals); - stack->formals = ao_lisp_poly_move(stack->formals); - stack->frame = ao_lisp_poly_move(stack->frame); - prev = ao_lisp_ref(stack->prev); - prev = ao_lisp_move_memory(prev, sizeof (struct ao_lisp_stack)); - stack->prev = ao_lisp_stack_poly(prev); - stack = prev; + while (stack) { + void *prev; + int ret; + (void) ao_lisp_poly_move(&stack->actuals); + (void) ao_lisp_poly_move(&stack->formals); + (void) ao_lisp_poly_move(&stack->frame); + prev = ao_lisp_poly_stack(stack->prev); + ret = ao_lisp_move(&ao_lisp_stack_type, &prev); + if (prev != ao_lisp_poly_stack(stack->prev)) + stack->prev = ao_lisp_stack_poly(prev); + if (ret); + break; + stack = ao_lisp_poly_stack(stack->prev); } } @@ -107,17 +116,19 @@ static const struct ao_lisp_type ao_lisp_stack_type = { .move = stack_move }; - static struct ao_lisp_stack *ao_lisp_stack; +static ao_poly ao_lisp_v; static uint8_t been_here; ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { + ao_lisp_stack->state = eval_cond; + ao_lisp_stack->actuals = ao_lisp_cons_poly(c); return AO_LISP_NIL; } -static void +void ao_lisp_stack_reset(struct ao_lisp_stack *stack) { stack->state = eval_sexpr; @@ -128,21 +139,21 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); } -static struct ao_lisp_stack * +struct ao_lisp_stack * ao_lisp_stack_push(void) { struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) return NULL; stack->prev = ao_lisp_stack_poly(ao_lisp_stack); - ao_lisp_stack_reset(stack); ao_lisp_stack = stack; + ao_lisp_stack_reset(stack); DBGI("stack push\n"); DBG_IN(); return stack; } -static struct ao_lisp_stack * +struct ao_lisp_stack * ao_lisp_stack_pop(void) { if (!ao_lisp_stack) @@ -164,7 +175,6 @@ ao_lisp_stack_clear(void) ao_lisp_frame_current = NULL; } - static ao_poly func_type(ao_poly func) { @@ -196,8 +206,11 @@ func_type(ao_poly func) f++; } return ao_lisp_arg(cons, 0); - } else - return ao_lisp_error(AO_LISP_INVALID, "not a func"); + } else { + ao_lisp_error(AO_LISP_INVALID, "not a func"); + abort(); + return AO_LISP_NIL; + } } static int @@ -236,7 +249,7 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) args_provided = 1; if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); - next_frame = ao_lisp_frame_new(args_wanted, 0); + next_frame = ao_lisp_frame_new(args_wanted); DBGI("new frame %d\n", OFFSET(next_frame)); switch (type) { case _ao_lisp_atom_lambda: { @@ -268,14 +281,16 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) } ao_poly -ao_lisp_eval(ao_poly v) +ao_lisp_eval(ao_poly _v) { struct ao_lisp_stack *stack; ao_poly formal; + ao_lisp_v = _v; if (!been_here) { been_here = 1; - ao_lisp_root_add(&ao_lisp_stack_type, &stack); + ao_lisp_root_add(&ao_lisp_stack_type, &ao_lisp_stack); + ao_lisp_root_poly_add(&ao_lisp_v); } stack = ao_lisp_stack_push(); @@ -285,19 +300,20 @@ ao_lisp_eval(ao_poly v) return AO_LISP_NIL; switch (stack->state) { case eval_sexpr: - DBGI("sexpr: "); DBG_POLY(v); DBG("\n"); - switch (ao_lisp_poly_type(v)) { + DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); + switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_CONS: - if (v == AO_LISP_NIL) { + if (ao_lisp_v == AO_LISP_NIL) { stack->state = eval_exec; break; } - stack->actuals = v; + stack->actuals = ao_lisp_v; + stack->state = eval_formal; stack = ao_lisp_stack_push(); - v = ao_lisp_poly_cons(v)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; break; case AO_LISP_ATOM: - v = ao_lisp_atom_get(v); + ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); /* fall through */ case AO_LISP_INT: case AO_LISP_STRING: @@ -306,15 +322,17 @@ ao_lisp_eval(ao_poly v) } break; case eval_val: - DBGI("val: "); DBG_POLY(v); DBG("\n"); + DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); stack = ao_lisp_stack_pop(); if (!stack) - return v; + return ao_lisp_v; + DBGI("..state %d\n", stack->state); + break; - stack->state = eval_sexpr; + case eval_formal: /* Check what kind of function we've got */ if (!stack->formals) { - switch (func_type(v)) { + switch (func_type(ao_lisp_v)) { case AO_LISP_LAMBDA: case _ao_lisp_atom_lambda: case AO_LISP_LEXPR: @@ -335,7 +353,7 @@ ao_lisp_eval(ao_poly v) break; } - formal = ao_lisp_cons_poly(ao_lisp_cons_cons(v, NULL)); + formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); if (!formal) { ao_lisp_stack_clear(); return AO_LISP_NIL; @@ -349,257 +367,78 @@ ao_lisp_eval(ao_poly v) DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n"); - v = ao_lisp_poly_cons(stack->actuals)->cdr; + ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->cdr; + + stack->state = eval_sexpr; break; case eval_exec: - v = ao_lisp_poly_cons(stack->formals)->car; + if (!stack->formals) { + ao_lisp_v = AO_LISP_NIL; + stack->state = eval_val; + break; + } + ao_lisp_v = ao_lisp_poly_cons(stack->formals)->car; case eval_exec_direct: - DBGI("exec: macro %d ", stack->macro); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + DBGI("exec: macro %d ", stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr); DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); - v = ao_lisp_func(b) (f); - DBGI("builtin result:"); DBG_POLY(v); DBG ("\n"); - if (ao_lisp_exception) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } if (stack->macro) stack->state = eval_sexpr; else stack->state = eval_val; stack->macro = 0; + ao_lisp_v = ao_lisp_func(b) (f); + DBGI("builtin result:"); DBG_POLY(ao_lisp_v); DBG ("\n"); + if (ao_lisp_exception) { + ao_lisp_stack_clear(); + return AO_LISP_NIL; + } break; } else { - v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); + ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); ao_lisp_stack_reset(stack); } break; - } - } -} -#if 0 - - - restart: - if (cond) { - DBGI("cond is now "); DBG_CONS(cond); DBG("\n"); - if (cond->car == AO_LISP_NIL) { - cond = AO_LISP_NIL; - v = AO_LISP_NIL; + case eval_cond: + DBGI("cond: "); DBG_POLY(stack->actuals); DBG("\n"); + if (!stack->actuals) { + ao_lisp_v = AO_LISP_NIL; + stack->state = eval_val; } else { - if (ao_lisp_poly_type(cond->car) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "malformed cond"); + ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->car; + if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { + ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); goto bail; } - v = ao_lisp_poly_cons(cond->car)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + stack->state = eval_cond_test; + stack = ao_lisp_stack_push(); + stack->state = eval_sexpr; } - } - - /* Build stack frames for each list */ - while (ao_lisp_poly_type(v) == AO_LISP_CONS) { - if (v == AO_LISP_NIL) - break; - - /* Push existing bits on the stack */ - if (cons++) - if (!ao_lisp_stack_push()) - goto bail; - - actuals = ao_lisp_poly_cons(v); - formals = NULL; - formals_tail = NULL; - save_cond = cond; - cond = NULL; - - v = actuals->car; - -// DBG("start: stack"); DBG_CONS(stack); DBG("\n"); -// DBG("start: actuals"); DBG_CONS(actuals); DBG("\n"); -// DBG("start: formals"); DBG_CONS(formals); DBG("\n"); - } - - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - switch (b->args) { - case AO_LISP_NLAMBDA: - formals = actuals; - goto eval; - - case AO_LISP_MACRO: - v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); - DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); - DBG(" -> "); DBG_POLY(v); - DBG("\n"); - if (ao_lisp_poly_type(v) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); - goto bail; - } - /* Reset frame to the new list */ - actuals = ao_lisp_poly_cons(v); - v = actuals->car; - goto restart; - } - /* Evaluate primitive types */ - - DBG ("actual: "); DBG_POLY(v); DBG("\n"); - - switch (ao_lisp_poly_type(v)) { - case AO_LISP_INT: - case AO_LISP_STRING: break; - case AO_LISP_ATOM: - v = ao_lisp_atom_get(v); - break; - } - - while (cons) { - DBG("add formal: "); DBG_POLY(v); DBG("\n"); - - /* We've processed the first element of the list, go check - * what kind of function we've got - */ - if (formals == NULL) { - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - switch (b->args) { - case AO_LISP_NLAMBDA: - formals = actuals; - goto eval; - - case AO_LISP_MACRO: - v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); - DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); - DBG(" -> "); DBG_POLY(v); - DBG("\n"); - if (ao_lisp_poly_type(v) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); - goto bail; - } - /* Reset frame to the new list */ - actuals = ao_lisp_poly_cons(v); - v = actuals->car; - goto restart; - } + case eval_cond_test: + DBGI("cond_test "); DBG_POLY(ao_lisp_v); DBG("\n"); + if (ao_lisp_v) { + struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->actuals)->car); + struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); + if (c) { + ao_lisp_v = c->car; + stack->state = eval_sexpr; } else { - switch (func_type(v)) { - case _ao_lisp_atom_lambda: - case _ao_lisp_atom_lexpr: - break; - case _ao_lisp_atom_nlambda: - formals = actuals; - goto eval; - case _ao_lisp_atom_macro: - break; - default: - ao_lisp_error(AO_LISP_INVALID, "operator is not a function"); - goto bail; - } - } - } - - formal = ao_lisp_cons_cons(v, NULL); - if (formals_tail) - formals_tail->cdr = ao_lisp_cons_poly(formal); - else - formals = formal; - formals_tail = formal; - actuals = ao_lisp_poly_cons(actuals->cdr); - - DBG("formals: "); - DBG_CONS(formals); - DBG("\n"); - DBG("actuals: "); - DBG_CONS(actuals); - DBG("\n"); - - /* Process all of the arguments */ - if (actuals) { - v = actuals->car; - break; - } - - v = formals->car; - - eval: - - /* Evaluate the resulting list */ - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_cons *old_cond = cond; - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - - v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr)); - - DBG ("eval: "); - DBG_CONS(formals); - DBG(" -> "); - DBG_POLY(v); - DBG ("\n"); - if (ao_lisp_exception) - goto bail; - - if (cond != old_cond) { - DBG("cond changed from "); DBG_CONS(old_cond); DBG(" to "); DBG_CONS(cond); DBG("\n"); - actuals = NULL; - formals = 0; - formals_tail = 0; - save_cons = cons; - cons = 0; - goto restart; - } - } else { - v = ao_lisp_lambda(formals); - if (ao_lisp_exception) - goto bail; - } - - cond_done: - --cons; - if (cons) { - ao_lisp_stack_pop(); -// DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); -// DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); -// DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); - } else { - actuals = 0; - formals = 0; - formals_tail = 0; - ao_lisp_frame_current = 0; - } - if (next_frame) { - ao_lisp_frame_current = next_frame; - DBG("next frame %d\n", OFFSET(next_frame)); - next_frame = 0; - goto restart; - } - } - if (cond) { - DBG("next cond cons is %d\n", cons); - if (v) { - v = ao_lisp_poly_cons(cond->car)->cdr; - cond = 0; - cons = save_cons; - if (v != AO_LISP_NIL) { - v = ao_lisp_poly_cons(v)->car; - DBG("cond complete, sexpr is "); DBG_POLY(v); DBG("\n"); + stack->state = eval_val; } - goto cond_done; } else { - cond = ao_lisp_poly_cons(cond->cdr); - DBG("next cond is "); DBG_CONS(cond); DBG("\n"); - goto restart; + stack->actuals = ao_lisp_poly_cons(stack->actuals)->cdr; + stack->state = eval_cond; } - } - if (!cons) break; + } } - DBG("leaving frame at %d\n", OFFSET(ao_lisp_frame_current)); - return v; bail: ao_lisp_stack_clear(); return AO_LISP_NIL; -#endif - +} diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 1853f6d7..8bf98571 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -33,7 +33,7 @@ frame_size(void *addr) return frame_num_size(frame->num); } -#define OFFSET(a) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const) +#define OFFSET(a) ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const)) static void frame_mark(void *addr) @@ -42,16 +42,19 @@ frame_mark(void *addr) int f; for (;;) { - if (frame->readonly) + DBG("frame mark %p\n", frame); + if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_mark(v->atom); ao_lisp_poly_mark(v->val); - DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); + DBG ("\tframe mark atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + OFFSET(v->atom), OFFSET(v->val), f); } frame = ao_lisp_poly_frame(frame->next); + DBG("frame next %p\n", frame); if (!frame) break; if (ao_lisp_mark_memory(frame, frame_size(frame))) @@ -66,26 +69,19 @@ frame_move(void *addr) int f; for (;;) { - struct ao_lisp_frame *next; - if (frame->readonly) + DBG("frame move %p\n", frame); + if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_poly t; - - t = ao_lisp_poly_move(v->atom); - DBG("\t\tatom %s %d -> %d\n", ao_lisp_poly_atom(t)->name, OFFSET(v->atom), OFFSET(t)); - v->atom = t; - t = ao_lisp_poly_move(v->val); - DBG("\t\tval %d -> %d\n", OFFSET(v->val), OFFSET(t)); - v->val = t; + + ao_lisp_poly_move(&v->atom); + DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); + ao_lisp_poly_move(&v->val); } - next = ao_lisp_poly_frame(frame->next); - if (!next) + if (ao_lisp_poly_move(&frame->next)) break; - next = ao_lisp_move_memory(next, frame_size(next)); - frame->next = ao_lisp_frame_poly(next); - frame = next; + frame = ao_lisp_poly_frame(frame->next); } } @@ -109,7 +105,7 @@ int ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) { while (frame) { - if (!frame->readonly) { + if (!AO_LISP_IS_CONST(frame)) { ao_poly *ref = ao_lisp_frame_ref(frame, atom); if (ref) { *ref = val; @@ -134,28 +130,28 @@ ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) } struct ao_lisp_frame * -ao_lisp_frame_new(int num, int readonly) +ao_lisp_frame_new(int num) { struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num)); if (!frame) return NULL; + frame->type = AO_LISP_FRAME; frame->num = num; - frame->readonly = readonly; frame->next = AO_LISP_NIL; memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); return frame; } static struct ao_lisp_frame * -ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num, int readonly) +ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) { struct ao_lisp_frame *new; int copy; if (new_num == frame->num) return frame; - new = ao_lisp_frame_new(new_num, readonly); + new = ao_lisp_frame_new(new_num); if (!new) return NULL; copy = new_num; @@ -175,10 +171,10 @@ ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) int f; if (frame) { f = frame->num; - frame = ao_lisp_frame_realloc(frame, f + 1, frame->readonly); + frame = ao_lisp_frame_realloc(frame, f + 1); } else { f = 0; - frame = ao_lisp_frame_new(1, 0); + frame = ao_lisp_frame_new(1); } if (!frame) return NULL; diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 9c2ea74c..9768dc22 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -45,7 +45,12 @@ struct builtin_func funcs[] = { "-", AO_LISP_LEXPR, builtin_minus, "*", AO_LISP_LEXPR, builtin_times, "/", AO_LISP_LEXPR, builtin_divide, - "%", AO_LISP_LEXPR, builtin_mod + "%", AO_LISP_LEXPR, builtin_mod, + "=", AO_LISP_LEXPR, builtin_equal, + "<", AO_LISP_LEXPR, builtin_less, + ">", AO_LISP_LEXPR, builtin_greater, + "<=", AO_LISP_LEXPR, builtin_less_equal, + ">=", AO_LISP_LEXPR, builtin_greater_equal, }; ao_poly @@ -92,7 +97,7 @@ main(int argc, char **argv) printf("/*\n"); printf(" * Generated file, do not edit\n"); ao_lisp_root_add(&ao_lisp_frame_type, &globals); - globals = ao_lisp_frame_new(0, 0); + globals = ao_lisp_frame_new(0); for (f = 0; f < N_FUNC; f++) { b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); a = ao_lisp_atom_intern(funcs[f].name); @@ -127,8 +132,6 @@ main(int argc, char **argv) ao_lisp_collect(); printf(" */\n"); - globals->readonly = 1; - printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 27f5b666..29d8dbf4 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -28,9 +28,18 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#define DBG_COLLECT_ALWAYS +#endif + +#if 0 +#define DBG_POOL +#endif + +#if 1 #define DBG_DUMP #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) +#define DBG_DO(a) a static int move_dump; static int move_depth; #define DBG_RESET() (move_depth = 0) @@ -39,6 +48,7 @@ static int move_depth; #define DBG_MOVE_OUT() (move_depth--) #else #define DBG(...) +#define DBG_DO(a) #define DBG_RESET() #define DBG_MOVE(...) #define DBG_MOVE_IN() @@ -162,14 +172,24 @@ move_object(void) DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); - for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { - void *new; - DBG_MOVE("root %d\n", DBG_OFFSET(*ao_lisp_root[i].addr)); - new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); - if (new) - *ao_lisp_root[i].addr = new; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (!ao_lisp_root[i].addr) + continue; + if (ao_lisp_root[i].type) { + DBG_DO(void *addr = *ao_lisp_root[i].addr); + DBG_MOVE("root %d\n", DBG_OFFSET(addr)); + if (!ao_lisp_move(ao_lisp_root[i].type, + ao_lisp_root[i].addr)) + DBG_MOVE("root moves from %p to %p\n", + addr, + *ao_lisp_root[i].addr); + } else { + DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) + DBG_MOVE("root poly move from %04x to %04x\n", + p, *(ao_poly *) ao_lisp_root[i].addr); } + } DBG_MOVE_OUT(); DBG_MOVE("move done\n"); } @@ -197,20 +217,39 @@ dump_busy(void) #define DUMP_BUSY() #endif +static void +ao_lisp_mark_busy(void) +{ + int i; + + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + DBG("mark\n"); + for (i = 0; i < AO_LISP_ROOT; i++) { + if (ao_lisp_root[i].type) { + void **a = ao_lisp_root[i].addr, *v; + if (a && (v = *a)) { + DBG("root %p\n", v); + ao_lisp_mark(ao_lisp_root[i].type, v); + } + } else { + ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; + if (a && (p = *a)) { + DBG("root %04x\n", p); + ao_lisp_poly_mark(p); + } + } + } +} + void ao_lisp_collect(void) { int i; int top; + DBG("collect\n"); /* Mark */ - memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); - DBG("mark\n"); - for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { - DBG("root %p\n", *ao_lisp_root[i].addr); - ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); - } + ao_lisp_mark_busy(); DUMP_BUSY(); /* Compact */ @@ -243,14 +282,15 @@ ao_lisp_collect(void) } -void +int ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (!addr) - return; + return 1; if (mark_object(ao_lisp_busy, addr, type->size(addr))) - return; + return 1; type->mark(addr); + return 0; } int @@ -290,28 +330,31 @@ check_move(void *addr, int size) return addr; } -void * -ao_lisp_move(const struct ao_lisp_type *type, void *addr) +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref) { - uint8_t *a = addr; - int size = type->size(addr); + void *addr = *ref; + uint8_t *a = addr; + int size = type->size(addr); if (!addr) return NULL; #ifndef AO_LISP_MAKE_CONST if (AO_LISP_IS_CONST(addr)) - return addr; + return 1; #endif DBG_MOVE("object %d\n", DBG_OFFSET(addr)); if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) abort(); DBG_MOVE_IN(); addr = check_move(addr, size); + if (addr != *ref) + *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { DBG_MOVE("already moved\n"); DBG_MOVE_OUT(); - return addr; + return 1; } DBG_MOVE_OUT(); DBG_MOVE("recursing...\n"); @@ -319,35 +362,97 @@ ao_lisp_move(const struct ao_lisp_type *type, void *addr) type->move(addr); DBG_MOVE_OUT(); DBG_MOVE("done %d\n", DBG_OFFSET(addr)); - return addr; + return 0; } -void * -ao_lisp_move_memory(void *addr, int size) +int +ao_lisp_move_memory(void **ref, int size) { + void *addr = *ref; if (!addr) return NULL; DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); DBG_MOVE_IN(); addr = check_move(addr, size); + if (addr != *ref) + *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { DBG_MOVE("already moved\n"); DBG_MOVE_OUT(); - return addr; + return 1; } DBG_MOVE_OUT(); - return addr; + return 0; +} + +#ifdef DBG_POOL +static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; + +static void +ao_lisp_poison(void) +{ + int i; + + printf("poison\n"); + ao_lisp_mark_busy(); + for (i = 0; i < AO_LISP_POOL_CUR; i += 4) { + uint32_t *a = (uint32_t *) &ao_lisp_pool[i]; + if (!busy_object(ao_lisp_busy, a)) + *a = 0xBEEFBEEF; + } + for (i = 0; i < AO_LISP_POOL_CUR; i += 2) { + ao_poly *a = (uint16_t *) &ao_lisp_pool[i]; + ao_poly p = *a; + + if (!ao_lisp_is_const(p)) { + void *r = ao_lisp_ref(p); + + if (ao_lisp_pool <= (uint8_t *) r && + (uint8_t *) r <= ao_lisp_pool + AO_LISP_POOL_CUR) + { + if (!busy_object(ao_lisp_busy, r)) { + printf("missing reference from %d to %d\n", + (int) ((uint8_t *) a - ao_lisp_pool), + (int) ((uint8_t *) r - ao_lisp_pool)); + } + } + } + } } +#else +#define AO_LISP_POOL_CUR AO_LISP_POOL +#endif + void * ao_lisp_alloc(int size) { void *addr; size = ao_lisp_mem_round(size); - if (ao_lisp_top + size > AO_LISP_POOL) { +#ifdef DBG_COLLECT_ALWAYS + ao_lisp_collect(); +#endif + if (ao_lisp_top + size > AO_LISP_POOL_CUR) { +#ifdef DBG_POOL + if (AO_LISP_POOL_CUR < AO_LISP_POOL) { + AO_LISP_POOL_CUR += AO_LISP_POOL / 8; + ao_lisp_poison(); + } else +#endif ao_lisp_collect(); +#ifdef DBG_POOL + { + int i; + + for (i = ao_lisp_top; i < AO_LISP_POOL; i += 4) { + uint32_t *p = (uint32_t *) &ao_lisp_pool[i]; + *p = 0xbeefbeef; + } + } +#endif + if (ao_lisp_top + size > AO_LISP_POOL) { ao_lisp_exception |= AO_LISP_OOM; return NULL; @@ -374,6 +479,12 @@ ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) return 0; } +int +ao_lisp_root_poly_add(ao_poly *p) +{ + return ao_lisp_root_add(NULL, p); +} + void ao_lisp_root_clear(void *addr) { diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index e9367553..7f02505d 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -14,6 +14,12 @@ #include "ao_lisp.h" +#if 0 +#define DBG(...) printf (__VA_ARGS__) +#else +#define DBG(...) +#endif + static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { [AO_LISP_CONS] = ao_lisp_cons_print, [AO_LISP_STRING] = ao_lisp_string_print, @@ -33,30 +39,52 @@ ao_lisp_poly_print(ao_poly p) static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_INT] = NULL, [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_OTHER] = (void *) 0x1, [AO_LISP_ATOM] = &ao_lisp_atom_type, [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, + [AO_LISP_FRAME] = &ao_lisp_frame_type, }; -void +int ao_lisp_poly_mark(ao_poly p) { const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; if (lisp_type) - ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return 1; } -ao_poly -ao_lisp_poly_move(ao_poly p) +int +ao_lisp_poly_move(ao_poly *ref) { - uint8_t type = p & AO_LISP_TYPE_MASK; + uint8_t type; + ao_poly p = *ref; const struct ao_lisp_type *lisp_type; + int ret; + void *addr; + + if (!p) + return 1; + type = p & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + if (type >= AO_LISP_NUM_TYPE) + abort(); + lisp_type = ao_lisp_types[type]; - if (lisp_type) - p = ao_lisp_poly(ao_lisp_move(lisp_type, ao_lisp_ref(p)), p & AO_LISP_TYPE_MASK); - return p; + if (!lisp_type) + return 1; + addr = ao_lisp_ref(p); + ret = ao_lisp_move(lisp_type, &addr); + if (addr != ao_lisp_ref(p)) { + ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); + DBG("poly %d moved %04x -> %04x\n", + type, p, np); + *ref = np; + } + return ret; } -- cgit v1.2.3 From d8cf97fe22acefab40d7bb321138e46d4483fef7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Nov 2016 17:53:15 -0700 Subject: altos/lisp: more GC issues. add patom Use global ao_lisp_stack instead of local stack so that gc moves of that item work. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_lambdakey.c | 28 ------ src/lambdakey-v1.0/ao_pins.h | 3 +- src/lisp/ao_lisp.h | 12 ++- src/lisp/ao_lisp_builtin.c | 13 +++ src/lisp/ao_lisp_cons.c | 11 +++ src/lisp/ao_lisp_eval.c | 197 +++++++++++++++++++++++++------------- src/lisp/ao_lisp_make_const.c | 1 + src/lisp/ao_lisp_mem.c | 11 ++- src/lisp/ao_lisp_prim.c | 61 +++++++++--- src/lisp/ao_lisp_string.c | 10 ++ src/nucleao-32/ao_pins.h | 3 +- 11 files changed, 237 insertions(+), 113 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c index 6ac78717..8353d811 100644 --- a/src/lambdakey-v1.0/ao_lambdakey.c +++ b/src/lambdakey-v1.0/ao_lambdakey.c @@ -15,39 +15,11 @@ #include #include -static uint16_t blink_delay, blink_running; - -static void blink(void) { - blink_running = 1; - while (blink_delay) { - ao_led_on(AO_LED_RED); - ao_delay(blink_delay); - ao_led_off(AO_LED_RED); - ao_delay(blink_delay); - } - blink_running = 0; - ao_wakeup(&blink_running); - ao_exit(); -} - -struct ao_task blink_task; - -static void blink_cmd() { - ao_cmd_decimal(); - blink_delay = ao_cmd_lex_i; - if (blink_delay && !blink_running) - ao_add_task(&blink_task, blink, "blink"); - if (!blink_delay) - while (blink_running) - ao_sleep(&blink_running); -} - static void lisp_cmd() { ao_lisp_read_eval_print(); } static const struct ao_cmds blink_cmds[] = { - { blink_cmd, "b \0Blink the green LED" }, { lisp_cmd, "l\0Run lisp interpreter" }, { 0, 0 } }; diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index e379ed12..4da638b9 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,7 +25,8 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 2048 +#define AO_LISP_POOL 1536 +#define AO_STACK_SIZE 2048 #define LEDS_AVAILABLE (AO_LED_RED) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 27174e13..0d179942 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -173,6 +173,7 @@ enum ao_lisp_builtin_id { builtin_setq, builtin_cond, builtin_print, + builtin_patom, builtin_plus, builtin_minus, builtin_times, @@ -331,6 +332,9 @@ ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); void ao_lisp_cons_print(ao_poly); +void +ao_lisp_cons_patom(ao_poly); + /* string */ extern const struct ao_lisp_type ao_lisp_string_type; @@ -346,6 +350,9 @@ ao_lisp_string_cat(char *a, char *b); void ao_lisp_string_print(ao_poly s); +void +ao_lisp_string_patom(ao_poly s); + /* atom */ extern const struct ao_lisp_type ao_lisp_atom_type; @@ -370,9 +377,12 @@ void ao_lisp_int_print(ao_poly i); /* prim */ -ao_poly +void ao_lisp_poly_print(ao_poly p); +void +ao_lisp_poly_patom(ao_poly p); + int ao_lisp_poly_mark(ao_poly p); diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 0ad1f464..49b6c37d 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -179,6 +179,18 @@ ao_lisp_print(struct ao_lisp_cons *cons) return val; } +ao_poly +ao_lisp_patom(struct ao_lisp_cons *cons) +{ + ao_poly val = AO_LISP_NIL; + while (cons) { + val = cons->car; + ao_lisp_poly_patom(val); + cons = ao_lisp_poly_cons(cons->cdr); + } + return val; +} + ao_poly ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) { @@ -376,6 +388,7 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_setq] = ao_lisp_setq, [builtin_cond] = ao_lisp_cond, [builtin_print] = ao_lisp_print, + [builtin_patom] = ao_lisp_patom, [builtin_plus] = ao_lisp_plus, [builtin_minus] = ao_lisp_minus, [builtin_times] = ao_lisp_times, diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 4929b91c..7d3ca68d 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -83,3 +83,14 @@ ao_lisp_cons_print(ao_poly c) } printf(")"); } + +void +ao_lisp_cons_patom(ao_poly c) +{ + struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); + + while (cons) { + ao_lisp_poly_patom(cons->car); + cons = ao_lisp_poly_cons(cons->cdr); + } +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 0de3f190..e3d653b9 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -15,12 +15,13 @@ #include "ao_lisp.h" #if 0 +#define DBG_CODE 1 static int stack_depth; #define DBG_INDENT() do { int _s; for(_s = 0; _s < stack_depth; _s++) printf(" "); } while(0) #define DBG_IN() (++stack_depth) #define DBG_OUT() (--stack_depth) #define DBG(...) printf(__VA_ARGS__) -#define DBGI(...) do { DBG_INDENT(); DBG(__VA_ARGS__); } while (0) +#define DBGI(...) do { DBG_INDENT(); DBG("%4d: ", __LINE__); DBG(__VA_ARGS__); } while (0) #define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) #define DBG_POLY(a) ao_lisp_poly_print(a) #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) @@ -90,6 +91,29 @@ stack_mark(void *addr) static const struct ao_lisp_type ao_lisp_stack_type; +#if DBG_CODE +static void +stack_validate_tail(struct ao_lisp_stack *stack) +{ + struct ao_lisp_cons *head = ao_lisp_poly_cons(stack->formals); + struct ao_lisp_cons *tail = ao_lisp_poly_cons(stack->formals_tail); + struct ao_lisp_cons *cons; + for (cons = head; cons && cons->cdr && cons != tail; cons = ao_lisp_poly_cons(cons->cdr)) + ; + if (cons != tail || (tail && tail->cdr)) { + if (!tail) { + printf("tail null\n"); + } else { + printf("tail validate fail head %d actual %d recorded %d\n", + OFFSET(head), OFFSET(cons), OFFSET(tail)); + abort(); + } + } +} +#else +#define stack_validate_tail(s) +#endif + static void stack_move(void *addr) { @@ -106,7 +130,8 @@ stack_move(void *addr) ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); - if (ret); + stack_validate_tail(stack); + if (ret) break; stack = ao_lisp_poly_stack(stack->prev); } @@ -122,6 +147,19 @@ static struct ao_lisp_stack *ao_lisp_stack; static ao_poly ao_lisp_v; static uint8_t been_here; +#if DBG_CODE +static void +stack_validate_tails(void) +{ + struct ao_lisp_stack *stack; + + for (stack = ao_lisp_stack; stack; stack = ao_lisp_poly_stack(stack->prev)) + stack_validate_tail(stack); +} +#else +#define stack_validate_tails(s) +#endif + ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { @@ -139,27 +177,35 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) stack->formals = AO_LISP_NIL; stack->formals_tail = AO_LISP_NIL; stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + stack_validate_tails(); } -struct ao_lisp_stack * +int ao_lisp_stack_push(void) { + stack_validate_tails(); + if (ao_lisp_stack) { + DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); + DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + } + DBGI("stack push\n"); + DBG_IN(); struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) - return NULL; + return 0; stack->prev = ao_lisp_stack_poly(ao_lisp_stack); ao_lisp_stack = stack; ao_lisp_stack_reset(stack); - DBGI("stack push\n"); - DBG_IN(); - return stack; + stack_validate_tails(); + return 1; } -struct ao_lisp_stack * +void ao_lisp_stack_pop(void) { if (!ao_lisp_stack) - return NULL; + return; + stack_validate_tails(); DBG_OUT(); DBGI("stack pop\n"); ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); @@ -167,12 +213,16 @@ ao_lisp_stack_pop(void) ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); else ao_lisp_frame_current = NULL; - return ao_lisp_stack; + if (ao_lisp_stack) { + DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); + DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + } } static void ao_lisp_stack_clear(void) { + stack_validate_tails(); ao_lisp_stack = NULL; ao_lisp_frame_current = NULL; } @@ -285,7 +335,6 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) ao_poly ao_lisp_eval(ao_poly _v) { - struct ao_lisp_stack *stack; ao_poly formal; ao_lisp_v = _v; @@ -295,45 +344,50 @@ ao_lisp_eval(ao_poly _v) ao_lisp_root_poly_add(&ao_lisp_v); } - stack = ao_lisp_stack_push(); + if (!ao_lisp_stack_push()) + goto bail; for (;;) { if (ao_lisp_exception) - return AO_LISP_NIL; - switch (stack->state) { + goto bail; + switch (ao_lisp_stack->state) { case eval_sexpr: DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_CONS: if (ao_lisp_v == AO_LISP_NIL) { - stack->state = eval_exec; + ao_lisp_stack->state = eval_exec; break; } - stack->actuals = ao_lisp_v; - stack->state = eval_formal; - stack = ao_lisp_stack_push(); + ao_lisp_stack->actuals = ao_lisp_v; + DBGI("actuals now "); DBG_POLY(ao_lisp_v); DBG("\n"); + ao_lisp_stack->state = eval_formal; + if (!ao_lisp_stack_push()) + goto bail; ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + stack_validate_tails(); break; case AO_LISP_ATOM: ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); /* fall through */ case AO_LISP_INT: case AO_LISP_STRING: - stack->state = eval_val; + case AO_LISP_BUILTIN: + ao_lisp_stack->state = eval_val; break; } break; case eval_val: DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); - stack = ao_lisp_stack_pop(); - if (!stack) + ao_lisp_stack_pop(); + if (!ao_lisp_stack) return ao_lisp_v; - DBGI("..state %d\n", stack->state); + DBGI("..state %d\n", ao_lisp_stack->state); break; case eval_formal: /* Check what kind of function we've got */ - if (!stack->formals) { + if (!ao_lisp_stack->formals) { switch (func_type(ao_lisp_v)) { case AO_LISP_LAMBDA: case _ao_lisp_atom_lambda: @@ -343,99 +397,108 @@ ao_lisp_eval(ao_poly _v) break; case AO_LISP_MACRO: case _ao_lisp_atom_macro: - stack->macro = 1; + ao_lisp_stack->macro = 1; case AO_LISP_NLAMBDA: case _ao_lisp_atom_nlambda: DBGI(".. nlambda or macro\n"); - stack->formals = stack->actuals; - stack->state = eval_exec_direct; + ao_lisp_stack->formals = ao_lisp_stack->actuals; + ao_lisp_stack->formals_tail = AO_LISP_NIL; + ao_lisp_stack->state = eval_exec_direct; + stack_validate_tails(); break; } - if (stack->state == eval_exec_direct) + if (ao_lisp_stack->state == eval_exec_direct) break; } + DBGI("add formal "); DBG_POLY(ao_lisp_v); DBG("\n"); + stack_validate_tails(); formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); - if (!formal) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } + stack_validate_tails(); + if (!formal) + goto bail; - if (stack->formals_tail) - ao_lisp_poly_cons(stack->formals_tail)->cdr = formal; + if (ao_lisp_stack->formals_tail) + ao_lisp_poly_cons(ao_lisp_stack->formals_tail)->cdr = formal; else - stack->formals = formal; - stack->formals_tail = formal; + ao_lisp_stack->formals = formal; + ao_lisp_stack->formals_tail = formal; - DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n"); + DBGI("formals now "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); - ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->cdr; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; - stack->state = eval_sexpr; + stack_validate_tails(); + ao_lisp_stack->state = eval_sexpr; break; case eval_exec: - if (!stack->formals) { + if (!ao_lisp_stack->formals) { ao_lisp_v = AO_LISP_NIL; - stack->state = eval_val; + ao_lisp_stack->state = eval_val; break; } - ao_lisp_v = ao_lisp_poly_cons(stack->formals)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->formals)->car; case eval_exec_direct: - DBGI("exec: macro %d ", stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + DBGI("exec: macro %d ", ao_lisp_stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(ao_lisp_stack->formals); DBG ("\n"); if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); - struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr); + stack_validate_tails(); + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); + stack_validate_tails(); + struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->formals)->cdr); DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); - if (stack->macro) - stack->state = eval_sexpr; + stack_validate_tails(); + if (ao_lisp_stack->macro) + ao_lisp_stack->state = eval_sexpr; else - stack->state = eval_val; - stack->macro = 0; + ao_lisp_stack->state = eval_val; + ao_lisp_stack->macro = 0; + ao_lisp_stack->actuals = ao_lisp_stack->formals = ao_lisp_stack->formals_tail = AO_LISP_NIL; ao_lisp_v = ao_lisp_func(b) (f); DBGI("builtin result:"); DBG_POLY(ao_lisp_v); DBG ("\n"); - if (ao_lisp_exception) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } + if (ao_lisp_exception) + goto bail; break; } else { - ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); - ao_lisp_stack_reset(stack); + ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(ao_lisp_stack->formals)); + ao_lisp_stack_reset(ao_lisp_stack); } break; case eval_cond: - DBGI("cond: "); DBG_POLY(stack->actuals); DBG("\n"); - if (!stack->actuals) { + DBGI("cond: "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + if (!ao_lisp_stack->actuals) { ao_lisp_v = AO_LISP_NIL; - stack->state = eval_val; + ao_lisp_stack->state = eval_val; } else { - ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->car; if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); goto bail; } ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; - stack->state = eval_cond_test; - stack = ao_lisp_stack_push(); - stack->state = eval_sexpr; + ao_lisp_stack->state = eval_cond_test; + stack_validate_tails(); + ao_lisp_stack_push(); + stack_validate_tails(); + ao_lisp_stack->state = eval_sexpr; } break; case eval_cond_test: - DBGI("cond_test "); DBG_POLY(ao_lisp_v); DBG("\n"); + DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); if (ao_lisp_v) { - struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->actuals)->car); + struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->actuals)->car); struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); if (c) { ao_lisp_v = c->car; - stack->state = eval_sexpr; + ao_lisp_stack->state = eval_sexpr; } else { - stack->state = eval_val; + ao_lisp_stack->state = eval_val; } } else { - stack->actuals = ao_lisp_poly_cons(stack->actuals)->cdr; - stack->state = eval_cond; + ao_lisp_stack->actuals = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; + DBGI("actuals now "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + ao_lisp_stack->state = eval_cond; } break; } diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 9768dc22..f2e3cea1 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -41,6 +41,7 @@ struct builtin_func funcs[] = { "setq", AO_LISP_MACRO, builtin_setq, "cond", AO_LISP_NLAMBDA,builtin_cond, "print", AO_LISP_LEXPR, builtin_print, + "patom", AO_LISP_LEXPR, builtin_patom, "+", AO_LISP_LEXPR, builtin_plus, "-", AO_LISP_LEXPR, builtin_minus, "*", AO_LISP_LEXPR, builtin_times, diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 9e716da9..6e656454 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,6 +36,7 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#define DBG_INCLUDE #define DBG_DUMP 0 #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) @@ -179,15 +180,17 @@ move_object(void) DBG_DO(void *addr = *ao_lisp_root[i].addr); DBG_MOVE("root %d\n", DBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, - ao_lisp_root[i].addr)) + ao_lisp_root[i].addr)) { DBG_MOVE("root moves from %p to %p\n", addr, *ao_lisp_root[i].addr); + } } else { DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); - if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) { DBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); + } } } DBG_MOVE_OUT(); @@ -338,7 +341,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) int size = type->size(addr); if (!addr) - return NULL; + return 1; #ifndef AO_LISP_MAKE_CONST if (AO_LISP_IS_CONST(addr)) @@ -370,7 +373,7 @@ ao_lisp_move_memory(void **ref, int size) { void *addr = *ref; if (!addr) - return NULL; + return 1; DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); DBG_MOVE_IN(); diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 7f02505d..82386a83 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -20,21 +20,60 @@ #define DBG(...) #endif -static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { - [AO_LISP_CONS] = ao_lisp_cons_print, - [AO_LISP_STRING] = ao_lisp_string_print, - [AO_LISP_INT] = ao_lisp_int_print, - [AO_LISP_ATOM] = ao_lisp_atom_print, - [AO_LISP_BUILTIN] = ao_lisp_builtin_print +struct ao_lisp_funcs { + void (*print)(ao_poly); + void (*patom)(ao_poly); }; -ao_poly +static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = { + .print = ao_lisp_cons_print, + .patom = ao_lisp_cons_patom, + }, + [AO_LISP_STRING] = { + .print = ao_lisp_string_print, + .patom = ao_lisp_string_patom, + }, + [AO_LISP_INT] = { + .print = ao_lisp_int_print, + .patom = ao_lisp_int_print, + }, + [AO_LISP_ATOM] = { + .print = ao_lisp_atom_print, + .patom = ao_lisp_atom_print, + }, + [AO_LISP_BUILTIN] = { + .print = ao_lisp_builtin_print, + .patom = ao_lisp_builtin_print, + } +}; + +static const struct ao_lisp_funcs * +funcs(ao_poly p) +{ + uint8_t type = ao_lisp_poly_type(p); + + if (type < AO_LISP_NUM_TYPE) + return &ao_lisp_funcs[type]; + return NULL; +} + +void ao_lisp_poly_print(ao_poly p) { - void (*print)(ao_poly) = ao_lisp_print_funcs[ao_lisp_poly_type(p)]; - if (print) - print(p); - return p; + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->print) + f->print(p); +} + +void +ao_lisp_poly_patom(ao_poly p) +{ + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->patom) + f->patom(p); } static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 39c3dc81..0064064c 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -99,3 +99,13 @@ ao_lisp_string_print(ao_poly p) } putchar('"'); } + +void +ao_lisp_string_patom(ao_poly p) +{ + char *s = ao_lisp_poly_string(p); + char c; + + while ((c = *s++)) + putchar(c); +} diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h index 65de89ed..092d347c 100644 --- a/src/nucleao-32/ao_pins.h +++ b/src/nucleao-32/ao_pins.h @@ -25,7 +25,8 @@ #define AO_LED_GREEN (1 << LED_PIN_GREEN) #define AO_LED_PANIC AO_LED_GREEN #define AO_CMD_LEN 128 -#define AO_LISP_POOL 2048 +#define AO_LISP_POOL 1024 +#define AO_STACK_SIZE 1536 #define LEDS_AVAILABLE (AO_LED_GREEN) -- cgit v1.2.3 From 6e5c1308ce33a864095eae02e7db18b0e043ab6e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Nov 2016 10:53:46 -0800 Subject: altos/lisp: convert GC to non-recursive Use a boolean array to note cons cells which would otherwise recurse, then loop until that array is empty. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 8 ++- src/lisp/ao_lisp_atom.c | 2 +- src/lisp/ao_lisp_cons.c | 15 +++-- src/lisp/ao_lisp_eval.c | 14 ++--- src/lisp/ao_lisp_frame.c | 19 +++++-- src/lisp/ao_lisp_mem.c | 140 ++++++++++++++++++++++++++++++++++++++++++++--- src/lisp/ao_lisp_prim.c | 51 ----------------- 7 files changed, 170 insertions(+), 79 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 0d179942..17f1e0f5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -221,6 +221,10 @@ ao_lisp_mem_round(int size) #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) +static inline int ao_lisp_poly_base_type(ao_poly poly) { + return poly & AO_LISP_TYPE_MASK; +} + static inline int ao_lisp_poly_type(ao_poly poly) { int type = poly & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) @@ -384,11 +388,11 @@ void ao_lisp_poly_patom(ao_poly p); int -ao_lisp_poly_mark(ao_poly p); +ao_lisp_poly_mark(ao_poly p, uint8_t note_cons); /* returns 1 if the object has already been moved */ int -ao_lisp_poly_move(ao_poly *p); +ao_lisp_poly_move(ao_poly *p, uint8_t note_cons); /* eval */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 5f1bcda0..41ba97f5 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -48,7 +48,7 @@ static void atom_move(void *addr) struct ao_lisp_atom *atom = addr; for (;;) { - if (ao_lisp_poly_move(&atom->next)) + if (ao_lisp_poly_move(&atom->next, 0)) break; atom = ao_lisp_poly_atom(atom->next); } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 7d3ca68d..855079b8 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -21,7 +21,7 @@ static void cons_mark(void *addr) struct ao_lisp_cons *cons = addr; for (;;) { - ao_lisp_poly_mark(cons->car); + ao_lisp_poly_mark(cons->car, 1); cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; @@ -44,10 +44,17 @@ static void cons_move(void *addr) return; for (;;) { - (void) ao_lisp_poly_move(&cons->car); - if (ao_lisp_poly_move(&cons->cdr)) + struct ao_lisp_cons *cdr; + int ret; + + (void) ao_lisp_poly_move(&cons->car, 1); + cdr = ao_lisp_poly_cons(cons->cdr); + ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); + if (cdr != ao_lisp_poly_cons(cons->cdr)) + cons->cdr = ao_lisp_cons_poly(cdr); + if (ret) break; - cons = ao_lisp_poly_cons(cons->cdr); + cons = cdr; } } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index e3d653b9..a5c74250 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -79,10 +79,10 @@ stack_mark(void *addr) { struct ao_lisp_stack *stack = addr; for (;;) { - ao_lisp_poly_mark(stack->actuals); - ao_lisp_poly_mark(stack->formals); + ao_lisp_poly_mark(stack->actuals, 0); + ao_lisp_poly_mark(stack->formals, 0); /* no need to mark formals_tail */ - ao_lisp_poly_mark(stack->frame); + ao_lisp_poly_mark(stack->frame, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -122,10 +122,10 @@ stack_move(void *addr) while (stack) { void *prev; int ret; - (void) ao_lisp_poly_move(&stack->actuals); - (void) ao_lisp_poly_move(&stack->formals); - (void) ao_lisp_poly_move(&stack->formals_tail); - (void) ao_lisp_poly_move(&stack->frame); + (void) ao_lisp_poly_move(&stack->actuals, 0); + (void) ao_lisp_poly_move(&stack->formals, 0); + (void) ao_lisp_poly_move(&stack->formals_tail, 0); + (void) ao_lisp_poly_move(&stack->frame, 0); prev = ao_lisp_poly_stack(stack->prev); ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 8bf98571..8791c4de 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -48,7 +48,7 @@ frame_mark(void *addr) for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_mark(v->val); + ao_lisp_poly_mark(v->val, 0); DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); @@ -69,19 +69,28 @@ frame_move(void *addr) int f; for (;;) { + struct ao_lisp_frame *next; + int ret; + DBG("frame move %p\n", frame); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_move(&v->atom); + ao_lisp_poly_move(&v->atom, 0); DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); - ao_lisp_poly_move(&v->val); + ao_lisp_poly_move(&v->val, 0); } - if (ao_lisp_poly_move(&frame->next)) + next = ao_lisp_poly_frame(frame->next); + ret = 1; + if (next) + ret = ao_lisp_move_memory((void **) &next, frame_size(next)); + if (next != ao_lisp_poly_frame(frame->next)) + frame->next = ao_lisp_frame_poly(next); + if (ret) break; - frame = ao_lisp_poly_frame(frame->next); + frame = next; } } diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 6e656454..c11ec25d 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -41,7 +41,7 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) #define DBG_DO(a) a -static int move_dump; +static int move_dump = 1; static int move_depth; #define DBG_RESET() (move_depth = 0) #define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) @@ -68,8 +68,10 @@ struct ao_lisp_root { static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; - static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; @@ -161,6 +163,17 @@ busy_object(uint8_t *tag, void *addr) { return 0; } +static void +note_cons(void *addr) +{ + DBG_MOVE("note cons %d\n", DBG_OFFSET(addr)); + if (AO_LISP_IS_POOL(addr)) { + ao_lisp_cons_noted = 1; + mark(ao_lisp_cons, (uint8_t *) addr - ao_lisp_pool); + } +} + + static void *move_old, *move_new; static int move_size; @@ -173,11 +186,15 @@ move_object(void) DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) continue; if (ao_lisp_root[i].type) { - DBG_DO(void *addr = *ao_lisp_root[i].addr); + void *addr = *ao_lisp_root[i].addr; + if (!addr) + continue; DBG_MOVE("root %d\n", DBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, ao_lisp_root[i].addr)) { @@ -186,13 +203,30 @@ move_object(void) *ao_lisp_root[i].addr); } } else { - DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); - if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) { + ao_poly p = *(ao_poly *) ao_lisp_root[i].addr; + if (!p) + continue; + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr, 0)) { DBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); } } } + while (ao_lisp_cons_noted) { + memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (busy(ao_lisp_cons_last, i)) { + void *addr = ao_lisp_pool + i; + DBG_MOVE("cons %d\n", DBG_OFFSET(addr)); + if (!ao_lisp_move(&ao_lisp_cons_type, &addr)) { + DBG_MOVE("cons moves from %p to %p\n", + ao_lisp_pool + i, addr); + } + } + } + } DBG_MOVE_OUT(); DBG_MOVE("move done\n"); } @@ -220,25 +254,50 @@ dump_busy(void) #define DUMP_BUSY() #endif +static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_INT] = NULL, + [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_OTHER] = (void *) 0x1, + [AO_LISP_ATOM] = &ao_lisp_atom_type, + [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, + [AO_LISP_FRAME] = &ao_lisp_frame_type, +}; + + static void ao_lisp_mark_busy(void) { int i; memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; DBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - DBG("root %p\n", v); + DBG("root %d\n", DBG_OFFSET(v)); ao_lisp_mark(ao_lisp_root[i].type, v); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - DBG("root %04x\n", p); - ao_lisp_poly_mark(p); + DBG("root 0x%04x\n", p); + ao_lisp_poly_mark(p, 0); + } + } + } + while (ao_lisp_cons_noted) { + memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (busy(ao_lisp_cons_last, i)) { + void *v = ao_lisp_pool + i; + DBG("cons %d\n", DBG_OFFSET(v)); + ao_lisp_mark(&ao_lisp_cons_type, v); } } } @@ -274,6 +333,10 @@ ao_lisp_collect(void) abort(); clear_object(ao_lisp_busy, move_old, move_size); mark_object(ao_lisp_busy, move_new, move_size); + if (busy_object(ao_lisp_cons, move_old)) { + clear_object(ao_lisp_cons, move_old, move_size); + mark_object(ao_lisp_cons, move_new, move_size); + } i += move_size; top += move_size; DUMP_BUSY(); @@ -296,6 +359,24 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr) return 0; } +int +ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) +{ + uint8_t type = ao_lisp_poly_type(p); + + if (!p) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { + note_cons(ao_lisp_ref(p)); + return 0; + } else { + const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (lisp_type) + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return 1; + } +} + int ao_lisp_mark_memory(void *addr, int size) { @@ -348,7 +429,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) return 1; #endif DBG_MOVE("object %d\n", DBG_OFFSET(addr)); - if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) + if (!AO_LISP_IS_POOL(a)) abort(); DBG_MOVE_IN(); addr = check_move(addr, size); @@ -389,6 +470,47 @@ ao_lisp_move_memory(void **ref, int size) return 0; } +int +ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) +{ + uint8_t type; + ao_poly p = *ref; + const struct ao_lisp_type *lisp_type; + int ret; + void *addr; + + if (!p) + return 1; + + type = ao_lisp_poly_base_type(p); + addr = ao_lisp_ref(p); + if (type == AO_LISP_CONS && do_note_cons) { + note_cons(addr); + addr = check_move(addr, sizeof (struct ao_lisp_cons)); + ret = 1; + } else { + + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + + if (type >= AO_LISP_NUM_TYPE) + abort(); + + lisp_type = ao_lisp_types[type]; + if (!lisp_type) + return 1; + ret = ao_lisp_move(lisp_type, &addr); + } + + if (addr != ao_lisp_ref(p)) { + ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); + DBG("poly %d moved %04x -> %04x\n", + type, p, np); + *ref = np; + } + return ret; +} + #ifdef DBG_POOL static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 82386a83..3c081ee8 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -76,54 +76,3 @@ ao_lisp_poly_patom(ao_poly p) f->patom(p); } -static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { - [AO_LISP_CONS] = &ao_lisp_cons_type, - [AO_LISP_INT] = NULL, - [AO_LISP_STRING] = &ao_lisp_string_type, - [AO_LISP_OTHER] = (void *) 0x1, - [AO_LISP_ATOM] = &ao_lisp_atom_type, - [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, - [AO_LISP_FRAME] = &ao_lisp_frame_type, -}; - -int -ao_lisp_poly_mark(ao_poly p) -{ - const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; - if (lisp_type) - return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); - return 1; -} - -int -ao_lisp_poly_move(ao_poly *ref) -{ - uint8_t type; - ao_poly p = *ref; - const struct ao_lisp_type *lisp_type; - int ret; - void *addr; - - if (!p) - return 1; - - type = p & AO_LISP_TYPE_MASK; - if (type == AO_LISP_OTHER) - type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); - - if (type >= AO_LISP_NUM_TYPE) - abort(); - - lisp_type = ao_lisp_types[type]; - if (!lisp_type) - return 1; - addr = ao_lisp_ref(p); - ret = ao_lisp_move(lisp_type, &addr); - if (addr != ao_lisp_ref(p)) { - ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - DBG("poly %d moved %04x -> %04x\n", - type, p, np); - *ref = np; - } - return ret; -} -- cgit v1.2.3 From 7da6bfc195fad97e3afc576c609897c131fd4d8c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:29:21 -0800 Subject: altos/lisp: Deal with memory compation in the middle of operations Handle memory compaction in places where we've got pointers into the heap across an allocation operation. Either re-compute the values from managed global references or add new roots across the allocation. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 7 +-- src/lisp/ao_lisp_atom.c | 2 +- src/lisp/ao_lisp_cons.c | 8 ++- src/lisp/ao_lisp_eval.c | 59 +++++------------- src/lisp/ao_lisp_frame.c | 28 ++++++--- src/lisp/ao_lisp_lambda.c | 19 ++++-- src/lisp/ao_lisp_mem.c | 149 ++++++++++++++++++++++++---------------------- 7 files changed, 137 insertions(+), 135 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 6122a2ed..60a97f2c 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -510,8 +510,8 @@ ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * ao_lisp_frame_new(int num); -struct ao_lisp_frame * -ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); +int +ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val); void ao_lisp_frame_print(ao_poly p); @@ -538,8 +538,7 @@ ao_poly ao_lisp_macro(struct ao_lisp_cons *cons); ao_poly -ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, - struct ao_lisp_cons *cons); +ao_lisp_lambda_eval(void); /* error */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 5c6d5a67..efa4f621 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -147,7 +147,7 @@ ao_lisp_atom_set(ao_poly atom, ao_poly val) if (ref) *ref = val; else - ao_lisp_frame_global = ao_lisp_frame_add(ao_lisp_frame_global, atom, val); + ao_lisp_frame_add(&ao_lisp_frame_global, atom, val); return val; } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 855079b8..cd8a8d1d 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -67,7 +67,13 @@ const struct ao_lisp_type ao_lisp_cons_type = { struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { - struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + struct ao_lisp_cons *cons; + + ao_lisp_root_add(&ao_lisp_cons_type, &cdr); + ao_lisp_root_poly_add(&car); + cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + ao_lisp_root_clear(&car); + ao_lisp_root_clear(&cdr); if (!cons) return NULL; cons->car = car; diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index c5addcb0..ae2436b8 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,7 +12,7 @@ * General Public License for more details. */ -#define DBG_EVAL 1 +#define DBG_EVAL 0 #include "ao_lisp.h" #include @@ -46,19 +46,20 @@ stack_move(void *addr) struct ao_lisp_stack *stack = addr; while (stack) { - void *prev; + struct ao_lisp_stack *prev; int ret; (void) ao_lisp_poly_move(&stack->sexprs, 0); (void) ao_lisp_poly_move(&stack->values, 0); (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); prev = ao_lisp_poly_stack(stack->prev); - ret = ao_lisp_move(&ao_lisp_stack_type, &prev); + ret = ao_lisp_move_memory((void **) &prev, + sizeof (struct ao_lisp_stack)); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); if (ret) break; - stack = ao_lisp_poly_stack(stack->prev); + stack = prev; } } @@ -101,8 +102,8 @@ ao_lisp_stack_push(void) ao_lisp_stack = stack; ao_lisp_stack_reset(stack); DBGI("stack push\n"); - DBG_IN(); DBG_FRAMES(); + DBG_IN(); return 1; } @@ -236,37 +237,11 @@ static int ao_lisp_eval_val(void) { DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); -#if 0 - if (ao_lisp_stack->macro) { - DBGI(".. end macro %d\n", ao_lisp_stack->macro); - DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); - DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); - ao_lisp_frames_dump(); - - ao_lisp_stack_pop(); -#if 0 - /* - * Re-use the current stack to evaluate - * the value from the macro - */ - ao_lisp_stack->state = eval_sexpr; - ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->macro_frame); - ao_lisp_stack->frame = ao_lisp_stack->macro_frame; - ao_lisp_stack->macro = 0; - ao_lisp_stack->macro_frame = AO_LISP_NIL; - ao_lisp_stack->sexprs = AO_LISP_NIL; - ao_lisp_stack->values = AO_LISP_NIL; - ao_lisp_stack->values_tail = AO_LISP_NIL; -#endif - } else -#endif - { - /* - * Value computed, pop the stack - * to figure out what to do with the value - */ - ao_lisp_stack_pop(); - } + /* + * Value computed, pop the stack + * to figure out what to do with the value + */ + ao_lisp_stack_pop(); DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1); return 1; } @@ -305,7 +280,6 @@ ao_lisp_eval_formal(void) break; case AO_LISP_FUNC_MACRO: /* Evaluate the result once more */ - prev = ao_lisp_stack; ao_lisp_stack->state = eval_sexpr; if (!ao_lisp_stack_push()) return 0; @@ -313,6 +287,7 @@ ao_lisp_eval_formal(void) /* After the function returns, take that * value and re-evaluate it */ + prev = ao_lisp_poly_stack(ao_lisp_stack->prev); ao_lisp_stack->state = eval_sexpr; ao_lisp_stack->sexprs = prev->sexprs; prev->sexprs = AO_LISP_NIL; @@ -400,8 +375,7 @@ ao_lisp_eval_exec(void) case AO_LISP_LAMBDA: ao_lisp_stack->state = eval_sexpr; DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - ao_lisp_v = ao_lisp_lambda_eval(ao_lisp_poly_lambda(ao_lisp_v), - ao_lisp_poly_cons(ao_lisp_stack->values)); + ao_lisp_v = ao_lisp_lambda_eval(); DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; @@ -464,12 +438,11 @@ ao_lisp_eval_cond_test(void) struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car); struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); - ao_lisp_stack->state = eval_val; if (c) { + ao_lisp_stack->state = eval_sexpr; ao_lisp_v = c->car; - if (!ao_lisp_stack_push()) - return 0; - } + } else + ao_lisp_stack->state = eval_val; } else { ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 7978f20a..90344719 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -174,8 +174,9 @@ ao_lisp_frame_new(int num) } static struct ao_lisp_frame * -ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) +ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) { + struct ao_lisp_frame *frame = *frame_ref; struct ao_lisp_frame *new; int copy; @@ -184,34 +185,45 @@ ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) new = ao_lisp_frame_new(new_num); if (!new) return NULL; + /* + * Re-fetch the frame as it may have moved + * during the allocation + */ + frame = *frame_ref; copy = new_num; if (copy > frame->num) copy = frame->num; memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); - if (frame) - new->next = frame->next; + new->next = frame->next; return new; } -struct ao_lisp_frame * -ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +int +ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) { + struct ao_lisp_frame *frame = *frame_ref; ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL; + if (!ref) { int f; + ao_lisp_root_poly_add(&atom); + ao_lisp_root_poly_add(&val); if (frame) { f = frame->num; - frame = ao_lisp_frame_realloc(frame, f + 1); + frame = ao_lisp_frame_realloc(frame_ref, f + 1); } else { f = 0; frame = ao_lisp_frame_new(1); } + ao_lisp_root_clear(&atom); + ao_lisp_root_clear(&val); if (!frame) - return NULL; + return 0; + *frame_ref = frame; DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); frame->vals[f].atom = atom; ref = &frame->vals[f].val; } *ref = val; - return frame; + return 1; } diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index cc5af4bc..8eafb187 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -133,18 +133,17 @@ ao_lisp_macro(struct ao_lisp_cons *cons) } ao_poly -ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, - struct ao_lisp_cons *cons) +ao_lisp_lambda_eval(void) { - struct ao_lisp_cons *code; - struct ao_lisp_cons *args; + struct ao_lisp_lambda *lambda = ao_lisp_poly_lambda(ao_lisp_v); + struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); + struct ao_lisp_cons *code = ao_lisp_poly_cons(lambda->code); + struct ao_lisp_cons *args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); struct ao_lisp_frame *next_frame; int args_wanted; int args_provided; - code = ao_lisp_poly_cons(lambda->code); DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); - args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); args_wanted = ao_lisp_cons_length(args); @@ -156,7 +155,15 @@ ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, args_provided = 1; if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); + next_frame = ao_lisp_frame_new(args_wanted); + + /* Re-fetch all of the values in case something moved */ + lambda = ao_lisp_poly_lambda(ao_lisp_v); + cons = ao_lisp_poly_cons(ao_lisp_stack->values); + code = ao_lisp_poly_cons(lambda->code); + args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); + switch (lambda->args) { case AO_LISP_FUNC_LAMBDA: { int f; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 66e09db0..b763d78b 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -28,32 +28,33 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 -#define DBG_COLLECT_ALWAYS +#define MDBG_COLLECT_ALWAYS #endif #if 0 -#define DBG_POOL +#define MDBG_POOL #endif #if 0 -#define DBG_INCLUDE -#define DBG_DUMP 0 -#define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) -#define DBG(...) printf(__VA_ARGS__) -#define DBG_DO(a) a -static int move_dump = 1; +#define MDBG_INCLUDE +#define MDBG_DUMP 1 +#define MDBG_MOVE 0 +#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) +#define MDBG(...) printf(__VA_ARGS__) +#define MDBG_DO(a) a +static int move_dump = MDBG_MOVE; static int move_depth; -#define DBG_RESET() (move_depth = 0) -#define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) -#define DBG_MOVE_IN() (move_depth++) -#define DBG_MOVE_OUT() (move_depth--) +#define MDBG_RESET() (move_depth = 0) +#define MDBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define MDBG_MOVE_IN() (move_depth++) +#define MDBG_MOVE_OUT() (move_depth--) #else -#define DBG(...) -#define DBG_DO(a) -#define DBG_RESET() -#define DBG_MOVE(...) -#define DBG_MOVE_IN() -#define DBG_MOVE_OUT() +#define MDBG(...) +#define MDBG_DO(a) +#define MDBG_RESET() +#define MDBG_MOVE(...) +#define MDBG_MOVE_IN() +#define MDBG_MOVE_OUT() #endif uint8_t ao_lisp_exception; @@ -69,7 +70,7 @@ static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_note[AO_LISP_POOL / 32]; static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; static uint8_t ao_lisp_cons_noted; @@ -78,6 +79,7 @@ uint16_t ao_lisp_top; static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; + tag[byte] |= (1 << bit); } @@ -166,10 +168,11 @@ busy_object(uint8_t *tag, void *addr) { static void note_cons(void *addr) { - DBG_MOVE("note cons %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); if (AO_LISP_IS_POOL(addr)) { + int offset = (uint8_t *) addr - ao_lisp_pool; ao_lisp_cons_noted = 1; - mark(ao_lisp_cons, (uint8_t *) addr - ao_lisp_pool); + mark(ao_lisp_cons_note, offset); } } @@ -182,11 +185,11 @@ move_object(void) { int i; - DBG_RESET(); - DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); - DBG_MOVE_IN(); + MDBG_RESET(); + MDBG_MOVE("move %d -> %d\n", MDBG_OFFSET(move_old), MDBG_OFFSET(move_new)); + MDBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) @@ -195,10 +198,10 @@ move_object(void) void *addr = *ao_lisp_root[i].addr; if (!addr) continue; - DBG_MOVE("root %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("root %d\n", MDBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, ao_lisp_root[i].addr)) { - DBG_MOVE("root moves from %p to %p\n", + MDBG_MOVE("root moves from %p to %p\n", addr, *ao_lisp_root[i].addr); } @@ -207,31 +210,31 @@ move_object(void) if (!p) continue; if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr, 0)) { - DBG_MOVE("root poly move from %04x to %04x\n", + MDBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); } } } while (ao_lisp_cons_noted) { - memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *addr = ao_lisp_pool + i; - DBG_MOVE("cons %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("cons %d\n", MDBG_OFFSET(addr)); if (!ao_lisp_move(&ao_lisp_cons_type, &addr)) { - DBG_MOVE("cons moves from %p to %p\n", + MDBG_MOVE("cons moves from %p to %p\n", ao_lisp_pool + i, addr); } } } } - DBG_MOVE_OUT(); - DBG_MOVE("move done\n"); + MDBG_MOVE_OUT(); + MDBG_MOVE("move done\n"); } -#if DBG_DUMP +#if MDBG_DUMP static void dump_busy(void) { @@ -272,32 +275,32 @@ ao_lisp_mark_busy(void) int i; memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; - DBG("mark\n"); + MDBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - DBG("root %d\n", DBG_OFFSET(v)); + MDBG("root %d\n", MDBG_OFFSET(v)); ao_lisp_mark(ao_lisp_root[i].type, v); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - DBG("root 0x%04x\n", p); + MDBG("root 0x%04x\n", p); ao_lisp_poly_mark(p, 0); } } } while (ao_lisp_cons_noted) { - memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - DBG("cons %d\n", DBG_OFFSET(v)); + MDBG("cons %d\n", MDBG_OFFSET(v)); ao_lisp_mark(&ao_lisp_cons_type, v); } } @@ -310,13 +313,13 @@ ao_lisp_collect(void) int i; int top; - DBG("collect\n"); + MDBG("collect\n"); /* Mark */ ao_lisp_mark_busy(); DUMP_BUSY(); /* Compact */ - DBG("find first busy\n"); + MDBG("find first busy\n"); for (i = 0; i < ao_lisp_top; i += 4) { if (!busy(ao_lisp_busy, i)) break; @@ -324,23 +327,25 @@ ao_lisp_collect(void) top = i; while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { - DBG("busy %d -> %d\n", i, top); + MDBG("busy %d -> %d\n", i, top); move_old = &ao_lisp_pool[i]; move_new = &ao_lisp_pool[top]; move_size = 0; move_object(); - DBG("\tbusy size %d\n", move_size); + MDBG("\tbusy size %d\n", move_size); if (move_size == 0) ao_lisp_abort(); clear_object(ao_lisp_busy, move_old, move_size); mark_object(ao_lisp_busy, move_new, move_size); - if (busy_object(ao_lisp_cons, move_old)) { - clear_object(ao_lisp_cons, move_old, move_size); - mark_object(ao_lisp_cons, move_new, move_size); + if (busy_object(ao_lisp_cons_note, move_old)) { + clear_object(ao_lisp_cons_note, move_old, move_size); + mark_object(ao_lisp_cons_note, move_new, move_size); } i += move_size; top += move_size; +#if MDBG_MOVE DUMP_BUSY(); +#endif } else { i += 4; } @@ -404,9 +409,9 @@ static void * check_move(void *addr, int size) { if (addr == move_old) { - DBG_MOVE("mapping %d -> %d\n", DBG_OFFSET(addr), DBG_OFFSET(move_new)); + MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); if (!busy_object(ao_lisp_moving, addr)) { - DBG_MOVE(" copy %d\n", size); + MDBG_MOVE(" copy %d\n", size); memmove(move_new, move_old, size); move_size = (size + 3) & ~3; } @@ -429,24 +434,24 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) if (AO_LISP_IS_CONST(addr)) return 1; #endif - DBG_MOVE("object %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("object %d\n", MDBG_OFFSET(addr)); if (!AO_LISP_IS_POOL(a)) ao_lisp_abort(); - DBG_MOVE_IN(); + MDBG_MOVE_IN(); addr = check_move(addr, size); if (addr != *ref) *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { - DBG_MOVE("already moved\n"); - DBG_MOVE_OUT(); + MDBG_MOVE("already moved\n"); + MDBG_MOVE_OUT(); return 1; } - DBG_MOVE_OUT(); - DBG_MOVE("recursing...\n"); - DBG_MOVE_IN(); + MDBG_MOVE_OUT(); + MDBG_MOVE("recursing...\n"); + MDBG_MOVE_IN(); type->move(addr); - DBG_MOVE_OUT(); - DBG_MOVE("done %d\n", DBG_OFFSET(addr)); + MDBG_MOVE_OUT(); + MDBG_MOVE("done %d\n", MDBG_OFFSET(addr)); return 0; } @@ -457,17 +462,17 @@ ao_lisp_move_memory(void **ref, int size) if (!addr) return 1; - DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); - DBG_MOVE_IN(); + MDBG_MOVE("memory %d\n", MDBG_OFFSET(addr)); + MDBG_MOVE_IN(); addr = check_move(addr, size); if (addr != *ref) *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { - DBG_MOVE("already moved\n"); - DBG_MOVE_OUT(); + MDBG_MOVE("already moved\n"); + MDBG_MOVE_OUT(); return 1; } - DBG_MOVE_OUT(); + MDBG_MOVE_OUT(); return 0; } @@ -505,14 +510,14 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - DBG("poly %d moved %04x -> %04x\n", + MDBG("poly %d moved %04x -> %04x\n", type, p, np); *ref = np; } return ret; } -#ifdef DBG_POOL +#ifdef MDBG_POOL static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; static void @@ -557,18 +562,18 @@ ao_lisp_alloc(int size) void *addr; size = ao_lisp_mem_round(size); -#ifdef DBG_COLLECT_ALWAYS +#ifdef MDBG_COLLECT_ALWAYS ao_lisp_collect(); #endif if (ao_lisp_top + size > AO_LISP_POOL_CUR) { -#ifdef DBG_POOL +#ifdef MDBG_POOL if (AO_LISP_POOL_CUR < AO_LISP_POOL) { AO_LISP_POOL_CUR += AO_LISP_POOL / 8; ao_lisp_poison(); } else #endif ao_lisp_collect(); -#ifdef DBG_POOL +#ifdef MDBG_POOL { int i; @@ -580,7 +585,7 @@ ao_lisp_alloc(int size) #endif if (ao_lisp_top + size > AO_LISP_POOL) { - ao_lisp_exception |= AO_LISP_OOM; + ao_lisp_error(AO_LISP_OOM, "out of memory"); return NULL; } } @@ -593,7 +598,7 @@ int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; - DBG("add root type %p addr %p\n", type, addr); + MDBG("add root type %p addr %p\n", type, addr); for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) { ao_lisp_root[i].addr = addr; -- cgit v1.2.3 From 7f7e2431f5d1f7c1782ed6e774ccfc70fb4c87cf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 00:28:31 -0800 Subject: altos/lisp: add length, pack, unpack and flush lots more builtins Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_lisp_os.h | 6 +++++ src/lisp/ao_lisp.h | 17 ++++++++++++++ src/lisp/ao_lisp_builtin.c | 47 +++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_cons.c | 11 +++++++++ src/lisp/ao_lisp_lambda.c | 11 --------- src/lisp/ao_lisp_make_const.c | 4 ++++ src/lisp/ao_lisp_os.h | 5 ++++ src/lisp/ao_lisp_string.c | 52 +++++++++++++++++++++++++++++++++++++---- src/test/ao_lisp_os.h | 5 ++++ 9 files changed, 142 insertions(+), 16 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h index df158f6a..1993ac44 100644 --- a/src/lambdakey-v1.0/ao_lisp_os.h +++ b/src/lambdakey-v1.0/ao_lisp_os.h @@ -35,6 +35,12 @@ ao_lisp_getc() { return c; } +static inline void +ao_lisp_os_flush(void) +{ + flush(); +} + static inline void ao_lisp_abort(void) { diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 60a97f2c..86a5ddcf 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -36,10 +36,14 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_cdr _atom("cdr") #define _ao_lisp_atom_cons _atom("cons") #define _ao_lisp_atom_last _atom("last") +#define _ao_lisp_atom_length _atom("length") #define _ao_lisp_atom_cond _atom("cond") #define _ao_lisp_atom_lambda _atom("lambda") #define _ao_lisp_atom_led _atom("led") #define _ao_lisp_atom_delay _atom("delay") +#define _ao_lisp_atom_pack _atom("pack") +#define _ao_lisp_atom_unpack _atom("unpack") +#define _ao_lisp_atom_flush _atom("flush") #define _ao_lisp_atom_eval _atom("eval") #define _ao_lisp_atom_read _atom("read") #define _ao_lisp_atom_eof _atom("eof") @@ -215,6 +219,7 @@ enum ao_lisp_builtin_id { builtin_cdr, builtin_cons, builtin_last, + builtin_length, builtin_quote, builtin_set, builtin_setq, @@ -233,6 +238,9 @@ enum ao_lisp_builtin_id { builtin_greater, builtin_less_equal, builtin_greater_equal, + builtin_pack, + builtin_unpack, + builtin_flush, builtin_delay, builtin_led, _builtin_last @@ -409,6 +417,9 @@ ao_lisp_cons_print(ao_poly); void ao_lisp_cons_patom(ao_poly); +int +ao_lisp_cons_length(struct ao_lisp_cons *cons); + /* string */ extern const struct ao_lisp_type ao_lisp_string_type; @@ -421,6 +432,12 @@ ao_lisp_string_copy(char *a); char * ao_lisp_string_cat(char *a, char *b); +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_string_unpack(char *a); + void ao_lisp_string_print(ao_poly s); diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 57d9ee10..30631980 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -58,6 +58,7 @@ static const ao_poly builtin_names[] = { [builtin_cdr] = _ao_lisp_atom_cdr, [builtin_cons] = _ao_lisp_atom_cons, [builtin_last] = _ao_lisp_atom_last, + [builtin_length] = _ao_lisp_atom_length, [builtin_quote] = _ao_lisp_atom_quote, [builtin_set] = _ao_lisp_atom_set, [builtin_setq] = _ao_lisp_atom_setq, @@ -76,6 +77,9 @@ static const ao_poly builtin_names[] = { [builtin_greater] = _ao_lisp_atom_3e, [builtin_less_equal] = _ao_lisp_atom_3c3d, [builtin_greater_equal] = _ao_lisp_atom_3e3d, + [builtin_pack] = _ao_lisp_atom_pack, + [builtin_unpack] = _ao_lisp_atom_unpack, + [builtin_flush] = _ao_lisp_atom_flush, [builtin_delay] = _ao_lisp_atom_delay, [builtin_led] = _ao_lisp_atom_led, }; @@ -200,6 +204,16 @@ ao_lisp_last(struct ao_lisp_cons *cons) return AO_LISP_NIL; } +ao_poly +ao_lisp_length(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)))); +} + ao_poly ao_lisp_quote(struct ao_lisp_cons *cons) { @@ -470,6 +484,35 @@ ao_lisp_greater_equal(struct ao_lisp_cons *cons) return ao_lisp_compare(cons, builtin_greater_equal); } +ao_poly +ao_lisp_pack(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_pack, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_pack, cons, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_unpack(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_unpack, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_unpack, cons, 0, AO_LISP_STRING, 0)) + return AO_LISP_NIL; + return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_flush(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0)) + return AO_LISP_NIL; + ao_lisp_os_flush(); + return _ao_lisp_atom_t; +} + ao_poly ao_lisp_led(struct ao_lisp_cons *cons) { @@ -524,6 +567,7 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_cdr] = ao_lisp_cdr, [builtin_cons] = ao_lisp_cons, [builtin_last] = ao_lisp_last, + [builtin_length] = ao_lisp_length, [builtin_quote] = ao_lisp_quote, [builtin_set] = ao_lisp_set, [builtin_setq] = ao_lisp_setq, @@ -542,6 +586,9 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_greater] = ao_lisp_greater, [builtin_less_equal] = ao_lisp_less_equal, [builtin_greater_equal] = ao_lisp_greater_equal, + [builtin_pack] = ao_lisp_pack, + [builtin_unpack] = ao_lisp_unpack, + [builtin_flush] = ao_lisp_flush, [builtin_led] = ao_lisp_led, [builtin_delay] = ao_lisp_delay, }; diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index cd8a8d1d..b75ffaa0 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -107,3 +107,14 @@ ao_lisp_cons_patom(ao_poly c) cons = ao_lisp_poly_cons(cons->cdr); } } + +int +ao_lisp_cons_length(struct ao_lisp_cons *cons) +{ + int len = 0; + while (cons) { + len++; + cons = ao_lisp_poly_cons(cons->cdr); + } + return len; +} diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 8eafb187..c53a38fd 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -49,17 +49,6 @@ const struct ao_lisp_type ao_lisp_lambda_type = { .move = lambda_move, }; -static int -ao_lisp_cons_length(struct ao_lisp_cons *cons) -{ - int len = 0; - while (cons) { - len++; - cons = ao_lisp_poly_cons(cons->cdr); - } - return len; -} - void ao_lisp_lambda_print(ao_poly poly) { diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 4fc43e58..0b3e25a6 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -43,6 +43,7 @@ struct builtin_func funcs[] = { "cdr", AO_LISP_FUNC_LAMBDA, builtin_cdr, "cons", AO_LISP_FUNC_LAMBDA, builtin_cons, "last", AO_LISP_FUNC_LAMBDA, builtin_last, + "length", AO_LISP_FUNC_LAMBDA, builtin_length, "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, "set", AO_LISP_FUNC_LAMBDA, builtin_set, "setq", AO_LISP_FUNC_MACRO, builtin_setq, @@ -61,6 +62,9 @@ struct builtin_func funcs[] = { ">", AO_LISP_FUNC_LEXPR, builtin_greater, "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, + "pack", AO_LISP_FUNC_LAMBDA, builtin_pack, + "unpack", AO_LISP_FUNC_LAMBDA, builtin_unpack, + "flush", AO_LISP_FUNC_LAMBDA, builtin_flush, "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, "led", AO_LISP_FUNC_LEXPR, builtin_led, }; diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h index 55ffed50..b7bf7a2c 100644 --- a/src/lisp/ao_lisp_os.h +++ b/src/lisp/ao_lisp_os.h @@ -27,6 +27,11 @@ ao_lisp_getc() { return getchar(); } +static inline void +ao_lisp_os_flush() { + fflush(stdout); +} + static inline void ao_lisp_abort(void) { diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 0064064c..9ee1a7dd 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -34,6 +34,12 @@ static void string_move(void *addr) (void) addr; } +const struct ao_lisp_type ao_lisp_string_type = { + .mark = string_mark, + .size = string_size, + .move = string_move, +}; + char * ao_lisp_string_new(int len) { char *a = ao_lisp_alloc(len + 1); @@ -68,11 +74,47 @@ ao_lisp_string_cat(char *a, char *b) return r; } -const struct ao_lisp_type ao_lisp_string_type = { - .mark = string_mark, - .size = string_size, - .move = string_move, -}; +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons) +{ + int len = ao_lisp_cons_length(cons); + char *r = ao_lisp_alloc(len + 1); + char *s = r; + + while (cons) { + if (ao_lisp_poly_type(cons->car) != AO_LISP_INT) + return ao_lisp_error(AO_LISP_INVALID, "non-int passed to pack"); + *s++ = ao_lisp_poly_int(cons->car); + cons = ao_lisp_poly_cons(cons->cdr); + } + *s++ = 0; + return ao_lisp_string_poly(r); +} + +ao_poly +ao_lisp_string_unpack(char *a) +{ + struct ao_lisp_cons *cons = NULL, *tail = NULL; + int c; + + ao_lisp_root_add(&ao_lisp_cons_type, &cons); + ao_lisp_root_add(&ao_lisp_cons_type, &tail); + while ((c = *a++)) { + struct ao_lisp_cons *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); + if (!n) { + cons = NULL; + break; + } + if (tail) + tail->cdr = ao_lisp_cons_poly(n); + else + cons = n; + tail = n; + } + ao_lisp_root_clear(&cons); + ao_lisp_root_clear(&tail); + return ao_lisp_cons_poly(cons); +} void ao_lisp_string_print(ao_poly p) diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h index 19bd4f64..c979697e 100644 --- a/src/test/ao_lisp_os.h +++ b/src/test/ao_lisp_os.h @@ -24,6 +24,11 @@ extern int ao_lisp_getc(void); +static inline void +ao_lisp_os_flush() { + fflush(stdout); +} + static inline void ao_lisp_abort(void) { -- cgit v1.2.3 From 29c890b4599b3bbdbd09a5915ea68a63f4e0a9ac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 21:11:13 -0800 Subject: altos/lisp: Make sure memmove only happens once per object. Other GC fixes The memmove may be overlapping, so make sure it happens only once by just checking whether move_size has been set, rather than looking at ao_lisp_moving; that doesn't get set when moving a noted cons as that still needs to be walked at a later time. Fix up the various looping move functions to all use the same pattern. Atom was busted. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_atom.c | 12 +++++-- src/lisp/ao_lisp_cons.c | 23 +++++++++---- src/lisp/ao_lisp_eval.c | 6 +++- src/lisp/ao_lisp_frame.c | 6 ++-- src/lisp/ao_lisp_mem.c | 85 ++++++++++++++++++++++++++---------------------- 5 files changed, 81 insertions(+), 51 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index efa4f621..e1d9b082 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -46,11 +46,19 @@ static void atom_mark(void *addr) static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; + int ret; for (;;) { - if (ao_lisp_poly_move(&atom->next, 0)) + struct ao_lisp_atom *next = ao_lisp_poly_atom(atom->next); + + if (!next) break; - atom = ao_lisp_poly_atom(atom->next); + ret = ao_lisp_move_memory((void **) &next, atom_size(next)); + if (next != ao_lisp_poly_atom(atom->next)) + atom->next = ao_lisp_atom_poly(next); + if (ret) + break; + atom = next; } } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index b75ffaa0..c7d8382f 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -49,6 +49,8 @@ static void cons_move(void *addr) (void) ao_lisp_poly_move(&cons->car, 1); cdr = ao_lisp_poly_cons(cons->cdr); + if (!cdr) + break; ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); if (cdr != ao_lisp_poly_cons(cons->cdr)) cons->cdr = ao_lisp_cons_poly(cdr); @@ -64,20 +66,29 @@ const struct ao_lisp_type ao_lisp_cons_type = { .move = cons_move, }; +static ao_poly cons_car; +static struct ao_lisp_cons *cons_cdr; +static int been_here; + struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - ao_lisp_root_add(&ao_lisp_cons_type, &cdr); - ao_lisp_root_poly_add(&car); + if (!been_here) { + ao_lisp_root_add(&ao_lisp_cons_type, &cons_cdr); + ao_lisp_root_poly_add(&cons_car); + been_here = 1; + } + cons_car = car; + cons_cdr = cdr; cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); - ao_lisp_root_clear(&car); - ao_lisp_root_clear(&cdr); if (!cons) return NULL; - cons->car = car; - cons->cdr = ao_lisp_cons_poly(cdr); + cons->car = cons_car; + cons->cdr = ao_lisp_cons_poly(cons_cdr); + cons_car = AO_LISP_NIL; + cons_cdr = NULL; return cons; } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index ae2436b8..1c929869 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -32,6 +32,7 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->values, 0); /* no need to mark values_tail */ ao_lisp_poly_mark(stack->frame, 0); + ao_lisp_poly_mark(stack->list, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -47,12 +48,15 @@ stack_move(void *addr) while (stack) { struct ao_lisp_stack *prev; - int ret; + int ret; (void) ao_lisp_poly_move(&stack->sexprs, 0); (void) ao_lisp_poly_move(&stack->values, 0); (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); + (void) ao_lisp_poly_move(&stack->list, 0); prev = ao_lisp_poly_stack(stack->prev); + if (!prev) + break; ret = ao_lisp_move_memory((void **) &prev, sizeof (struct ao_lisp_stack)); if (prev != ao_lisp_poly_stack(stack->prev)) diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 90344719..082860ee 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -83,9 +83,9 @@ frame_move(void *addr) ao_lisp_poly_move(&v->val, 0); } next = ao_lisp_poly_frame(frame->next); - ret = 1; - if (next) - ret = ao_lisp_move_memory((void **) &next, frame_size(next)); + if (!next) + break; + ret = ao_lisp_move_memory((void **) &next, frame_size(next)); if (next != ao_lisp_poly_frame(frame->next)) frame->next = ao_lisp_frame_poly(next); if (ret) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 1fb1b459..31ee9e1e 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,22 +36,20 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#include #define MDBG_INCLUDE -#define MDBG_DUMP 1 -#define MDBG_MOVE 0 +#if 1 +#define MDBG_MOVE(...) do { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } while (0) +#endif #define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define MDBG(...) printf(__VA_ARGS__) #define MDBG_DO(a) a -static int move_dump = MDBG_MOVE; static int move_depth; -#define MDBG_RESET() (move_depth = 0) -#define MDBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) #define MDBG_MOVE_IN() (move_depth++) -#define MDBG_MOVE_OUT() (move_depth--) +#define MDBG_MOVE_OUT() (assert(--move_depth >= 0)) #else #define MDBG(...) #define MDBG_DO(a) -#define MDBG_RESET() #define MDBG_MOVE(...) #define MDBG_MOVE_IN() #define MDBG_MOVE_OUT() @@ -68,10 +66,12 @@ struct ao_lisp_root { static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; -static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons_note[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; +#define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) + +static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_moving[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_cons_note[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_cons_last[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; @@ -167,9 +167,9 @@ busy_object(uint8_t *tag, void *addr) { static void note_cons(void *addr) { - MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); if (AO_LISP_IS_POOL(addr)) { int offset = (uint8_t *) addr - ao_lisp_pool; + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); ao_lisp_cons_noted = 1; mark(ao_lisp_cons_note, offset); } @@ -180,9 +180,9 @@ note_cons(void *addr) */ static void -walk_all(uint8_t *tag, - int (*visit_addr)(const struct ao_lisp_type *type, void **addr), - int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) +walk(uint8_t *tag, + int (*visit_addr)(const struct ao_lisp_type *type, void **addr), + int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) { int i; @@ -193,13 +193,13 @@ walk_all(uint8_t *tag, if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - MDBG("root %d\n", MDBG_OFFSET(v)); + MDBG("root ptr %d\n", MDBG_OFFSET(v)); visit_addr(ao_lisp_root[i].type, a); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - MDBG("root 0x%04x\n", p); + MDBG("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); visit_poly(a, 0); } } @@ -211,7 +211,7 @@ walk_all(uint8_t *tag, for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - MDBG("cons %d\n", MDBG_OFFSET(v)); + MDBG("root cons %d\n", MDBG_OFFSET(v)); visit_addr(&ao_lisp_cons_type, &v); } } @@ -221,12 +221,6 @@ walk_all(uint8_t *tag, static void *move_old, *move_new; static int move_size; -static void -move_object(void) -{ - walk_all(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); -} - #if MDBG_DUMP static void dump_busy(void) @@ -273,12 +267,6 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } -static void -ao_lisp_mark_busy(void) -{ - walk_all(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); -} - void ao_lisp_collect(void) { @@ -287,7 +275,7 @@ ao_lisp_collect(void) MDBG("collect\n"); /* Mark */ - ao_lisp_mark_busy(); + walk(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); DUMP_BUSY(); /* Compact */ @@ -300,10 +288,11 @@ ao_lisp_collect(void) while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { MDBG("busy %d -> %d\n", i, top); + MDBG_MOVE_IN(); move_old = &ao_lisp_pool[i]; move_new = &ao_lisp_pool[top]; move_size = 0; - move_object(); + walk(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); MDBG("\tbusy size %d\n", move_size); if (move_size == 0) ao_lisp_abort(); @@ -318,6 +307,7 @@ ao_lisp_collect(void) #if MDBG_MOVE DUMP_BUSY(); #endif + MDBG_MOVE_OUT(); } else { i += 4; } @@ -331,9 +321,15 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (!addr) return 1; - if (mark_object(ao_lisp_busy, addr, type->size(addr))) + MDBG_MOVE_IN(); + MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr)); + if (mark_object(ao_lisp_busy, addr, type->size(addr))) { + MDBG_MOVE("already marked\n"); + MDBG_MOVE_OUT(); return 1; + } type->mark(addr); + MDBG_MOVE_OUT(); return 0; } @@ -345,6 +341,7 @@ ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) if (!p) return 1; if (type == AO_LISP_CONS && do_note_cons) { + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(ao_lisp_ref(p))); note_cons(ao_lisp_ref(p)); return 0; } else { @@ -371,7 +368,7 @@ void * ao_lisp_move_map(void *addr) { if (addr == move_old) { - if (busy_object(ao_lisp_moving, addr)) + if (move_size != 0) return move_new; } return addr; @@ -382,7 +379,13 @@ check_move(void *addr, int size) { if (addr == move_old) { MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); - if (!busy_object(ao_lisp_moving, addr)) { + if (move_size && move_size != ((size + 3) & ~3)) + ao_lisp_abort(); + + /* Only copy the object once, otherwise we may + * smash stuff + */ + if (move_size == 0) { MDBG_MOVE(" copy %d\n", size); memmove(move_new, move_old, size); move_size = (size + 3) & ~3; @@ -397,7 +400,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; uint8_t *a = addr; - int size = type->size(addr); + int size = type->size(ao_lisp_move_map(addr)); if (!addr) return 1; @@ -462,9 +465,13 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); + + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { - note_cons(addr); addr = check_move(addr, sizeof (struct ao_lisp_cons)); + note_cons(addr); ret = 1; } else { @@ -482,8 +489,8 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - MDBG("poly %d moved %04x -> %04x\n", - type, p, np); + MDBG("poly %d moved %d -> %d\n", + type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); *ref = np; } return ret; -- cgit v1.2.3 From ddb4b8d90478ae324aa207a7541352c1ac9451ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 18:45:12 -0800 Subject: altos/lisp: Change GC to do moves in batches of 32 This should make it quite a bit faster than doing one at a time. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 69 ++++- src/lisp/ao_lisp_atom.c | 14 +- src/lisp/ao_lisp_cons.c | 32 +- src/lisp/ao_lisp_eval.c | 21 +- src/lisp/ao_lisp_frame.c | 48 +-- src/lisp/ao_lisp_lambda.c | 3 + src/lisp/ao_lisp_mem.c | 745 ++++++++++++++++++++++++++++++++-------------- src/lisp/ao_lisp_read.c | 64 ++-- src/lisp/ao_lisp_string.c | 33 +- 9 files changed, 674 insertions(+), 355 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index ea3d2a09..906bae19 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -134,6 +134,7 @@ struct ao_lisp_type { int (*size)(void *addr); void (*mark)(void *addr); void (*move)(void *addr); + char name[]; }; struct ao_lisp_cons { @@ -304,11 +305,17 @@ ao_lisp_other_poly(const void *other) } static inline int -ao_lisp_mem_round(int size) +ao_lisp_size_round(int size) { return (size + 3) & ~3; } +static inline int +ao_lisp_size(const struct ao_lisp_type *type, void *addr) +{ + return ao_lisp_size_round(type->size(addr)); +} + #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) static inline int ao_lisp_poly_base_type(ao_poly poly) { @@ -389,7 +396,7 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ int -ao_lisp_mark_memory(void *addr, int size); +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr); void * ao_lisp_move_map(void *addr); @@ -400,7 +407,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref); /* returns 1 if the object was already moved */ int -ao_lisp_move_memory(void **ref, int size); +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref); void * ao_lisp_alloc(int size); @@ -408,14 +415,23 @@ ao_lisp_alloc(int size); void ao_lisp_collect(void); -int -ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons); -int -ao_lisp_root_poly_add(ao_poly *p); +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id); void -ao_lisp_root_clear(void *addr); +ao_lisp_string_stash(int id, char *string); + +char * +ao_lisp_string_fetch(int id); + +void +ao_lisp_poly_stash(int id, ao_poly poly); + +ao_poly +ao_lisp_poly_fetch(int id); /* cons */ extern const struct ao_lisp_type ao_lisp_cons_type; @@ -435,9 +451,6 @@ ao_lisp_cons_length(struct ao_lisp_cons *cons); /* string */ extern const struct ao_lisp_type ao_lisp_string_type; -char * -ao_lisp_string_new(int len); - char * ao_lisp_string_copy(char *a); @@ -529,6 +542,10 @@ char * ao_lisp_args_name(uint8_t args); /* read */ +extern struct ao_lisp_cons *ao_lisp_read_cons; +extern struct ao_lisp_cons *ao_lisp_read_cons_tail; +extern struct ao_lisp_cons *ao_lisp_read_stack; + ao_poly ao_lisp_read(void); @@ -585,6 +602,8 @@ ao_lisp_restore(struct ao_lisp_cons *cons); /* error */ +extern const struct ao_lisp_type ao_lisp_stack_type; + void ao_lisp_stack_print(void); @@ -631,4 +650,32 @@ ao_lisp_frames_dump(void) #define DBG_FRAMES() #endif +#define DBG_MEM 1 +#define DBG_MEM_START 1 + +#if DBG_MEM + +#include +extern int dbg_move_depth; +#define MDBG_DUMP 1 +#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) + +extern int dbg_mem; + +#define MDBG_DO(a) a +#define MDBG_MOVE(...) do { if (dbg_mem) { int d; for (d = 0; d < dbg_move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define MDBG_MORE(...) do { if (dbg_mem) printf(__VA_ARGS__); } while (0) +#define MDBG_MOVE_IN() (dbg_move_depth++) +#define MDBG_MOVE_OUT() (assert(--dbg_move_depth >= 0)) + +#else + +#define MDBG_DO(a) +#define MDBG_MOVE(...) +#define MDBG_MORE(...) +#define MDBG_MOVE_IN() +#define MDBG_MOVE_OUT() + +#endif + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index e1d9b082..6705f140 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -38,7 +38,7 @@ static void atom_mark(void *addr) atom = ao_lisp_poly_atom(atom->next); if (!atom) break; - if (ao_lisp_mark_memory(atom, atom_size(atom))) + if (ao_lisp_mark_memory(&ao_lisp_atom_type, atom)) break; } } @@ -53,7 +53,7 @@ static void atom_move(void *addr) if (!next) break; - ret = ao_lisp_move_memory((void **) &next, atom_size(next)); + ret = ao_lisp_move_memory(&ao_lisp_atom_type, (void **) &next); if (next != ao_lisp_poly_atom(atom->next)) atom->next = ao_lisp_atom_poly(next); if (ret) @@ -66,6 +66,7 @@ const struct ao_lisp_type ao_lisp_atom_type = { .mark = atom_mark, .size = atom_size, .move = atom_move, + .name = "atom" }; struct ao_lisp_atom *ao_lisp_atoms; @@ -85,12 +86,12 @@ ao_lisp_atom_intern(char *name) return atom; } #endif + ao_lisp_string_stash(0, name); atom = ao_lisp_alloc(name_size(name)); + name = ao_lisp_string_fetch(0); if (atom) { atom->type = AO_LISP_ATOM; atom->next = ao_lisp_atom_poly(ao_lisp_atoms); - if (!ao_lisp_atoms) - ao_lisp_root_add(&ao_lisp_atom_type, &ao_lisp_atoms); ao_lisp_atoms = atom; strcpy(atom->name, name); } @@ -103,11 +104,8 @@ struct ao_lisp_frame *ao_lisp_frame_current; static void ao_lisp_atom_init(void) { - if (!ao_lisp_frame_global) { + if (!ao_lisp_frame_global) ao_lisp_frame_global = ao_lisp_frame_new(0); - ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_global); - ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_current); - } } static ao_poly * diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index c7d8382f..311d63ab 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -14,8 +14,6 @@ #include "ao_lisp.h" -#define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) - static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -25,7 +23,7 @@ static void cons_mark(void *addr) cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; - if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) + if (ao_lisp_mark_memory(&ao_lisp_cons_type, cons)) break; } } @@ -47,13 +45,17 @@ static void cons_move(void *addr) struct ao_lisp_cons *cdr; int ret; + MDBG_MOVE("cons_move start %d (%d, %d)\n", + MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); (void) ao_lisp_poly_move(&cons->car, 1); cdr = ao_lisp_poly_cons(cons->cdr); if (!cdr) break; - ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); + ret = ao_lisp_move_memory(&ao_lisp_cons_type, (void **) &cdr); if (cdr != ao_lisp_poly_cons(cons->cdr)) cons->cdr = ao_lisp_cons_poly(cdr); + MDBG_MOVE("cons_move end %d (%d, %d)\n", + MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); if (ret) break; cons = cdr; @@ -64,31 +66,23 @@ const struct ao_lisp_type ao_lisp_cons_type = { .mark = cons_mark, .size = cons_size, .move = cons_move, + .name = "cons", }; -static ao_poly cons_car; -static struct ao_lisp_cons *cons_cdr; -static int been_here; - struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - if (!been_here) { - ao_lisp_root_add(&ao_lisp_cons_type, &cons_cdr); - ao_lisp_root_poly_add(&cons_car); - been_here = 1; - } - cons_car = car; - cons_cdr = cdr; + ao_lisp_poly_stash(0, car); + ao_lisp_cons_stash(0, cdr); cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + car = ao_lisp_poly_fetch(0); + cdr = ao_lisp_cons_fetch(0); if (!cons) return NULL; - cons->car = cons_car; - cons->cdr = ao_lisp_cons_poly(cons_cdr); - cons_car = AO_LISP_NIL; - cons_cdr = NULL; + cons->car = car; + cons->cdr = ao_lisp_cons_poly(cdr); return cons; } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index f945bc16..04d0e70a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -16,6 +16,8 @@ #include "ao_lisp.h" #include +const struct ao_lisp_type ao_lisp_stack_type; + static int stack_size(void *addr) { @@ -34,13 +36,11 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->frame, 0); ao_lisp_poly_mark(stack->list, 0); stack = ao_lisp_poly_stack(stack->prev); - if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) + if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack)) break; } } -static const struct ao_lisp_type ao_lisp_stack_type; - static void stack_move(void *addr) { @@ -57,8 +57,7 @@ stack_move(void *addr) prev = ao_lisp_poly_stack(stack->prev); if (!prev) break; - ret = ao_lisp_move_memory((void **) &prev, - sizeof (struct ao_lisp_stack)); + ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); if (ret) @@ -67,10 +66,11 @@ stack_move(void *addr) } } -static const struct ao_lisp_type ao_lisp_stack_type = { +const struct ao_lisp_type ao_lisp_stack_type = { .size = stack_size, .mark = stack_mark, - .move = stack_move + .move = stack_move, + .name = "stack" }; struct ao_lisp_stack *ao_lisp_stack; @@ -567,14 +567,7 @@ ao_lisp_eval_restart(void) ao_poly ao_lisp_eval(ao_poly _v) { - static uint8_t been_here; - ao_lisp_v = _v; - if (!been_here) { - been_here = 1; - ao_lisp_root_add(&ao_lisp_stack_type, &ao_lisp_stack); - ao_lisp_root_poly_add(&ao_lisp_v); - } if (!ao_lisp_stack_push()) return AO_LISP_NIL; diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 082860ee..e23a6413 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -14,12 +14,6 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf(__VA_ARGS__) -#else -#define DBG(...) -#endif - static inline int frame_num_size(int num) { @@ -33,8 +27,6 @@ frame_size(void *addr) return frame_num_size(frame->num); } -#define OFFSET(a) ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const)) - static void frame_mark(void *addr) { @@ -42,22 +34,23 @@ frame_mark(void *addr) int f; for (;;) { - DBG("frame mark %p\n", frame); + MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_mark(v->val, 0); - DBG ("\tframe mark atom %s %d val %d at %d\n", - ao_lisp_poly_atom(v->atom)->name, - OFFSET(v->atom), OFFSET(v->val), f); + MDBG_MOVE("frame mark atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + MDBG_OFFSET(ao_lisp_ref(v->atom)), + MDBG_OFFSET(ao_lisp_ref(v->val)), f); } frame = ao_lisp_poly_frame(frame->next); - DBG("frame next %p\n", frame); + MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame)); if (!frame) break; - if (ao_lisp_mark_memory(frame, frame_size(frame))) + if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame)) break; } } @@ -72,22 +65,29 @@ frame_move(void *addr) struct ao_lisp_frame *next; int ret; - DBG("frame move %p\n", frame); + MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_move(&v->atom, 0); - DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); ao_lisp_poly_move(&v->val, 0); + MDBG_MOVE("frame move atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + MDBG_OFFSET(ao_lisp_ref(v->atom)), + MDBG_OFFSET(ao_lisp_ref(v->val)), f); } next = ao_lisp_poly_frame(frame->next); if (!next) break; - ret = ao_lisp_move_memory((void **) &next, frame_size(next)); - if (next != ao_lisp_poly_frame(frame->next)) + ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &next); + if (next != ao_lisp_poly_frame(frame->next)) { + MDBG_MOVE("frame next moved from %d to %d\n", + MDBG_OFFSET(ao_lisp_poly_frame(frame->next)), + MDBG_OFFSET(next)); frame->next = ao_lisp_frame_poly(next); + } if (ret) break; frame = next; @@ -97,7 +97,8 @@ frame_move(void *addr) const struct ao_lisp_type ao_lisp_frame_type = { .mark = frame_mark, .size = frame_size, - .move = frame_move + .move = frame_move, + .name = "frame", }; void @@ -206,8 +207,8 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) if (!ref) { int f; - ao_lisp_root_poly_add(&atom); - ao_lisp_root_poly_add(&val); + ao_lisp_poly_stash(0, atom); + ao_lisp_poly_stash(1, val); if (frame) { f = frame->num; frame = ao_lisp_frame_realloc(frame_ref, f + 1); @@ -215,12 +216,11 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) f = 0; frame = ao_lisp_frame_new(1); } - ao_lisp_root_clear(&atom); - ao_lisp_root_clear(&val); + atom = ao_lisp_poly_fetch(0); + val = ao_lisp_poly_fetch(1); if (!frame) return 0; *frame_ref = frame; - DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); frame->vals[f].atom = atom; ref = &frame->vals[f].val; } diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index c53a38fd..6020a8b8 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -47,6 +47,7 @@ const struct ao_lisp_type ao_lisp_lambda_type = { .size = lambda_size, .mark = lambda_mark, .move = lambda_move, + .name = "lambda", }; void @@ -68,7 +69,9 @@ ao_lisp_lambda_print(ao_poly poly) ao_poly ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) { + ao_lisp_cons_stash(0, code); struct ao_lisp_lambda *lambda = ao_lisp_alloc(sizeof (struct ao_lisp_lambda)); + code = ao_lisp_cons_fetch(0); struct ao_lisp_cons *arg; int f; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 0373f015..60f4bbee 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -18,64 +18,243 @@ #include #ifdef AO_LISP_MAKE_CONST + +/* + * When building the constant table, it is the + * pool for allocations. + */ + #include uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); #define ao_lisp_pool ao_lisp_const #undef AO_LISP_POOL #define AO_LISP_POOL AO_LISP_POOL_CONST + #else + uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); -#endif -#if 0 -#define MDBG_COLLECT_ALWAYS #endif #if 0 #define MDBG_POOL #endif -#if 0 -#include -#define MDBG_INCLUDE -#if 1 -#define MDBG_MOVE(...) do { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } while (0) -#endif -#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) -#define MDBG(...) printf(__VA_ARGS__) -#define MDBG_DO(a) a -static int move_depth; -#define MDBG_MOVE_IN() (move_depth++) -#define MDBG_MOVE_OUT() (assert(--move_depth >= 0)) +#if DBG_MEM +int dbg_move_depth; +int dbg_mem = DBG_MEM_START; +int dbg_collects = 0; +int dbg_validate = 0; + +struct ao_lisp_record { + struct ao_lisp_record *next; + const struct ao_lisp_type *type; + void *addr; + int size; +}; + +static struct ao_lisp_record *record_head, **record_tail; + +static void +ao_lisp_record_free(struct ao_lisp_record *record) +{ + while (record) { + struct ao_lisp_record *next = record->next; + free(record); + record = next; + } +} + +static void +ao_lisp_record_reset(void) +{ + ao_lisp_record_free(record_head); + record_head = NULL; + record_tail = &record_head; +} + +static void +ao_lisp_record(const struct ao_lisp_type *type, + void *addr, + int size) +{ + struct ao_lisp_record *r = malloc(sizeof (struct ao_lisp_record)); + + r->next = NULL; + r->type = type; + r->addr = addr; + r->size = size; + *record_tail = r; + record_tail = &r->next; +} + +static struct ao_lisp_record * +ao_lisp_record_save(void) +{ + struct ao_lisp_record *r = record_head; + + record_head = NULL; + record_tail = &record_head; + return r; +} + +static void +ao_lisp_record_compare(char *where, + struct ao_lisp_record *a, + struct ao_lisp_record *b) +{ + while (a && b) { + if (a->type != b->type || a->size != b->size) { + printf("%s record difers %d %s %d -> %d %s %d\n", + where, + MDBG_OFFSET(a->addr), + a->type->name, + a->size, + MDBG_OFFSET(b->addr), + b->type->name, + b->size); + ao_lisp_abort(); + } + a = a->next; + b = b->next; + } + if (a) { + printf("%s record differs %d %s %d -> NULL\n", + where, + MDBG_OFFSET(a->addr), + a->type->name, + a->size); + ao_lisp_abort(); + } + if (b) { + printf("%s record differs NULL -> %d %s %d\n", + where, + MDBG_OFFSET(b->addr), + b->type->name, + b->size); + ao_lisp_abort(); + } +} + #else -#define MDBG(...) -#define MDBG_DO(a) -#define MDBG_MOVE(...) -#define MDBG_MOVE_IN() -#define MDBG_MOVE_OUT() +#define ao_lisp_record_reset() #endif uint8_t ao_lisp_exception; struct ao_lisp_root { - void **addr; const struct ao_lisp_type *type; + void **addr; }; -#define AO_LISP_ROOT 16 +static struct ao_lisp_cons *save_cons[2]; +static char *save_string[2]; +static ao_poly save_poly[2]; + +static const struct ao_lisp_root ao_lisp_root[] = { + { + .type = &ao_lisp_cons_type, + .addr = (void **) &save_cons[0], + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &save_cons[1], + }, + { + .type = &ao_lisp_string_type, + .addr = (void **) &save_string[0] + }, + { + .type = &ao_lisp_string_type, + .addr = (void **) &save_string[1] + }, + { + .type = NULL, + .addr = (void **) &save_poly[0] + }, + { + .type = NULL, + .addr = (void **) &save_poly[1] + }, + { + .type = &ao_lisp_atom_type, + .addr = (void **) &ao_lisp_atoms + }, + { + .type = &ao_lisp_frame_type, + .addr = (void **) &ao_lisp_frame_global, + }, + { + .type = &ao_lisp_frame_type, + .addr = (void **) &ao_lisp_frame_current, + }, + { + .type = &ao_lisp_stack_type, + .addr = (void **) &ao_lisp_stack, + }, + { + .type = NULL, + .addr = (void **) &ao_lisp_v, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_cons, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_cons_tail, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_stack, + }, +}; -static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; +#define AO_LISP_ROOT (sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0])) #define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; -static uint8_t ao_lisp_moving[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_note[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_last[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; +struct ao_lisp_chunk { + uint16_t old_addr; + union { + uint16_t size; + uint16_t new_addr; + }; +}; + +#define AO_LISP_NCHUNK 32 + +static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK]; + +/* Offset of an address within the pool. */ +static inline uint16_t pool_offset(void *addr) { + if (!AO_LISP_IS_POOL(addr)) + ao_lisp_abort(); + return ((uint8_t *) addr) - ao_lisp_pool; +} + +/* + * Convert back and forth between 'poly's used + * as short addresses in the pool and addresses. + * These are used in the chunk code. + */ +static inline ao_poly pool_poly(void *addr) { + if (!AO_LISP_IS_POOL(addr)) + ao_lisp_abort(); + return ((uint8_t *) addr) - AO_LISP_POOL_BASE; +} + +static inline void *pool_ref(ao_poly p) { + return AO_LISP_POOL_BASE + p; +} + static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; @@ -101,24 +280,28 @@ static inline int limit(int offset) { return min(AO_LISP_POOL, max(offset, 0)); } +static int total_marked; + +/* + * Mark a range of addresses + */ static int mark_object(uint8_t *tag, void *addr, int size) { int base; int bound; - if (!addr) - return 1; + MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) + ao_lisp_abort()); - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) - return 1; - - base = (uint8_t *) addr - ao_lisp_pool; + base = pool_offset(addr); bound = base + size; - base = limit(base); - bound = limit(bound); + MDBG_DO(if (bound > ao_lisp_top) ao_lisp_abort()); + if (busy(tag, base)) return 1; + if (tag == ao_lisp_busy) + total_marked += size; while (base < bound) { mark(tag, base); base += 4; @@ -126,12 +309,14 @@ mark_object(uint8_t *tag, void *addr, int size) { return 0; } +MDBG_DO( static int clear_object(uint8_t *tag, void *addr, int size) { int base; int bound; - if (!addr) - return 1; + + MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) + ao_lisp_abort()); base = (uint8_t *) addr - ao_lisp_pool; bound = base + size; @@ -140,29 +325,13 @@ clear_object(uint8_t *tag, void *addr, int size) { bound = limit(bound); if (!busy(tag, base)) return 1; + total_marked -= size; while (base < bound) { clear(tag, base); base += 4; } return 0; -} - -static int -busy_object(uint8_t *tag, void *addr) { - int base; - - if (!addr) - return 1; - - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) - return 1; - - base = (uint8_t *) addr - ao_lisp_pool; - base = limit(base); - if (busy(tag, base)) - return 1; - return 0; -} +}) static void note_cons(void *addr) @@ -175,31 +344,63 @@ note_cons(void *addr) } } +static uint16_t chunk_low; +static uint16_t chunk_first, chunk_last; + +static void +note_chunk(uint16_t addr, uint16_t size) +{ + int i; + + if (addr < chunk_low) + return; + + for (i = 0; i < AO_LISP_NCHUNK; i++) { + if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { + if (ao_lisp_chunk[i].size != size) + ao_lisp_abort(); + return; + } + if (ao_lisp_chunk[i].old_addr > addr) { + memmove(&ao_lisp_chunk[i+1], + &ao_lisp_chunk[i], + (AO_LISP_NCHUNK - (i+1)) * sizeof (struct ao_lisp_chunk)); + ao_lisp_chunk[i].size = 0; + } + if (ao_lisp_chunk[i].size == 0) { + ao_lisp_chunk[i].old_addr = addr; + ao_lisp_chunk[i].size = size; + return; + } + } +} + /* * Walk all referenced objects calling functions on each one */ static void -walk(uint8_t *tag, - int (*visit_addr)(const struct ao_lisp_type *type, void **addr), +walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) { int i; - memset(tag, '\0', sizeof (ao_lisp_busy)); + total_marked = 0; + ao_lisp_record_reset(); + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - MDBG("root ptr %d\n", MDBG_OFFSET(v)); + MDBG_MOVE("root ptr %d\n", MDBG_OFFSET(v)); visit_addr(ao_lisp_root[i].type, a); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - MDBG("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); + MDBG_MOVE("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); visit_poly(a, 0); } } @@ -211,33 +412,32 @@ walk(uint8_t *tag, for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - MDBG("root cons %d\n", MDBG_OFFSET(v)); + MDBG_MOVE("root cons %d\n", MDBG_OFFSET(v)); visit_addr(&ao_lisp_cons_type, &v); } } } } -static void *move_old, *move_new; -static int move_size; - #if MDBG_DUMP static void dump_busy(void) { int i; - printf("busy:"); + MDBG_MOVE("busy:"); for (i = 0; i < ao_lisp_top; i += 4) { - if ((i & 0xff) == 0) - printf("\n"); + if ((i & 0xff) == 0) { + MDBG_MORE("\n"); + MDBG_MOVE("%s", ""); + } else if ((i & 0x1f) == 0) - printf(" "); + MDBG_MORE(" "); if (busy(ao_lisp_busy, i)) - putchar('*'); + MDBG_MORE("*"); else - putchar('-'); + MDBG_MORE("-"); } - printf ("\n"); + MDBG_MORE ("\n"); } #define DUMP_BUSY() dump_busy() #else @@ -272,183 +472,241 @@ ao_lisp_collect(void) { int i; int top; +#if DBG_MEM + int loops = 0; + int marked; + int moved; + struct ao_lisp_record *mark_record = NULL, *move_record = NULL; + + ++dbg_collects; + MDBG_MOVE("collect %d\n", dbg_collects); + marked = moved = 0; +#endif + chunk_low = 0; + top = 0; + for (;;) { + MDBG_DO(loops++); + MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); + /* Find the sizes of the first chunk of objects to move */ + memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +#if DBG_MEM + marked = total_marked; + + ao_lisp_record_free(mark_record); + mark_record = ao_lisp_record_save(); + if (mark_record && move_record) + ao_lisp_record_compare("mark", move_record, mark_record); + + if (moved && moved != marked) + ao_lisp_abort(); +#endif - MDBG("collect\n"); - /* Mark */ - walk(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); + DUMP_BUSY(); - DUMP_BUSY(); - /* Compact */ - MDBG("find first busy\n"); - for (i = 0; i < ao_lisp_top; i += 4) { - if (!busy(ao_lisp_busy, i)) - break; - } - top = i; - while(i < ao_lisp_top) { - if (busy(ao_lisp_busy, i)) { - MDBG("busy %d -> %d\n", i, top); - MDBG_MOVE_IN(); - move_old = &ao_lisp_pool[i]; - move_new = &ao_lisp_pool[top]; - move_size = 0; - walk(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); - MDBG("\tbusy size %d\n", move_size); - if (move_size == 0) + /* Find the first moving object */ + for (i = 0; i < AO_LISP_NCHUNK; i++) { + uint16_t size = ao_lisp_chunk[i].size; + + if (!size) + break; + + if (ao_lisp_chunk[i].old_addr > top) + break; + if (ao_lisp_chunk[i].old_addr != top) + ao_lisp_abort(); + + top += size; + MDBG_MOVE("chunk %d %d not moving\n", + ao_lisp_chunk[i].old_addr, + ao_lisp_chunk[i].size); + chunk_low = ao_lisp_chunk[i].old_addr + size; + } + + chunk_first = i; + /* Copy all of the objects */ + for (; i < AO_LISP_NCHUNK; i++) { + uint16_t size = ao_lisp_chunk[i].size; + + if (!size) + break; + + MDBG_MOVE("chunk %d %d -> %d\n", + ao_lisp_chunk[i].old_addr, + size, + top); + ao_lisp_chunk[i].new_addr = top; + memmove(&ao_lisp_pool[top], + &ao_lisp_pool[ao_lisp_chunk[i].old_addr], + size); + MDBG_DO(clear_object(ao_lisp_busy, &ao_lisp_pool[ao_lisp_chunk[i].old_addr], size)); + MDBG_DO(mark_object(ao_lisp_busy, &ao_lisp_pool[top], size)); + top += size; + chunk_low = ao_lisp_chunk[i].old_addr + size; + } + + MDBG_MOVE("after moving objects, busy is now:\n"); + DUMP_BUSY(); + chunk_last = i; + + if (chunk_first < chunk_last) { + /* Relocate all references to the objects */ + walk(ao_lisp_move, ao_lisp_poly_move); + +#if DBG_MEM + ao_lisp_record_free(move_record); + move_record = ao_lisp_record_save(); + if (mark_record && move_record) + ao_lisp_record_compare("move", mark_record, move_record); + + moved = total_marked; + if (moved != marked) ao_lisp_abort(); - clear_object(ao_lisp_busy, move_old, move_size); - mark_object(ao_lisp_busy, move_new, move_size); - if (busy_object(ao_lisp_cons_note, move_old)) { - clear_object(ao_lisp_cons_note, move_old, move_size); - mark_object(ao_lisp_cons_note, move_new, move_size); - } - i += move_size; - top += move_size; -#if MDBG_MOVE - DUMP_BUSY(); #endif - MDBG_MOVE_OUT(); - } else { - i += 4; } + + if (chunk_last != AO_LISP_NCHUNK) + break; } ao_lisp_top = top; + + MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); + +// printf ("collect. top %d loops %d\n", top, loops); } +/* + * Mark interfaces for objects + * + * Note a reference to memory and + * collect information about a few object sizes + * at a time + */ int -ao_lisp_mark(const struct ao_lisp_type *type, void *addr) +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr) { - if (!addr) + int size; + if (!AO_LISP_IS_POOL(addr)) return 1; - MDBG_MOVE_IN(); + + size = ao_lisp_size(type, addr); + MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr)); + if (!mark_object(ao_lisp_busy, addr, size)) { + note_chunk(pool_offset(addr), size); + MDBG_DO(ao_lisp_record(type, addr, size)); + return 0; + } + MDBG_MOVE("already marked\n"); + return 1; +} + +int +ao_lisp_mark(const struct ao_lisp_type *type, void *addr) +{ + int ret; MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr)); - if (mark_object(ao_lisp_busy, addr, type->size(addr))) { - MDBG_MOVE("already marked\n"); - MDBG_MOVE_OUT(); - return 1; + MDBG_MOVE_IN(); + ret = ao_lisp_mark_memory(type, addr); + if (!ret) { + MDBG_MOVE("mark recurse\n"); + type->mark(addr); } - type->mark(addr); MDBG_MOVE_OUT(); - return 0; + return ret; } int ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) { - uint8_t type = ao_lisp_poly_type(p); + uint8_t type; + void *addr; if (!p) return 1; + + type = ao_lisp_poly_base_type(p); + addr = ao_lisp_ref(p); + + if (!AO_LISP_IS_POOL(addr)) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { - MDBG_MOVE("note cons %d\n", MDBG_OFFSET(ao_lisp_ref(p))); note_cons(ao_lisp_ref(p)); - return 0; - } else { - const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; - if (lisp_type) - return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); return 1; - } -} + } else { + const struct ao_lisp_type *lisp_type; -int -ao_lisp_mark_memory(void *addr, int size) -{ - return mark_object(ao_lisp_busy, addr, size); -} + if (type == AO_LISP_OTHER) { + type = ao_lisp_other_type(ao_lisp_poly_other(p)); + if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) + ao_lisp_abort(); + } -/* - * After the object has been moved, we have to reference it - * in the new location. This is only relevant for ao_lisp_poly_move - * as it needs to fetch the type byte from the object, which - * may have been overwritten by the copy - */ -void * -ao_lisp_move_map(void *addr) -{ - if (addr == move_old) { - if (move_size != 0) - return move_new; + lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (!lisp_type) + return 1; + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); } - return addr; } static void * -check_move(void *addr, int size) +move_map(void *addr) { - if (addr == move_old) { - MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); - if (move_size && move_size != ((size + 3) & ~3)) - ao_lisp_abort(); - - /* Only copy the object once, otherwise we may - * smash stuff - */ - if (move_size == 0) { - MDBG_MOVE(" copy %d\n", size); - memmove(move_new, move_old, size); - move_size = (size + 3) & ~3; + uint16_t offset = pool_offset(addr); + int i; + + for (i = chunk_first; i < chunk_last; i++) { + if (ao_lisp_chunk[i].old_addr == offset) { + MDBG_MOVE("move %d -> %d\n", + ao_lisp_chunk[i].old_addr, + ao_lisp_chunk[i].new_addr); + return ao_lisp_pool + ao_lisp_chunk[i].new_addr; } - addr = move_new; } return addr; } int -ao_lisp_move(const struct ao_lisp_type *type, void **ref) +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; - uint8_t *a = addr; - int size = type->size(ao_lisp_move_map(addr)); + int size; - if (!addr) + if (!AO_LISP_IS_POOL(addr)) return 1; -#ifndef AO_LISP_MAKE_CONST - if (AO_LISP_IS_CONST(addr)) - return 1; -#endif - MDBG_MOVE("object %d\n", MDBG_OFFSET(addr)); - if (!AO_LISP_IS_POOL(a)) - ao_lisp_abort(); - MDBG_MOVE_IN(); - addr = check_move(addr, size); - if (addr != *ref) + MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); + addr = move_map(addr); + size = ao_lisp_size(type, addr); + if (addr != *ref) { + MDBG_MOVE("update ref %d %d -> %d\n", + AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1, + MDBG_OFFSET(*ref), MDBG_OFFSET(addr)); *ref = addr; - if (mark_object(ao_lisp_moving, addr, size)) { - MDBG_MOVE("already moved\n"); - MDBG_MOVE_OUT(); - return 1; } - MDBG_MOVE_OUT(); - MDBG_MOVE("recursing...\n"); - MDBG_MOVE_IN(); - type->move(addr); - MDBG_MOVE_OUT(); - MDBG_MOVE("done %d\n", MDBG_OFFSET(addr)); - return 0; + if (!mark_object(ao_lisp_busy, addr, size)) { + MDBG_DO(ao_lisp_record(type, addr, size)); + return 0; + } + MDBG_MOVE("already moved\n"); + return 1; } int -ao_lisp_move_memory(void **ref, int size) +ao_lisp_move(const struct ao_lisp_type *type, void **ref) { - void *addr = *ref; - if (!addr) - return 1; - - MDBG_MOVE("memory %d\n", MDBG_OFFSET(addr)); + int ret; + MDBG_MOVE("move object %d\n", MDBG_OFFSET(*ref)); MDBG_MOVE_IN(); - addr = check_move(addr, size); - if (addr != *ref) - *ref = addr; - if (mark_object(ao_lisp_moving, addr, size)) { - MDBG_MOVE("already moved\n"); - MDBG_MOVE_OUT(); - return 1; + ret = ao_lisp_move_memory(type, ref); + if (!ret) { + MDBG_MOVE("move recurse\n"); + type->move(*ref); } MDBG_MOVE_OUT(); - return 0; + return ret; } int @@ -456,7 +714,6 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) { uint8_t type; ao_poly p = *ref; - const struct ao_lisp_type *lisp_type; int ret; void *addr; @@ -466,20 +723,24 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + if (!AO_LISP_IS_POOL(addr)) return 1; if (type == AO_LISP_CONS && do_note_cons) { - addr = check_move(addr, sizeof (struct ao_lisp_cons)); +// addr = move_map(addr); + MDBG_DO(if (addr != move_map(addr)) MDBG_MOVE("noting cons at old addr %d instead of new addr %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_map(addr)));); + note_cons(addr); + addr = move_map(addr); ret = 1; } else { + const struct ao_lisp_type *lisp_type; - if (type == AO_LISP_OTHER) - type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); - - if (type >= AO_LISP_NUM_TYPE) - ao_lisp_abort(); + if (type == AO_LISP_OTHER) { + type = ao_lisp_other_type(move_map(ao_lisp_poly_other(p))); + if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) + ao_lisp_abort(); + } lisp_type = ao_lisp_types[type]; if (!lisp_type) @@ -487,10 +748,11 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) ret = ao_lisp_move(lisp_type, &addr); } + /* Re-write the poly value */ if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - MDBG("poly %d moved %d -> %d\n", - type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); + MDBG_MOVE("poly %d moved %d -> %d\n", + type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); *ref = np; } return ret; @@ -535,15 +797,28 @@ ao_lisp_poison(void) #define AO_LISP_POOL_CUR AO_LISP_POOL #endif +#if DBG_MEM +void +ao_lisp_validate(void) +{ + chunk_low = 0; + memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +} + +int dbg_allocs; + +#endif + + void * ao_lisp_alloc(int size) { void *addr; - size = ao_lisp_mem_round(size); -#ifdef MDBG_COLLECT_ALWAYS - ao_lisp_collect(); -#endif + MDBG_DO(++dbg_allocs); + MDBG_DO(if (dbg_validate) ao_lisp_validate()); + size = ao_lisp_size_round(size); if (ao_lisp_top + size > AO_LISP_POOL_CUR) { #ifdef MDBG_POOL if (AO_LISP_POOL_CUR < AO_LISP_POOL) { @@ -573,37 +848,47 @@ ao_lisp_alloc(int size) return addr; } -int -ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons) { - int i; - MDBG("add root type %p addr %p\n", type, addr); - for (i = 0; i < AO_LISP_ROOT; i++) { - if (!ao_lisp_root[i].addr) { - ao_lisp_root[i].addr = addr; - ao_lisp_root[i].type = type; - return 1; - } - } - ao_lisp_abort(); - return 0; + if (save_cons[id] != NULL) + ao_lisp_abort(); + save_cons[id] = cons; } -int -ao_lisp_root_poly_add(ao_poly *p) +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id) { - return ao_lisp_root_add(NULL, p); + struct ao_lisp_cons *cons = save_cons[id]; + save_cons[id] = NULL; + return cons; } void -ao_lisp_root_clear(void *addr) +ao_lisp_string_stash(int id, char *string) { - int i; - for (i = 0; i < AO_LISP_ROOT; i++) { - if (ao_lisp_root[i].addr == addr) { - ao_lisp_root[i].addr = 0; - ao_lisp_root[i].type = 0; - break; - } - } + if (save_cons[id] != NULL) + ao_lisp_abort(); + save_string[id] = string; +} + +char * +ao_lisp_string_fetch(int id) +{ + char *string = save_string[id]; + save_string[id] = NULL; + return string; +} +void +ao_lisp_poly_stash(int id, ao_poly poly) +{ + save_poly[id] = poly; +} + +ao_poly +ao_lisp_poly_fetch(int id) +{ + ao_poly poly = save_poly[id]; + save_poly[id] = AO_LISP_NIL; + return poly; } diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index 7a5751ce..b792c2f1 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -357,25 +357,25 @@ lex(void) } static int parse_token; -static uint8_t been_here; -static struct ao_lisp_cons *read_cons; -static struct ao_lisp_cons *read_cons_tail; -static struct ao_lisp_cons *read_stack; + +struct ao_lisp_cons *ao_lisp_read_cons; +struct ao_lisp_cons *ao_lisp_read_cons_tail; +struct ao_lisp_cons *ao_lisp_read_stack; static int push_read_stack(int cons, int in_quote) { - DBGI("push read stack %p %d\n", read_cons, in_quote); + DBGI("push read stack %p %d\n", ao_lisp_read_cons, in_quote); DBG_IN(); if (cons) { - read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), + ao_lisp_read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_read_cons), ao_lisp_cons_cons(ao_lisp_int_poly(in_quote), - read_stack)); - if (!read_stack) + ao_lisp_read_stack)); + if (!ao_lisp_read_stack) return 0; } - read_cons = NULL; - read_cons_tail = NULL; + ao_lisp_read_cons = NULL; + ao_lisp_read_cons_tail = NULL; return 1; } @@ -384,21 +384,21 @@ pop_read_stack(int cons) { int in_quote = 0; if (cons) { - read_cons = ao_lisp_poly_cons(read_stack->car); - read_stack = ao_lisp_poly_cons(read_stack->cdr); - in_quote = ao_lisp_poly_int(read_stack->car); - read_stack = ao_lisp_poly_cons(read_stack->cdr); - for (read_cons_tail = read_cons; - read_cons_tail && read_cons_tail->cdr; - read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) + ao_lisp_read_cons = ao_lisp_poly_cons(ao_lisp_read_stack->car); + ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); + in_quote = ao_lisp_poly_int(ao_lisp_read_stack->car); + ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); + for (ao_lisp_read_cons_tail = ao_lisp_read_cons; + ao_lisp_read_cons_tail && ao_lisp_read_cons_tail->cdr; + ao_lisp_read_cons_tail = ao_lisp_poly_cons(ao_lisp_read_cons_tail->cdr)) ; } else { - read_cons = 0; - read_cons_tail = 0; - read_stack = 0; + ao_lisp_read_cons = 0; + ao_lisp_read_cons_tail = 0; + ao_lisp_read_stack = 0; } DBG_OUT(); - DBGI("pop read stack %p %d\n", read_cons, in_quote); + DBGI("pop read stack %p %d\n", ao_lisp_read_cons, in_quote); return in_quote; } @@ -411,18 +411,12 @@ ao_lisp_read(void) int in_quote; ao_poly v; - if (!been_here) { - ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); - ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); - ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); - been_here = 1; - } parse_token = lex(); DBGI("token %d (%s)\n", parse_token, token_string); cons = 0; in_quote = 0; - read_cons = read_cons_tail = read_stack = 0; + ao_lisp_read_cons = ao_lisp_read_cons_tail = ao_lisp_read_stack = 0; for (;;) { while (parse_token == OPEN) { if (!push_read_stack(cons, in_quote)) @@ -469,7 +463,7 @@ ao_lisp_read(void) v = AO_LISP_NIL; break; } - v = ao_lisp_cons_poly(read_cons); + v = ao_lisp_cons_poly(ao_lisp_read_cons); --cons; in_quote = pop_read_stack(cons); break; @@ -484,16 +478,16 @@ ao_lisp_read(void) if (!read) return AO_LISP_NIL; - if (read_cons_tail) - read_cons_tail->cdr = ao_lisp_cons_poly(read); + if (ao_lisp_read_cons_tail) + ao_lisp_read_cons_tail->cdr = ao_lisp_cons_poly(read); else - read_cons = read; - read_cons_tail = read; + ao_lisp_read_cons = read; + ao_lisp_read_cons_tail = read; - if (!in_quote || !read_cons->cdr) + if (!in_quote || !ao_lisp_read_cons->cdr) break; - v = ao_lisp_cons_poly(read_cons); + v = ao_lisp_cons_poly(ao_lisp_read_cons); --cons; in_quote = pop_read_stack(cons); } diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 9ee1a7dd..207d4f3b 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -38,23 +38,17 @@ const struct ao_lisp_type ao_lisp_string_type = { .mark = string_mark, .size = string_size, .move = string_move, + .name = "string", }; -char * -ao_lisp_string_new(int len) { - char *a = ao_lisp_alloc(len + 1); - if (!a) - return NULL; - a[len] = '\0'; - return a; -} - char * ao_lisp_string_copy(char *a) { int alen = strlen(a); + ao_lisp_string_stash(0, a); char *r = ao_lisp_alloc(alen + 1); + a = ao_lisp_string_fetch(0); if (!r) return NULL; strcpy(r, a); @@ -66,7 +60,12 @@ ao_lisp_string_cat(char *a, char *b) { int alen = strlen(a); int blen = strlen(b); + + ao_lisp_string_stash(0, a); + ao_lisp_string_stash(1, b); char *r = ao_lisp_alloc(alen + blen + 1); + a = ao_lisp_string_fetch(0); + b = ao_lisp_string_fetch(1); if (!r) return NULL; strcpy(r, a); @@ -78,7 +77,9 @@ ao_poly ao_lisp_string_pack(struct ao_lisp_cons *cons) { int len = ao_lisp_cons_length(cons); + ao_lisp_cons_stash(0, cons); char *r = ao_lisp_alloc(len + 1); + cons = ao_lisp_cons_fetch(0); char *s = r; while (cons) { @@ -96,11 +97,17 @@ ao_lisp_string_unpack(char *a) { struct ao_lisp_cons *cons = NULL, *tail = NULL; int c; + int i; - ao_lisp_root_add(&ao_lisp_cons_type, &cons); - ao_lisp_root_add(&ao_lisp_cons_type, &tail); - while ((c = *a++)) { + for (i = 0; (c = a[i]); i++) { + ao_lisp_cons_stash(0, cons); + ao_lisp_cons_stash(1, tail); + ao_lisp_string_stash(0, a); struct ao_lisp_cons *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); + cons = ao_lisp_cons_fetch(0); + tail = ao_lisp_cons_fetch(1); + a = ao_lisp_string_fetch(0); + if (!n) { cons = NULL; break; @@ -111,8 +118,6 @@ ao_lisp_string_unpack(char *a) cons = n; tail = n; } - ao_lisp_root_clear(&cons); - ao_lisp_root_clear(&tail); return ao_lisp_cons_poly(cons); } -- cgit v1.2.3 From 5557f6b87a9b8bc9716de8191f2062a772a6ae6c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 21:25:38 -0800 Subject: altos/lisp: Cache freed cons and stack items Track freed cons cells and stack items from the eval process where possible so that they can be re-used without needing to collect. This dramatically reduces the number of collect calls. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 17 ++++++++++++++ src/lisp/ao_lisp_cons.c | 32 +++++++++++++++++++------ src/lisp/ao_lisp_eval.c | 33 +++++++++++++++++++++----- src/lisp/ao_lisp_lambda.c | 1 + src/lisp/ao_lisp_make_const.c | 54 +++++++++++++++++++++---------------------- src/lisp/ao_lisp_mem.c | 41 ++++++++++++++++++++++++-------- src/lisp/ao_lisp_save.c | 2 +- 7 files changed, 130 insertions(+), 50 deletions(-) (limited to 'src/lisp/ao_lisp_cons.c') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index e90d791a..efd13cf5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -206,6 +206,7 @@ ao_lisp_stack_poly(struct ao_lisp_stack *stack) } extern struct ao_lisp_stack *ao_lisp_stack; +extern struct ao_lisp_stack *ao_lisp_stack_free_list; extern ao_poly ao_lisp_v; #define AO_LISP_FUNC_LAMBDA 0 @@ -213,6 +214,14 @@ extern ao_poly ao_lisp_v; #define AO_LISP_FUNC_MACRO 2 #define AO_LISP_FUNC_LEXPR 3 +#define AO_LISP_FUNC_FREE_ARGS 0x80 +#define AO_LISP_FUNC_MASK 0x7f + +#define AO_LISP_FUNC_F_LAMBDA (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LAMBDA) +#define AO_LISP_FUNC_F_NLAMBDA (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_NLAMBDA) +#define AO_LISP_FUNC_F_MACRO (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_MACRO) +#define AO_LISP_FUNC_F_LEXPR (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LEXPR) + struct ao_lisp_builtin { uint8_t type; uint8_t args; @@ -390,6 +399,9 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) } /* memory functions */ + +extern int ao_lisp_collects; + /* returns 1 if the object was already marked */ int ao_lisp_mark(const struct ao_lisp_type *type, void *addr); @@ -439,6 +451,11 @@ extern const struct ao_lisp_type ao_lisp_cons_type; struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); +extern struct ao_lisp_cons *ao_lisp_cons_free_list; + +void +ao_lisp_cons_free(struct ao_lisp_cons *cons); + void ao_lisp_cons_print(ao_poly); diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 311d63ab..d2b60c9a 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -69,23 +69,41 @@ const struct ao_lisp_type ao_lisp_cons_type = { .name = "cons", }; +struct ao_lisp_cons *ao_lisp_cons_free_list; + struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - ao_lisp_poly_stash(0, car); - ao_lisp_cons_stash(0, cdr); - cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); - car = ao_lisp_poly_fetch(0); - cdr = ao_lisp_cons_fetch(0); - if (!cons) - return NULL; + if (ao_lisp_cons_free_list) { + cons = ao_lisp_cons_free_list; + ao_lisp_cons_free_list = ao_lisp_poly_cons(cons->cdr); + } else { + ao_lisp_poly_stash(0, car); + ao_lisp_cons_stash(0, cdr); + cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + car = ao_lisp_poly_fetch(0); + cdr = ao_lisp_cons_fetch(0); + if (!cons) + return NULL; + } cons->car = car; cons->cdr = ao_lisp_cons_poly(cdr); return cons; } +void +ao_lisp_cons_free(struct ao_lisp_cons *cons) +{ + while (cons) { + ao_poly cdr = cons->cdr; + cons->cdr = ao_lisp_cons_poly(ao_lisp_cons_free_list); + ao_lisp_cons_free_list = cons; + cons = ao_lisp_poly_cons(cdr); + } +} + void ao_lisp_cons_print(ao_poly c) { diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 04d0e70a..5cc1b75a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -76,6 +76,8 @@ const struct ao_lisp_type ao_lisp_stack_type = { struct ao_lisp_stack *ao_lisp_stack; ao_poly ao_lisp_v; +struct ao_lisp_stack *ao_lisp_stack_free_list; + ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { @@ -97,9 +99,15 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) static int ao_lisp_stack_push(void) { - struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); - if (!stack) - return 0; + struct ao_lisp_stack *stack; + if (ao_lisp_stack_free_list) { + stack = ao_lisp_stack_free_list; + ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev); + } else { + stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); + if (!stack) + return 0; + } stack->prev = ao_lisp_stack_poly(ao_lisp_stack); stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); stack->list = AO_LISP_NIL; @@ -114,9 +122,15 @@ ao_lisp_stack_push(void) static void ao_lisp_stack_pop(void) { + ao_poly prev; + if (!ao_lisp_stack) return; - ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); + prev = ao_lisp_stack->prev; + ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list); + ao_lisp_stack_free_list = ao_lisp_stack; + + ao_lisp_stack = ao_lisp_poly_stack(prev); if (ao_lisp_stack) ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); else @@ -141,7 +155,7 @@ func_type(ao_poly func) return ao_lisp_error(AO_LISP_INVALID, "func is nil"); switch (ao_lisp_poly_type(func)) { case AO_LISP_BUILTIN: - return ao_lisp_poly_builtin(func)->args; + return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK; case AO_LISP_LAMBDA: return ao_lisp_poly_lambda(func)->args; default: @@ -359,12 +373,15 @@ static int ao_lisp_eval_exec(void) { ao_poly v; + struct ao_lisp_builtin *builtin; + DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n"); ao_lisp_stack->sexprs = AO_LISP_NIL; switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_BUILTIN: ao_lisp_stack->state = eval_val; - v = ao_lisp_func(ao_lisp_poly_builtin(ao_lisp_v)) ( + builtin = ao_lisp_poly_builtin(ao_lisp_v); + v = ao_lisp_func(builtin) ( ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr)); DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) { struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); @@ -372,6 +389,10 @@ ao_lisp_eval_exec(void) ao_poly val = ao_lisp_arg(cons, 2); DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n"); }); + builtin = ao_lisp_poly_builtin(ao_lisp_v); + if (builtin->args & AO_LISP_FUNC_FREE_ARGS) + ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values)); + ao_lisp_v = v; DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 6020a8b8..0dd8c698 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -168,6 +168,7 @@ ao_lisp_lambda_eval(void) args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } + ao_lisp_cons_free(cons); break; } case AO_LISP_FUNC_LEXPR: diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 6a29f402..178b041e 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -33,42 +33,42 @@ struct builtin_func { }; struct builtin_func funcs[] = { - "eval", AO_LISP_FUNC_LAMBDA, builtin_eval, - "read", AO_LISP_FUNC_LAMBDA, builtin_read, + "eval", AO_LISP_FUNC_F_LAMBDA, builtin_eval, + "read", AO_LISP_FUNC_F_LAMBDA, builtin_read, "lambda", AO_LISP_FUNC_NLAMBDA, builtin_lambda, "lexpr", AO_LISP_FUNC_NLAMBDA, builtin_lexpr, "nlambda", AO_LISP_FUNC_NLAMBDA, builtin_nlambda, "macro", AO_LISP_FUNC_NLAMBDA, builtin_macro, - "car", AO_LISP_FUNC_LAMBDA, builtin_car, - "cdr", AO_LISP_FUNC_LAMBDA, builtin_cdr, - "cons", AO_LISP_FUNC_LAMBDA, builtin_cons, - "last", AO_LISP_FUNC_LAMBDA, builtin_last, - "length", AO_LISP_FUNC_LAMBDA, builtin_length, + "car", AO_LISP_FUNC_F_LAMBDA, builtin_car, + "cdr", AO_LISP_FUNC_F_LAMBDA, builtin_cdr, + "cons", AO_LISP_FUNC_F_LAMBDA, builtin_cons, + "last", AO_LISP_FUNC_F_LAMBDA, builtin_last, + "length", AO_LISP_FUNC_F_LAMBDA, builtin_length, "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, - "set", AO_LISP_FUNC_LAMBDA, builtin_set, + "set", AO_LISP_FUNC_F_LAMBDA, builtin_set, "setq", AO_LISP_FUNC_MACRO, builtin_setq, "cond", AO_LISP_FUNC_NLAMBDA, builtin_cond, "progn", AO_LISP_FUNC_NLAMBDA, builtin_progn, "while", AO_LISP_FUNC_NLAMBDA, builtin_while, - "print", AO_LISP_FUNC_LEXPR, builtin_print, - "patom", AO_LISP_FUNC_LEXPR, builtin_patom, - "+", AO_LISP_FUNC_LEXPR, builtin_plus, - "-", AO_LISP_FUNC_LEXPR, builtin_minus, - "*", AO_LISP_FUNC_LEXPR, builtin_times, - "/", AO_LISP_FUNC_LEXPR, builtin_divide, - "%", AO_LISP_FUNC_LEXPR, builtin_mod, - "=", AO_LISP_FUNC_LEXPR, builtin_equal, - "<", AO_LISP_FUNC_LEXPR, builtin_less, - ">", AO_LISP_FUNC_LEXPR, builtin_greater, - "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, - ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, - "pack", AO_LISP_FUNC_LAMBDA, builtin_pack, - "unpack", AO_LISP_FUNC_LAMBDA, builtin_unpack, - "flush", AO_LISP_FUNC_LAMBDA, builtin_flush, - "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, - "led", AO_LISP_FUNC_LEXPR, builtin_led, - "save", AO_LISP_FUNC_LAMBDA, builtin_save, - "restore", AO_LISP_FUNC_LAMBDA, builtin_restore, + "print", AO_LISP_FUNC_F_LEXPR, builtin_print, + "patom", AO_LISP_FUNC_F_LEXPR, builtin_patom, + "+", AO_LISP_FUNC_F_LEXPR, builtin_plus, + "-", AO_LISP_FUNC_F_LEXPR, builtin_minus, + "*", AO_LISP_FUNC_F_LEXPR, builtin_times, + "/", AO_LISP_FUNC_F_LEXPR, builtin_divide, + "%", AO_LISP_FUNC_F_LEXPR, builtin_mod, + "=", AO_LISP_FUNC_F_LEXPR, builtin_equal, + "<", AO_LISP_FUNC_F_LEXPR, builtin_less, + ">", AO_LISP_FUNC_F_LEXPR, builtin_greater, + "<=", AO_LISP_FUNC_F_LEXPR, builtin_less_equal, + ">=", AO_LISP_FUNC_F_LEXPR, builtin_greater_equal, + "pack", AO_LISP_FUNC_F_LAMBDA, builtin_pack, + "unpack", AO_LISP_FUNC_F_LAMBDA, builtin_unpack, + "flush", AO_LISP_FUNC_F_LAMBDA, builtin_flush, + "delay", AO_LISP_FUNC_F_LAMBDA, builtin_delay, + "led", AO_LISP_FUNC_F_LEXPR, builtin_led, + "save", AO_LISP_FUNC_F_LAMBDA, builtin_save, + "restore", AO_LISP_FUNC_F_LAMBDA, builtin_restore, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 08b5bac0..e7ece960 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -43,7 +43,6 @@ uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4 #if DBG_MEM int dbg_move_depth; int dbg_mem = DBG_MEM_START; -int dbg_collects = 0; int dbg_validate = 0; struct ao_lisp_record { @@ -212,6 +211,13 @@ static const struct ao_lisp_root ao_lisp_root[] = { #define AO_LISP_ROOT (sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0])) +static const void ** const ao_lisp_cache[] = { + (const void **) &ao_lisp_cons_free_list, + (const void **) &ao_lisp_stack_free_list, +}; + +#define AO_LISP_CACHE (sizeof (ao_lisp_cache) / sizeof (ao_lisp_cache[0])) + #define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; @@ -229,14 +235,16 @@ struct ao_lisp_chunk { }; }; -#define AO_LISP_NCHUNK 32 +#define AO_LISP_NCHUNK 64 static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK]; /* Offset of an address within the pool. */ static inline uint16_t pool_offset(void *addr) { +#if DBG_MEM if (!AO_LISP_IS_POOL(addr)) ao_lisp_abort(); +#endif return ((uint8_t *) addr) - ao_lisp_pool; } @@ -246,8 +254,10 @@ static inline uint16_t pool_offset(void *addr) { * These are used in the chunk code. */ static inline ao_poly pool_poly(void *addr) { +#if DBG_MEM if (!AO_LISP_IS_POOL(addr)) ao_lisp_abort(); +#endif return ((uint8_t *) addr) - AO_LISP_POOL_BASE; } @@ -306,8 +316,10 @@ note_chunk(uint16_t addr, uint16_t size) for (i = 0; i < AO_LISP_NCHUNK; i++) { if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { +#if DBG_MEM if (ao_lisp_chunk[i].size != size) ao_lisp_abort(); +#endif return; } if (ao_lisp_chunk[i].old_addr > addr) { @@ -339,7 +351,7 @@ walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; - for (i = 0; i < AO_LISP_ROOT; i++) { + for (i = 0; i < (int) AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { @@ -416,6 +428,8 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } +int ao_lisp_collects; + void ao_lisp_collect(void) { @@ -427,10 +441,15 @@ ao_lisp_collect(void) int moved; struct ao_lisp_record *mark_record = NULL, *move_record = NULL; - ++dbg_collects; - MDBG_MOVE("collect %d\n", dbg_collects); + MDBG_MOVE("collect %d\n", ao_lisp_collects); marked = moved = 0; #endif + + ++ao_lisp_collects; + + /* Clear references to all caches */ + for (i = 0; i < (int) AO_LISP_CACHE; i++) + *ao_lisp_cache[i] = NULL; chunk_low = 0; top = 0; for (;;) { @@ -462,8 +481,10 @@ ao_lisp_collect(void) if (ao_lisp_chunk[i].old_addr > top) break; +#if DBG_MEM if (ao_lisp_chunk[i].old_addr != top) ao_lisp_abort(); +#endif top += size; MDBG_MOVE("chunk %d %d not moving\n", @@ -585,8 +606,10 @@ ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) if (type == AO_LISP_OTHER) { type = ao_lisp_other_type(ao_lisp_poly_other(p)); +#if DBG_MEM if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) ao_lisp_abort(); +#endif } lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; @@ -622,6 +645,8 @@ ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) if (!AO_LISP_IS_POOL(addr)) return 1; + (void) type; + MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); addr = move_map(addr); if (addr != *ref) { @@ -682,8 +707,10 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (type == AO_LISP_OTHER) { type = ao_lisp_other_type(move_map(ao_lisp_poly_other(p))); +#if DBG_MEM if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) ao_lisp_abort(); +#endif } lisp_type = ao_lisp_types[type]; @@ -795,8 +822,6 @@ ao_lisp_alloc(int size) void ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons) { - if (save_cons[id] != NULL) - ao_lisp_abort(); save_cons[id] = cons; } @@ -811,8 +836,6 @@ ao_lisp_cons_fetch(int id) void ao_lisp_string_stash(int id, char *string) { - if (save_cons[id] != NULL) - ao_lisp_abort(); save_string[id] = string; } diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c index 030846b7..d5f28e7d 100644 --- a/src/lisp/ao_lisp_save.c +++ b/src/lisp/ao_lisp_save.c @@ -27,7 +27,7 @@ ao_lisp_save(struct ao_lisp_cons *cons) os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); os->globals = ao_lisp_frame_poly(ao_lisp_frame_global); os->const_checksum = ao_lisp_const_checksum; - os->const_checksum_inv = ~ao_lisp_const_checksum; + os->const_checksum_inv = (uint16_t) ~ao_lisp_const_checksum; if (ao_lisp_os_save()) return _ao_lisp_atom_t; -- cgit v1.2.3