diff --git a/femtolisp/Makefile b/femtolisp/Makefile index 86be36b..08c0468 100644 --- a/femtolisp/Makefile +++ b/femtolisp/Makefile @@ -24,8 +24,8 @@ test: %.do: %.c $(CC) $(DEBUGFLAGS) -c $< -o $@ -flisp.o: flisp.c cvalues.c flisp.h print.c read.c -flisp.do: flisp.c cvalues.c flisp.h print.c read.c +flisp.o: flisp.c cvalues.c types.c flisp.h print.c read.c +flisp.do: flisp.c cvalues.c types.c flisp.h print.c read.c $(LLT): cd $(LLTDIR) && make diff --git a/femtolisp/builtins.c b/femtolisp/builtins.c index 9078272..56bf98f 100644 --- a/femtolisp/builtins.c +++ b/femtolisp/builtins.c @@ -171,7 +171,7 @@ value_t fl_fixnum(value_t *args, u_int32_t nargs) if (iscvalue(args[0])) { cvalue_t *cv = (cvalue_t*)ptr(args[0]); long i; - if (cv->flags.cstring) { + if (cv_isstr(cv)) { char *pend; errno = 0; i = strtol(cv_data(cv), &pend, 0); diff --git a/femtolisp/cvalues.c b/femtolisp/cvalues.c index 6b4ea93..342da95 100644 --- a/femtolisp/cvalues.c +++ b/femtolisp/cvalues.c @@ -5,35 +5,33 @@ #define NWORDS(sz) (((sz)+3)>>2) #endif -static int struct_aligns[8] = { - sizeof(struct { char a; int8_t i; }), - sizeof(struct { char a; int16_t i; }), - sizeof(struct { char a; char i[3]; }), - sizeof(struct { char a; int32_t i; }), - sizeof(struct { char a; char i[5]; }), - sizeof(struct { char a; char i[6]; }), - sizeof(struct { char a; char i[7]; }), - sizeof(struct { char a; int64_t i; }) }; static int ALIGN2, ALIGN4, ALIGN8, ALIGNPTR; -typedef void (*cvinitfunc_t)(value_t, value_t, void*, void*); - value_t int8sym, uint8sym, int16sym, uint16sym, int32sym, uint32sym; value_t int64sym, uint64sym; value_t longsym, ulongsym, charsym, wcharsym; value_t floatsym, doublesym; -value_t gftypesym, lispvaluesym, stringtypesym, wcstringtypesym; +value_t gftypesym, stringtypesym, wcstringtypesym; value_t emptystringsym; value_t structsym, arraysym, enumsym, cfunctionsym, voidsym, pointersym; value_t unionsym; -value_t autoreleasesym, typeofsym, sizeofsym; +static htable_t TypeTable; +static fltype_t *builtintype; +static fltype_t *int8type, *uint8type; +static fltype_t *int16type, *uint16type; +static fltype_t *int32type, *uint32type; +static fltype_t *int64type, *uint64type; +static fltype_t *longtype, *ulongtype; + fltype_t *chartype, *wchartype; + fltype_t *stringtype, *wcstringtype; +static fltype_t *floattype, *doubletype; -static void cvalue_init(value_t type, value_t v, void *dest); +static void cvalue_init(fltype_t *type, value_t v, void *dest); void cvalue_print(ios_t *f, value_t v, int princ); -// exported guest functions +// cvalues-specific builtins value_t cvalue_new(value_t *args, u_int32_t nargs); value_t cvalue_sizeof(value_t *args, u_int32_t nargs); value_t cvalue_typeof(value_t *args, u_int32_t nargs); @@ -41,79 +39,41 @@ value_t cvalue_typeof(value_t *args, u_int32_t nargs); // compute the size of the metadata object for a cvalue static size_t cv_nwords(cvalue_t *cv) { - if (cv->flags.prim) { - if (cv->flags.inlined) - return CPRIM_NWORDS_INL + NWORDS(cv->flags.inllen); - return CPRIM_NWORDS; - } - if (cv->flags.inlined) { - size_t s = CVALUE_NWORDS_INL + - NWORDS(cv->flags.inllen + cv->flags.cstring); - return (s < CVALUE_NWORDS) ? CVALUE_NWORDS : s; + if (isinlined(cv)) { + size_t n = cv_len(cv); + if (n==0 || cv_isstr(cv)) + n++; + return CVALUE_NWORDS - 1 + NWORDS(n); } return CVALUE_NWORDS; } -void *cv_data(cvalue_t *cv) -{ - if (cv->flags.prim) { - if (cv->flags.inlined) { - return &((cprim_t*)cv)->data; - } - return ((cprim_t*)cv)->data; - } - else if (cv->flags.inlined) { - return &cv->data; - } - return cv->data; -} - -void *cvalue_data(value_t v) -{ - return cv_data((cvalue_t*)ptr(v)); -} - static void autorelease(cvalue_t *cv) { - cv->flags.autorelease = 1; + cv->type = (fltype_t*)(((uptrint_t)cv->type) | CV_OWNED_BIT); // TODO: add to finalizer list } -value_t cvalue(value_t type, size_t sz) +value_t cvalue(fltype_t *type, size_t sz) { cvalue_t *pcv; - if (issymbol(type)) { - cprim_t *pcp; - pcp = (cprim_t*)alloc_words(CPRIM_NWORDS_INL + NWORDS(sz)); - pcp->flagbits = INITIAL_FLAGS; - pcp->flags.inllen = sz; - pcp->flags.inlined = 1; - pcp->flags.prim = 1; - pcp->type = type; - return tagptr(pcp, TAG_CVALUE); - } - PUSH(type); if (sz <= MAX_INL_SIZE) { - size_t nw = CVALUE_NWORDS_INL + NWORDS(sz); - pcv = (cvalue_t*)alloc_words((nw < CVALUE_NWORDS) ? CVALUE_NWORDS : nw); - pcv->flagbits = INITIAL_FLAGS; - pcv->flags.inllen = sz; - pcv->flags.inlined = 1; + size_t nw = CVALUE_NWORDS - 1 + NWORDS(sz) + (sz==0 ? 1 : 0); + pcv = (cvalue_t*)alloc_words(nw); + pcv->data = &pcv->_space[0]; } else { pcv = (cvalue_t*)alloc_words(CVALUE_NWORDS); - pcv->flagbits = INITIAL_FLAGS; - pcv->flags.inlined = 0; pcv->data = malloc(sz); - pcv->len = sz; autorelease(pcv); } - pcv->type = POP(); + pcv->len = sz; + pcv->type = type; return tagptr(pcv, TAG_CVALUE); } -value_t cvalue_from_data(value_t type, void *data, size_t sz) +value_t cvalue_from_data(fltype_t *type, void *data, size_t sz) { cvalue_t *pcv; value_t cv; @@ -131,22 +91,18 @@ value_t cvalue_from_data(value_t type, void *data, size_t sz) // user explicitly calls (autorelease ) on the result of this function. // 'parent' is an optional cvalue that this pointer is known to point // into; NIL if none. -value_t cvalue_from_ref(value_t type, void *ptr, size_t sz, value_t parent) +value_t cvalue_from_ref(fltype_t *type, void *ptr, size_t sz, value_t parent) { cvalue_t *pcv; value_t cv; - PUSH(parent); - PUSH(type); pcv = (cvalue_t*)alloc_words(CVALUE_NWORDS); - pcv->flagbits = INITIAL_FLAGS; - pcv->flags.inlined = 0; pcv->data = ptr; pcv->len = sz; - pcv->type = POP(); - parent = POP(); + pcv->type = type; if (parent != NIL) { - // TODO: add dependency + pcv->type = (fltype_t*)(((uptrint_t)pcv->type) | CV_PARENT_BIT); + pcv->parent = parent; } cv = tagptr(pcv, TAG_CVALUE); return cv; @@ -162,24 +118,17 @@ value_t cvalue_string(size_t sz) return symbol_value(emptystringsym); // secretly allocate space for 1 more byte, hide a NUL there so // any string will always be NUL terminated. - cv = cvalue(symbol_value(stringtypesym), sz+1); + cv = cvalue(stringtype, sz+1); pcv = (cvalue_t*)ptr(cv); data = cv_data(pcv); data[sz] = '\0'; - if (pcv->flags.inlined) - pcv->flags.inllen = sz; - else - pcv->len = sz; - pcv->flags.cstring = 1; + pcv->len = sz; return cv; } value_t cvalue_static_cstring(char *str) { - value_t v = cvalue_from_ref(symbol_value(stringtypesym), str, strlen(str), - NIL); - ((cvalue_t*)ptr(v))->flags.cstring = 1; - return v; + return cvalue_from_ref(stringtype, str, strlen(str), NIL); } value_t string_from_cstr(char *str) @@ -192,7 +141,7 @@ value_t string_from_cstr(char *str) int isstring(value_t v) { - return (iscvalue(v) && ((cvalue_t*)ptr(v))->flags.cstring); + return (iscvalue(v) && cv_isstr((cvalue_t*)ptr(v))); } // convert to malloc representation (fixed address) @@ -217,12 +166,12 @@ static void cv_pin(cvalue_t *cv) } */ -#define num_ctor(typenam, cnvt, tag, fromstr) \ -static void cvalue_##typenam##_init(value_t type, value_t arg, \ - void *dest, void *data) \ +#define num_ctor(typenam, cnvt, tag) \ +static void cvalue_##typenam##_init(fltype_t *type, value_t arg, \ + void *dest) \ { \ typenam##_t n=0; \ - (void)data; (void)type; \ + (void)type; \ if (isfixnum(arg)) { \ n = numval(arg); \ } \ @@ -245,39 +194,37 @@ static void cvalue_##typenam##_init(value_t type, value_t arg, \ value_t cvalue_##typenam(value_t *args, u_int32_t nargs) \ { \ if (nargs==0) { PUSH(fixnum(0)); args = &Stack[SP-1]; } \ - value_t cv = cvalue(typenam##sym, sizeof(typenam##_t)); \ - ((cprim_t*)ptr(cv))->flags.numtype = tag; \ - cvalue_##typenam##_init(typenam##sym, \ - args[0], &((cprim_t*)ptr(cv))->data, 0); \ + value_t cv = cvalue(typenam##type, sizeof(typenam##_t)); \ + cvalue_##typenam##_init(typenam##type, \ + args[0], &((cvalue_t*)ptr(cv))->_space[0]); \ return cv; \ } \ value_t mk_##typenam(typenam##_t n) \ { \ - value_t cv = cvalue(typenam##sym, sizeof(typenam##_t)); \ - ((cprim_t*)ptr(cv))->flags.numtype = tag; \ - *(typenam##_t*)&((cprim_t*)ptr(cv))->data = n; \ + value_t cv = cvalue(typenam##type, sizeof(typenam##_t)); \ + *(typenam##_t*)&((cvalue_t*)ptr(cv))->_space[0] = n; \ return cv; \ } -num_ctor(int8, int32, T_INT8, strtoi64) -num_ctor(uint8, uint32, T_UINT8, strtoui64) -num_ctor(int16, int32, T_INT16, strtoi64) -num_ctor(uint16, uint32, T_UINT16, strtoui64) -num_ctor(int32, int32, T_INT32, strtoi64) -num_ctor(uint32, uint32, T_UINT32, strtoui64) -num_ctor(int64, int64, T_INT64, strtoi64) -num_ctor(uint64, uint64, T_UINT64, strtoui64) -num_ctor(char, uint32, T_UINT8, strtoui64) -num_ctor(wchar, int32, T_INT32, strtoi64) +num_ctor(int8, int32, T_INT8) +num_ctor(uint8, uint32, T_UINT8) +num_ctor(int16, int32, T_INT16) +num_ctor(uint16, uint32, T_UINT16) +num_ctor(int32, int32, T_INT32) +num_ctor(uint32, uint32, T_UINT32) +num_ctor(int64, int64, T_INT64) +num_ctor(uint64, uint64, T_UINT64) +num_ctor(char, uint32, T_UINT8) +num_ctor(wchar, int32, T_INT32) #ifdef BITS64 -num_ctor(long, int64, T_INT64, strtoi64) -num_ctor(ulong, uint64, T_UINT64, strtoui64) +num_ctor(long, int64, T_INT64) +num_ctor(ulong, uint64, T_UINT64) #else -num_ctor(long, int32, T_INT32, strtoi64) -num_ctor(ulong, uint32, T_UINT32, strtoui64) +num_ctor(long, int32, T_INT32) +num_ctor(ulong, uint32, T_UINT32) #endif -num_ctor(float, double, T_FLOAT, strtodouble) -num_ctor(double, double, T_DOUBLE, strtodouble) +num_ctor(float, double, T_FLOAT) +num_ctor(double, double, T_DOUBLE) value_t size_wrap(size_t sz) { @@ -309,12 +256,12 @@ value_t char_from_code(uint32_t code) return cvalue_char(&ccode, 1); } -static void cvalue_enum_init(value_t type, value_t arg, void *dest, void *data) +static void cvalue_enum_init(fltype_t *ft, value_t arg, void *dest) { int n=0; value_t syms; + value_t type = ft->type; - (void)data; syms = car(cdr(type)); if (!iscons(syms)) type_error("enum", "cons", syms); @@ -346,15 +293,15 @@ static void cvalue_enum_init(value_t type, value_t arg, void *dest, void *data) value_t cvalue_enum(value_t *args, u_int32_t nargs) { argcount("enum", nargs, 2); - value_t cv = cvalue(list2(enumsym, args[0]), 4); - ((cvalue_t*)ptr(cv))->flags.numtype = T_INT32; - cvalue_enum_init(cv_type((cvalue_t*)ptr(cv)), - args[1], cv_data((cvalue_t*)ptr(cv)), NULL); + value_t type = list2(enumsym, args[0]); + fltype_t *ft = get_type(type); + value_t cv = cvalue(ft, 4); + cvalue_enum_init(ft, args[1], cv_data((cvalue_t*)ptr(cv))); return cv; } static void array_init_fromargs(char *dest, value_t *vals, size_t cnt, - value_t eltype, size_t elsize) + fltype_t *eltype, size_t elsize) { size_t i; for(i=0; i < cnt; i++) { @@ -366,8 +313,7 @@ static void array_init_fromargs(char *dest, value_t *vals, size_t cnt, static int isarray(value_t v) { if (!iscvalue(v)) return 0; - value_t type = cv_type((cvalue_t*)ptr(v)); - return (iscons(type) && car_(type)==arraysym); + return cv_class((cvalue_t*)ptr(v))->eltype != NULL; } static size_t predict_arraylen(value_t arg) @@ -383,17 +329,13 @@ static size_t predict_arraylen(value_t arg) return 1; } -static void cvalue_array_init(value_t type, value_t arg, void *dest, void *data) +static void cvalue_array_init(fltype_t *ft, value_t arg, void *dest) { + value_t type = ft->type; size_t elsize, i, cnt, sz; - int junk; - value_t eltype = car(cdr(type)); - - if (data != 0) - elsize = (size_t)data; // already computed by constructor - else - elsize = ctype_sizeof(eltype, &junk); + fltype_t *eltype = ft->eltype; + elsize = ft->elsz; cnt = predict_arraylen(arg); if (iscons(cdr_(cdr_(type)))) { @@ -427,7 +369,7 @@ static void cvalue_array_init(value_t type, value_t arg, void *dest, void *data) else if (iscvalue(arg)) { cvalue_t *cv = (cvalue_t*)ptr(arg); if (isarray(arg)) { - value_t aet = car(cdr(cv_type(cv))); + fltype_t *aet = cv_class(cv)->eltype; if (aet == eltype) { if (cv_len(cv) == sz) memcpy(dest, cv_data(cv), sz); @@ -447,13 +389,11 @@ static void cvalue_array_init(value_t type, value_t arg, void *dest, void *data) type_error("array", "sequence", arg); } -static value_t alloc_array(value_t type, size_t sz) +static value_t alloc_array(fltype_t *type, size_t sz) { value_t cv; - if (car_(cdr_(type)) == charsym) { - PUSH(type); + if (type->eltype == chartype) { cv = cvalue_string(sz); - ((cvalue_t*)ptr(cv))->type = POP(); } else { cv = cvalue(type, sz); @@ -464,18 +404,18 @@ static value_t alloc_array(value_t type, size_t sz) value_t cvalue_array(value_t *args, u_int32_t nargs) { size_t elsize, cnt, sz; - int junk; if (nargs < 1) argcount("array", nargs, 1); cnt = nargs - 1; - elsize = ctype_sizeof(args[0], &junk); + fltype_t *type = get_array_type(args[0]); + elsize = type->elsz; sz = elsize * cnt; - value_t cv = alloc_array(listn(3, arraysym, args[0], size_wrap(cnt)), sz); + value_t cv = alloc_array(type, sz); array_init_fromargs(cv_data((cvalue_t*)ptr(cv)), &args[1], cnt, - args[0], elsize); + type->eltype, elsize); return cv; } @@ -483,16 +423,7 @@ value_t cvalue_array(value_t *args, u_int32_t nargs) size_t cvalue_arraylen(value_t v) { cvalue_t *cv = (cvalue_t*)ptr(v); - value_t type = cv_type(cv); - - if (iscons(cdr_(cdr_(type)))) { - return toulong(car_(cdr_(cdr_(type))), "length"); - } - // incomplete array type - int junk; - value_t eltype = car_(cdr_(type)); - size_t elsize = ctype_sizeof(eltype, &junk); - return elsize ? cv_len(cv)/elsize : 0; + return cv_len(cv)/(cv_class(cv)->elsz); } value_t cvalue_relocate(value_t v) @@ -502,19 +433,13 @@ value_t cvalue_relocate(value_t v) cvalue_t *nv; value_t ncv; - if (!cv->flags.islispfunction) { - nw = cv_nwords(cv); - nv = (cvalue_t*)alloc_words(nw); - memcpy(nv, cv, nw*sizeof(value_t)); - ncv = tagptr(nv, TAG_CVALUE); - forward(v, ncv); - } - else { - // guestfunctions are permanent objects, unmanaged - nv = cv; - ncv = v; - } - nv->type = relocate(nv->type); + nw = cv_nwords(cv); + nv = (cvalue_t*)alloc_words(nw); + memcpy(nv, cv, nw*sizeof(value_t)); + if (isinlined(cv)) + nv->data = &nv->_space[0]; + ncv = tagptr(nv, TAG_CVALUE); + forward(v, ncv); return ncv; } @@ -591,7 +516,7 @@ size_t ctype_sizeof(value_t type, int *palign) } if (iscons(type)) { value_t hed = car_(type); - if (hed == pointersym || hed == cfunctionsym || hed == lispvaluesym) { + if (hed == pointersym || hed == cfunctionsym) { *palign = ALIGNPTR; return sizeof(void*); } @@ -653,36 +578,26 @@ value_t cvalue_copy(value_t v) value_t *pnv = alloc_words(nw); v = POP(); cv = (cvalue_t*)ptr(v); memcpy(pnv, cv, nw * sizeof(value_t)); - if (!cv->flags.inlined) { + if (!isinlined(cv)) { size_t len = cv_len(cv); - if (cv->flags.cstring) len++; + if (cv_isstr(cv)) len++; void *data = malloc(len); memcpy(data, cv_data(cv), len); - if (cv->flags.prim) - ((cprim_t*)pnv)->data = data; - else - ((cvalue_t*)pnv)->data = data; + ((cvalue_t*)pnv)->data = data; autorelease((cvalue_t*)pnv); } return tagptr(pnv, TAG_CVALUE); } -static void cvalue_init(value_t type, value_t v, void *dest) +static void cvalue_init(fltype_t *type, value_t v, void *dest) { - cvinitfunc_t f=NULL; + cvinitfunc_t f=type->init; - if (issymbol(type)) { - f = ((symbol_t*)ptr(type))->dlcache; - } - else if (iscons(type)) { - value_t head = car_(type); - f = ((symbol_t*)ptr(head))->dlcache; - } if (f == NULL) lerror(ArgError, "c-value: invalid c type"); - f(type, v, dest, NULL); + f(type, v, dest); } static numerictype_t sym_to_numtype(value_t type) @@ -719,6 +634,10 @@ static numerictype_t sym_to_numtype(value_t type) else if (type == uint64sym) #endif return T_UINT64; + else if (type == floatsym) + return T_FLOAT; + else if (type == doublesym) + return T_DOUBLE; assert(false); return N_NUMTYPES; } @@ -732,32 +651,27 @@ value_t cvalue_new(value_t *args, u_int32_t nargs) if (nargs < 1 || nargs > 2) argcount("c-value", nargs, 2); value_t type = args[0]; + fltype_t *ft = get_type(type); value_t cv; - if (iscons(type) && car_(type) == arraysym) { + if (ft->eltype != NULL) { // special case to handle incomplete array types bla[] - value_t eltype = car(cdr_(type)); - int junk; - size_t elsz = ctype_sizeof(eltype, &junk); + size_t elsz = ft->elsz; size_t cnt; + if (iscons(cdr_(cdr_(type)))) cnt = toulong(car_(cdr_(cdr_(type))), "array"); else if (nargs == 2) cnt = predict_arraylen(args[1]); else cnt = 0; - cv = alloc_array(type, elsz * cnt); + cv = alloc_array(ft, elsz * cnt); if (nargs == 2) - cvalue_array_init(type, args[1], cv_data((cvalue_t*)ptr(cv)), - (void*)elsz); + cvalue_array_init(ft, args[1], cv_data((cvalue_t*)ptr(cv))); } else { - int junk; - cv = cvalue(type, ctype_sizeof(type, &junk)); - if (issymbol(type)) { - ((cvalue_t*)ptr(cv))->flags.numtype = sym_to_numtype(type); - } + cv = cvalue(ft, ft->size); if (nargs == 2) - cvalue_init(type, args[1], cv_data((cvalue_t*)ptr(cv))); + cvalue_init(ft, args[1], cv_data((cvalue_t*)ptr(cv))); } return cv; } @@ -825,14 +739,13 @@ value_t cvalue_set_int8(value_t *args, u_int32_t nargs) return args[2]; } -value_t guestfunc(guestfunc_t f) +value_t cbuiltin(builtin_t f) { - value_t gf = cvalue(symbol_value(gftypesym), sizeof(void*)); + value_t gf = cvalue(builtintype, sizeof(void*)); ((cvalue_t*)ptr(gf))->data = f; - ((cvalue_t*)ptr(gf))->flags.islispfunction = 1; size_t nw = cv_nwords((cvalue_t*)ptr(gf)); // directly-callable values are assumed not to move for - // evaluator performance, so put guestfunction metadata on the + // evaluator performance, so put builtin func metadata on the // unmanaged heap cvalue_t *buf = malloc_aligned(nw * sizeof(value_t), 8); memcpy(buf, ptr(gf), nw*sizeof(value_t)); @@ -840,36 +753,32 @@ value_t guestfunc(guestfunc_t f) } #define cv_intern(tok) tok##sym = symbol(#tok) -#define ctor_cv_intern(tok) cv_intern(tok); set(tok##sym, guestfunc(cvalue_##tok)) -#define symbol_dlcache(s) (((symbol_t*)ptr(s))->dlcache) -#define cache_initfunc(tok) symbol_dlcache(tok##sym) = &cvalue_##tok##_init +#define ctor_cv_intern(tok) cv_intern(tok);set(tok##sym, cbuiltin(cvalue_##tok)) + +void types_init(); void cvalues_init() { - int i; + htable_new(&TypeTable, 256); - // compute struct field alignment required for primitives of sizes 1-8 - for(i=0; i < 8; i++) - struct_aligns[i] -= (i+1); - ALIGN2 = struct_aligns[1]; - ALIGN4 = struct_aligns[3]; - ALIGN8 = struct_aligns[7]; - ALIGNPTR = struct_aligns[sizeof(void*)-1]; + // compute struct field alignment required for primitives + ALIGN2 = sizeof(struct { char a; int16_t i; }) - 2; + ALIGN4 = sizeof(struct { char a; int32_t i; }) - 4; + ALIGN8 = sizeof(struct { char a; int64_t i; }) - 8; + ALIGNPTR = sizeof(struct { char a; void *i; }) - sizeof(void*); - cv_intern(uint32); cv_intern(pointer); cfunctionsym = symbol("c-function"); - cv_intern(lispvalue); - gftypesym = symbol("*guest-function-type*"); - setc(gftypesym, listn(3, cfunctionsym, lispvaluesym, - list2(list2(pointersym, lispvaluesym), uint32sym))); - set(uint32sym, guestfunc(cvalue_uint32)); + + builtintype = define_opaque_type(builtinsym, sizeof(builtin_t), NULL, + NULL); ctor_cv_intern(int8); ctor_cv_intern(uint8); ctor_cv_intern(int16); ctor_cv_intern(uint16); ctor_cv_intern(int32); + ctor_cv_intern(uint32); ctor_cv_intern(int64); ctor_cv_intern(uint64); ctor_cv_intern(char); @@ -884,34 +793,13 @@ void cvalues_init() cv_intern(struct); cv_intern(union); cv_intern(void); - set(symbol("c-value"), guestfunc(cvalue_new)); - set(symbol("get-int8"), guestfunc(cvalue_get_int8)); - set(symbol("set-int8"), guestfunc(cvalue_set_int8)); - cv_intern(autorelease); - ctor_cv_intern(typeof); - ctor_cv_intern(sizeof); - - // set up references to the init functions for each primitive type. - // this is used for fast access in constructors for compound types - // like arrays that need to initialize (but not allocate) elements. - cache_initfunc(int8); - cache_initfunc(uint8); - cache_initfunc(int16); - cache_initfunc(uint16); - cache_initfunc(int32); - cache_initfunc(uint32); - cache_initfunc(int64); - cache_initfunc(uint64); - cache_initfunc(char); - cache_initfunc(wchar); - cache_initfunc(long); - cache_initfunc(ulong); - cache_initfunc(float); - cache_initfunc(double); - - cache_initfunc(array); - cache_initfunc(enum); + set(symbol("c-value"), cbuiltin(cvalue_new)); + set(symbol("get-int8"), cbuiltin(cvalue_get_int8)); + set(symbol("set-int8"), cbuiltin(cvalue_set_int8)); + set(symbol("typeof"), cbuiltin(cvalue_typeof)); + set(symbol("sizeof"), cbuiltin(cvalue_sizeof)); + // todo: autorelease stringtypesym = symbol("*string-type*"); setc(stringtypesym, list2(arraysym, charsym)); @@ -919,6 +807,8 @@ void cvalues_init() wcstringtypesym = symbol("*wcstring-type*"); setc(wcstringtypesym, list2(arraysym, wcharsym)); + types_init(); + emptystringsym = symbol("*empty-string*"); setc(emptystringsym, cvalue_static_cstring("")); } diff --git a/femtolisp/flisp.c b/femtolisp/flisp.c index d351390..802597b 100644 --- a/femtolisp/flisp.c +++ b/femtolisp/flisp.c @@ -199,6 +199,7 @@ static symbol_t *mk_symbol(char *str) sym->binding = UNBOUND; sym->syntax = 0; } + sym->type = NULL; sym->hash = memhash32(str, len)^0xAAAAAAAA; strcpy(&sym->name[0], str); return sym; @@ -233,7 +234,7 @@ value_t symbol(char *str) typedef struct { value_t syntax; // syntax environment entry value_t binding; // global value binding - void *dlcache; // dlsym address (not used here) + fltype_t *type; uint32_t id; } gensym_t; @@ -250,6 +251,7 @@ value_t gensym(value_t *args, uint32_t nargs) gs->id = _gensym_ctr++; gs->binding = UNBOUND; gs->syntax = 0; + gs->type = NULL; return tagptr(gs, TAG_SYM); } @@ -344,6 +346,7 @@ static int symchar(char c); // cvalues -------------------------------------------------------------------- #include "cvalues.c" +#include "types.c" // collector ------------------------------------------------------------------ @@ -445,6 +448,7 @@ void gc(int mustgrow) for (i=0; i < SP; i++) Stack[i] = relocate(Stack[i]); trace_globals(symtab); + relocate_typetable(); rs = readstate; while (rs) { for(i=0; i < rs->backrefs.size; i++) @@ -645,7 +649,7 @@ static value_t eval_sexpr(value_t e, uint32_t penv, int tail) cons_t *c; symbol_t *sym; uint32_t saveSP, envsz, lenv; - int i, nargs, noeval=0; + int i, nargs=0, noeval=0; fixnum_t s, lo, hi; cvalue_t *cv; int64_t accum; @@ -963,13 +967,11 @@ static value_t eval_sexpr(value_t e, uint32_t penv, int tail) break; case F_FIXNUMP: argcount("fixnump", nargs, 1); - v = ((isfixnum(Stack[SP-1])) ? T : NIL); + v = (isfixnum(Stack[SP-1]) ? T : NIL); break; case F_BUILTINP: argcount("builtinp", nargs, 1); - v = (isbuiltinish(Stack[SP-1]) || - (iscvalue(Stack[SP-1]) && - ((cvalue_t*)ptr(Stack[SP-1]))->flags.islispfunction))? T:NIL; + v = (isbuiltinish(Stack[SP-1]) ? T : NIL); break; case F_VECTORP: argcount("vectorp", nargs, 1); @@ -1190,12 +1192,7 @@ static value_t eval_sexpr(value_t e, uint32_t penv, int tail) default: // a guest function is a cvalue tagged as a builtin cv = (cvalue_t*)ptr(f); - if (cv->flags.islispfunction) { - v = ((guestfunc_t)cv->data)(&Stack[saveSP+1], nargs); - } - else { - goto apply_lambda; // trigger type error - } + v = ((builtin_t)cv->data)(&Stack[saveSP+1], nargs); } SP = saveSP; return v; @@ -1317,7 +1314,7 @@ static char *EXEDIR; void assign_global_builtins(builtinspec_t *b) { while (b->name != NULL) { - set(symbol(b->name), guestfunc(b->fptr)); + set(symbol(b->name), cbuiltin(b->fptr)); b++; } } @@ -1389,8 +1386,8 @@ void lisp_init(void) #endif cvalues_init(); - set(symbol("gensym"), guestfunc(gensym)); - set(symbol("hash"), guestfunc(fl_hash)); + set(symbol("gensym"), cbuiltin(gensym)); + set(symbol("hash"), cbuiltin(fl_hash)); char buf[1024]; char *exename = get_exename(buf, sizeof(buf)); diff --git a/femtolisp/flisp.h b/femtolisp/flisp.h index cdeb449..0241867 100644 --- a/femtolisp/flisp.h +++ b/femtolisp/flisp.h @@ -17,8 +17,9 @@ typedef struct { typedef struct _symbol_t { value_t syntax; // syntax environment entry value_t binding; // global value binding - void *dlcache; // dlsym address + struct _fltype_t *type; uint32_t hash; + void *dlcache; // dlsym address // below fields are private struct _symbol_t *left; struct _symbol_t *right; @@ -157,39 +158,6 @@ static inline void argcount(char *fname, int nargs, int c) lerror(ArgError,"%s: too %s arguments", fname, nargsflags.inlined ? (c)->flags.inllen : (c)->len) -#define cv_type(c) ((c)->type) -#define cv_numtype(c) ((c)->flags.numtype) +#define CV_OWNED_BIT 0x1 +#define CV_PARENT_BIT 0x2 +#define owned(cv) ((cv)->type & CV_OWNED_BIT) +#define hasparent(cv) ((cv)->type & CV_PARENT_BIT) +#define isinlined(cv) ((cv)->data == &(cv)->_space[0]) +#define cv_class(cv) ((fltype_t*)(((uptrint_t)(cv)->type)&~3)) +#define cv_len(cv) ((cv)->len) +#define cv_type(cv) (cv_class(cv)->type) +#define cv_data(cv) ((cv)->data) +#define cv_numtype(cv) (cv_class(cv)->numtype) +#define cv_isstr(cv) (cv_class(cv)->eltype == chartype) + +#define cvalue_data(v) cv_data((cvalue_t*)ptr(v)) #define valid_numtype(v) ((v) < N_NUMTYPES) @@ -240,23 +224,23 @@ typedef unsigned long ulong_t; typedef double double_t; typedef float float_t; -typedef value_t (*guestfunc_t)(value_t*, uint32_t); +typedef value_t (*builtin_t)(value_t*, uint32_t); extern value_t int8sym, uint8sym, int16sym, uint16sym, int32sym, uint32sym; -extern value_t int64sym, uint64sym, shortsym, ushortsym; -extern value_t intsym, uintsym, longsym, ulongsym, charsym, ucharsym, wcharsym; +extern value_t int64sym, uint64sym; +extern value_t longsym, ulongsym, charsym, ucharsym, wcharsym; extern value_t structsym, arraysym, enumsym, cfunctionsym, voidsym, pointersym; extern value_t stringtypesym, wcstringtypesym, emptystringsym; -extern value_t unionsym, floatsym, doublesym, lispvaluesym; +extern value_t unionsym, floatsym, doublesym, builtinsym; +extern fltype_t *chartype, *wchartype; +extern fltype_t *stringtype, *wcstringtype; -value_t cvalue(value_t type, size_t sz); +value_t cvalue(fltype_t *type, size_t sz); size_t ctype_sizeof(value_t type, int *palign); -void *cvalue_data(value_t v); -void *cv_data(cvalue_t *cv); value_t cvalue_copy(value_t v); -value_t cvalue_from_data(value_t type, void *data, size_t sz); -value_t cvalue_from_ref(value_t type, void *ptr, size_t sz, value_t parent); -value_t guestfunc(guestfunc_t f); +value_t cvalue_from_data(fltype_t *type, void *data, size_t sz); +value_t cvalue_from_ref(fltype_t *type, void *ptr, size_t sz, value_t parent); +value_t cbuiltin(builtin_t f); size_t cvalue_arraylen(value_t v); value_t size_wrap(size_t sz); size_t toulong(value_t n, char *fname); @@ -269,6 +253,11 @@ value_t cvalue_compare(value_t a, value_t b); value_t cvalue_char(value_t *args, uint32_t nargs); value_t cvalue_wchar(value_t *args, uint32_t nargs); +fltype_t *get_type(value_t t); +fltype_t *get_array_type(value_t eltype); +fltype_t *define_opaque_type(value_t sym, size_t sz, cvtable_t *vtab, + cvinitfunc_t init); + value_t mk_double(double_t n); value_t mk_float(float_t n); value_t mk_uint32(uint32_t n); @@ -279,7 +268,7 @@ value_t char_from_code(uint32_t code); typedef struct { char *name; - guestfunc_t fptr; + builtin_t fptr; } builtinspec_t; void assign_global_builtins(builtinspec_t *b); diff --git a/femtolisp/print.c b/femtolisp/print.c index a5a84c8..f2fa38b 100644 --- a/femtolisp/print.c +++ b/femtolisp/print.c @@ -62,7 +62,7 @@ void print_traverse(value_t v) assert(iscvalue(v)); cvalue_t *cv = (cvalue_t*)ptr(v); // don't consider shared references to "" - if (!cv->flags.cstring || cv_len(cv)!=0) + if (!cv_isstr(cv) || cv_len(cv)!=0) mark_cons(v); } } @@ -468,9 +468,6 @@ static void cvalue_printdata(ios_t *f, void *data, size_t len, value_t type, (uint32_t)(ui64>>32), (uint32_t)(ui64)); } - else if (type == lispvaluesym) { - // TODO - } else if (type == floatsym || type == doublesym) { char buf[64]; double d; @@ -586,9 +583,9 @@ void cvalue_print(ios_t *f, value_t v, int princ) cvalue_t *cv = (cvalue_t*)ptr(v); void *data = cv_data(cv); - if (cv->flags.islispfunction) { - HPOS+=ios_printf(f, "#", - (unsigned long)*(guestfunc_t*)data); + if (isbuiltinish(v)) { + HPOS+=ios_printf(f, "#", + (unsigned long)(builtin_t)data); return; } diff --git a/femtolisp/read.c b/femtolisp/read.c index 6b3c801..d002490 100644 --- a/femtolisp/read.c +++ b/femtolisp/read.c @@ -368,7 +368,8 @@ static value_t read_string(ios_t *f) if (c!=IOS_EOF) ios_ungetc(c, f); eseq[j] = '\0'; wc = strtol(eseq, NULL, 8); - i += u8_wc_toutf8(&buf[i], wc); + // \DDD and \xXX read bytes, not characters + buf[i++] = ((char)wc); } else if ((c=='x' && (ndig=2)) || (c=='u' && (ndig=4)) || @@ -385,7 +386,10 @@ static value_t read_string(ios_t *f) free(buf); lerror(ParseError, "read: invalid escape sequence"); } - i += u8_wc_toutf8(&buf[i], wc); + if (ndig == 2) + buf[i++] = ((char)wc); + else + i += u8_wc_toutf8(&buf[i], wc); } else { buf[i++] = read_escape_control_char((char)c); diff --git a/femtolisp/string.c b/femtolisp/string.c index d1279bb..8596b26 100644 --- a/femtolisp/string.c +++ b/femtolisp/string.c @@ -84,7 +84,7 @@ value_t fl_string_decode(value_t *args, u_int32_t nargs) size_t nc = u8_charnum(ptr, nb); size_t newsz = nc*sizeof(uint32_t); if (term) newsz += sizeof(uint32_t); - value_t wcstr = cvalue(symbol_value(wcstringtypesym), newsz); + value_t wcstr = cvalue(wcstringtype, newsz); ptr = cv_data((cvalue_t*)ptr(args[0])); // relocatable pointer uint32_t *pwc = cvalue_data(wcstr); u8_toucs(pwc, nc, ptr, nb); @@ -118,7 +118,7 @@ value_t fl_string(value_t *args, u_int32_t nargs) sz += u8_charlen(wc); continue; } - else if (temp->flags.cstring) { + else if (cv_isstr(temp)) { sz += cv_len(temp); continue; } diff --git a/femtolisp/table.c b/femtolisp/table.c index 3996ca3..97ad7a9 100644 --- a/femtolisp/table.c +++ b/femtolisp/table.c @@ -36,7 +36,7 @@ typedef struct { htable_t ht; } fltable_t; -void print_htable(ios_t *f, value_t h, int princ) +void print_htable(value_t h, ios_t *f, int princ) { } diff --git a/femtolisp/todo b/femtolisp/todo index b29fb8d..3674f47 100644 --- a/femtolisp/todo +++ b/femtolisp/todo @@ -920,10 +920,10 @@ switch to miser mode, otherwise default is ok, for example: consolidated todo list as of 8/30: - new cvalues, types representation +- use the unused tag for TAG_PRIM, add smaller prim representation - implement support for defining new opaque values -- hashtable - finalizers in gc -- unify vectors and arrays +- hashtable - expose io stream object - enable print-shared for cvalues' types @@ -931,6 +931,8 @@ consolidated todo list as of 8/30: - remaining cvalues functions - finish ios - special efficient reader for #array +- reimplement vectors as (array lispvalue) +- implement fast subvectors and subarrays ----------------------------------------------------------------------------- diff --git a/femtolisp/types.c b/femtolisp/types.c new file mode 100644 index 0000000..d33b279 --- /dev/null +++ b/femtolisp/types.c @@ -0,0 +1,124 @@ +#include "equalhash.h" + +fltype_t *get_type(value_t t) +{ + fltype_t *ft; + if (issymbol(t)) { + ft = ((symbol_t*)ptr(t))->type; + if (ft != NULL) + return ft; + } + void **bp = equalhash_bp(&TypeTable, (void*)t); + if (*bp != HT_NOTFOUND) + return *bp; + + int align, isarray=(iscons(t) && car_(t) == arraysym && iscons(cdr_(t))); + size_t sz; + if (isarray && !iscons(cdr_(cdr_(t)))) { + // special case: incomplete array type + sz = 0; + } + else { + sz = ctype_sizeof(t, &align); + } + + ft = (fltype_t*)malloc(sizeof(fltype_t)); + ft->type = t; + if (issymbol(t)) { + ft->numtype = sym_to_numtype(t); + ((symbol_t*)ptr(t))->type = ft; + } + else { + ft->numtype = N_NUMTYPES; + } + ft->size = sz; + ft->vtable = NULL; + ft->artype = NULL; + ft->marked = 1; + ft->elsz = 0; + ft->eltype = NULL; + ft->init = NULL; + if (iscons(t)) { + if (isarray) { + fltype_t *eltype = get_type(car_(cdr_(t))); + ft->elsz = eltype->size; + ft->eltype = eltype; + ft->init = &cvalue_array_init; + eltype->artype = ft; + } + else if (car_(t) == enumsym) { + ft->numtype = T_INT32; + ft->init = &cvalue_enum_init; + } + } + *bp = ft; + return ft; +} + +fltype_t *get_array_type(value_t eltype) +{ + fltype_t *et = get_type(eltype); + if (et->artype != NULL) + return et->artype; + return get_type(list2(arraysym, eltype)); +} + +fltype_t *define_opaque_type(value_t sym, size_t sz, cvtable_t *vtab, + cvinitfunc_t init) +{ + void **bp = equalhash_bp(&TypeTable, (void*)sym); + if (*bp != HT_NOTFOUND) + return *bp; + fltype_t *ft = (fltype_t*)malloc(sizeof(fltype_t)); + ft->type = sym; + ((symbol_t*)ptr(sym))->type = ft; + ft->size = sz; + ft->numtype = N_NUMTYPES; + ft->vtable = vtab; + ft->artype = NULL; + ft->eltype = NULL; + ft->elsz = 0; + ft->marked = 1; + ft->init = init; + *bp = ft; + return ft; +} + +void relocate_typetable() +{ + htable_t *h = &TypeTable; + size_t i; + void *nv; + for(i=0; i < h->size; i+=2) { + if (h->table[i] != HT_NOTFOUND) { + nv = (void*)relocate((value_t)h->table[i]); + h->table[i] = nv; + if (h->table[i+1] != HT_NOTFOUND) + ((fltype_t*)h->table[i+1])->type = (value_t)nv; + } + } +} + +#define mk_primtype(name) \ + name##type=get_type(name##sym);name##type->init = &cvalue_##name##_init + +void types_init() +{ + mk_primtype(int8); + mk_primtype(uint8); + mk_primtype(int16); + mk_primtype(uint16); + mk_primtype(int32); + mk_primtype(uint32); + mk_primtype(int64); + mk_primtype(uint64); + mk_primtype(long); + mk_primtype(ulong); + mk_primtype(char); + mk_primtype(wchar); + mk_primtype(float); + mk_primtype(double); + + stringtype = get_type(symbol_value(stringtypesym)); + wcstringtype = get_type(symbol_value(wcstringtypesym)); +} diff --git a/llt/htableh.inc b/llt/htableh.inc index 57ff425..b2d12ba 100644 --- a/llt/htableh.inc +++ b/llt/htableh.inc @@ -10,7 +10,7 @@ int HTNAME##_has(htable_t *h, void *key); \ void HTNAME##_remove(htable_t *h, void *key); \ void **HTNAME##_bp(htable_t *h, void *key); -// return value, or PH_NOTFOUND if key not found +// return value, or HT_NOTFOUND if key not found // add key/value binding diff --git a/llt/operators.c b/llt/operators.c index 73b0c37..0d7440b 100644 --- a/llt/operators.c +++ b/llt/operators.c @@ -133,8 +133,18 @@ uint64_t conv_to_uint64(void *data, numerictype_t tag) case T_UINT32: i = (uint64_t)*(uint32_t*)data; break; case T_INT64: i = (uint64_t)*(int64_t*)data; break; case T_UINT64: i = (uint64_t)*(uint64_t*)data; break; - case T_FLOAT: i = (uint64_t)(int64_t)*(float*)data; break; - case T_DOUBLE: i = (uint64_t)(int64_t)*(double*)data; break; + case T_FLOAT: + if (*(float*)data >= 0) + i = (uint64_t)*(float*)data; + else + i = (uint64_t)(int64_t)*(float*)data; + break; + case T_DOUBLE: + if (*(double*)data >= 0) + i = (uint64_t)*(double*)data; + else + i = (uint64_t)(int64_t)*(double*)data; + break; } return i; } diff --git a/llt/pshash.c b/llt/pshash.c new file mode 100644 index 0000000..2dce927 --- /dev/null +++ b/llt/pshash.c @@ -0,0 +1,58 @@ +// by Paul Hsieh +//#include "pstdint.h" /* Replace with if appropriate */ +#include +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + +uint32_t SuperFastHash (const char * data, int len) { +uint32_t hash = len, tmp; +int rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= data[sizeof (uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +}