diff --git a/src/c/debug.c b/src/c/debug.c index 9145a66..ae57c16 100644 --- a/src/c/debug.c +++ b/src/c/debug.c @@ -1,7 +1,7 @@ /** - * debug.h + * debug.c * - * Post Scarcity Software Environment: entry point. + * Post Scarcity Software Environment: debugging messages. * * Print debugging output. * @@ -10,6 +10,8 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ +#include + #include "debug.h" int verbosity = 0; diff --git a/src/c/debug.h b/src/c/debug.h index c9c2a26..dc833dd 100644 --- a/src/c/debug.h +++ b/src/c/debug.h @@ -14,8 +14,10 @@ #define __psse_debug_h #include #include +#include #include + /** * @brief Print messages debugging memory allocation. * diff --git a/src/c/memory/header.h b/src/c/memory/header.h index 71a449f..429cda1 100644 --- a/src/c/memory/header.h +++ b/src/c/memory/header.h @@ -12,6 +12,8 @@ #include +#include "memory/pointer.h" + #define TAGLENGTH 3 /** @@ -20,7 +22,7 @@ */ struct pso_header { union { - /** the tag (type) of this cell, + /** the tag (type) of this object, * considered as bytes */ struct { /** mnemonic for this type; */ @@ -31,10 +33,10 @@ struct pso_header { /** the tag considered as a number */ uint32_t value; } tag; - /** the count of the number of references to this cell */ + /** the count of the number of references to this object */ uint32_t count; - /** cons pointer to the access control list of this cell */ - struct cons_pointer access; + /** pointer to the access control list of this object */ + struct pso_pointer access; }; #endif diff --git a/src/c/memory/memory.c b/src/c/memory/memory.c index d3dbe24..85754bc 100644 --- a/src/c/memory/memory.c +++ b/src/c/memory/memory.c @@ -19,9 +19,8 @@ struct pso_pointer freelists[MAX_SIZE_CLASS + 1]; int initialise_memory( int node ) { - fprintf( stderr, "TODO: Implement initialise_memory()" ); - for (uint8_t i = 0; i <= MAX_SIZE_CLASS; i++) { - freelists[i] = nil;S + freelists[i] = nil; } + } diff --git a/src/c/memory/memory.h b/src/c/memory/memory.h index 49f45e2..fc242c2 100644 --- a/src/c/memory/memory.h +++ b/src/c/memory/memory.h @@ -10,6 +10,8 @@ #ifndef __psse_memory_memory_h #define __psse_memory_memory_h +#include "memory/pointer.h" + /** * @brief Maximum size class * diff --git a/src/c/memory/node.h b/src/c/memory/node.h index cae61e6..fbc177a 100644 --- a/src/c/memory/node.h +++ b/src/c/memory/node.h @@ -11,12 +11,13 @@ #ifndef __psse_memory_node_h #define __psse_memory_node_h +#include /** * @brief The index of this node in the hypercube. * */ -extern int node_index; +extern uint32_t node_index; /** * @brief The canonical `nil` pointer @@ -30,4 +31,6 @@ extern struct pso_pointer nil; */ extern struct pso_pointer t; +struct pso_pointer initialise_node( uint32_t index ); + #endif diff --git a/src/c/memory/page.c b/src/c/memory/page.c index 3d5643c..1486301 100644 --- a/src/c/memory/page.c +++ b/src/c/memory/page.c @@ -44,15 +44,27 @@ struct page * pages[NPAGES]; */ uint32_t npages_allocated = 0 -struct cons_pointer initialise_page( struct page * result, uint16_t page_index, uint8_t size_class, pso_pointer freelist) { +/** + * @brief private to allocate_page; do not use. + * + * @param page_addr address of the newly allocated page to be initialised; + * @param page_index its location in the pages[] array; + * @param size_class the size class of objects in this page; + * @param freelist the freelist for objects of this size class. + * @return struct cons_pointer the new head for the freelist for this size_class, + */ +struct cons_pointer initialise_page( struct page * page_addr, uint16_t page_index, uint8_t size_class, pso_pointer freelist) { struct cons_pointer result = freelist; int obj_size = pow(2, size_class); int obj_bytes = obj_size * sizeof(uint64_t); int objs_in_page = PAGE_BYTES/obj_bytes; + // we do this backwards (i--) so that object {0, 0, 0} will be first on the + // freelist when the first page is initiated, so we can grab that one for + // `nil` and the next on for `t`. for (int i = objs_in_page - 1; i >= 0; i--) { // it should be safe to cast any pso object to a pso2 - struct pso2* object = (pso2 *)(result + (i * obj_bytes)); + struct pso2* object = (pso2 *)(page_addr + (i * obj_bytes)); object->header.tag.size_class = size_class; strncpy( (char *)(object->header.tag.mnemonic), FREETAG, TAGLENGTH); @@ -75,10 +87,10 @@ struct cons_pointer initialise_page( struct page * result, uint16_t page_index, * cast it back. * * @param size_class an integer in the range 0...MAX_SIZE_CLASS. - * @return a pointer to the page, or NULL if an error occurred. + * @return t on success, an exception if an error occurred. */ -void *allocate_page( uint8_t size_class ) { - void *result = NULL; +struct cons_pointer allocate_page( uint8_t size_class ) { + struct cons_pointer result = t; if ( npages_allocated == 0) { for (int i = 0; i < NPAGES; i++) { @@ -108,22 +120,28 @@ void *allocate_page( uint8_t size_class ) { npages_allocated ++; } else { + // TODO: exception when we have one. + result = nil; fwide( stderr, 1 ); fwprintf( stderr, L"\nCannot allocate page: heap exhausted,\n", size_class, MAX_SIZE_CLASS ); } } else { + // TODO: exception when we have one. + result = nil; fwide( stderr, 1 ); fwprintf( stderr, L"\nCannot allocate page for size class %x, min is 2 max is %x.\n", size_class, MAX_SIZE_CLASS ); } } else { - fwide( stderr, 1 ); - fwprintf( stderr, - L"\nCannot allocate page: page space exhausted.\n", - size_class, MAX_SIZE_CLASS ); + // TODO: exception when we have one. + result = nil; + fwide( stderr, 1 ); + fwprintf( stderr, + L"\nCannot allocate page: page space exhausted.\n", + size_class, MAX_SIZE_CLASS ); } return result; diff --git a/src/c/memory/pointer.h b/src/c/memory/pointer.h index fad04cd..902fce2 100644 --- a/src/c/memory/pointer.h +++ b/src/c/memory/pointer.h @@ -38,6 +38,9 @@ struct pso_pointer { uint16_t offset; }; + struct pso_pointer make_pointer( uint32_t node, uint16_t page, uint16_t offset); +struct pso2* pointer_to_object( struct pso_pointer pointer); + #endif diff --git a/src/c/memory/pso.c b/src/c/memory/pso.c index 2914700..f76890d 100644 --- a/src/c/memory/pso.c +++ b/src/c/memory/pso.c @@ -14,11 +14,26 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ -struct cons_pointer allocate( char* tag, uint8_t size_class) { - struct cons_pointer result = nil; + #include "memory/page.h" + #include "memory/pointer.h" + #include "memory/pso.h" + + /** + * @brief Allocate an object of this size_class with this tag. + * + * @param tag The tag. Only the first three bytes will be used; + * @param size_class The size class for the object to be allocated; + * @return struct pso_pointer a pointer to the newly allocated object + */ +struct pso_pointer allocate( char* tag, uint8_t size_class) { + struct pso_pointer result = nil; if (size_class <= MAX_SIZE_CLASS) { - if ( not( freelists[size_class] ) ) { + if (freelists[size_class] == nil) { + result = allocate_page(size_class) + } + + if ( !exceptionp( result) && not( freelists[size_class] ) ) { result = freelists[size_class]; struct pso2* object = pointer_to_object( result); freelists[size_class] = object->payload.free.next; @@ -32,7 +47,7 @@ struct cons_pointer allocate( char* tag, uint8_t size_class) { } /* the objext ought to have a reference count ot zero, because it's * on the freelist, but again we should sanity check. */ - if ( object->header.count != 0) { + if ( object->header.header.count != 0) { // TODO: return an exception instead? Or warn, set it, and continue? } @@ -42,6 +57,97 @@ struct cons_pointer allocate( char* tag, uint8_t size_class) { return result; } -struct cons_pointer get_tag_value( struct cons_pointer pointer) { - result = +/** + * increment the reference count of the object at this cons pointer. + * + * You can't roll over the reference count. Once it hits the maximum + * value you cannot increment further. + * + * Returns the `pointer`. + */ +struct pso_pointer inc_ref( struct pso_pointer pointer ) { + struct pso2 *object = pointer_to_object( pointer ); + + if ( object->header.count < MAXREFERENCE ) { + object->header.count++; +#ifdef DEBUG + debug_printf( DEBUG_ALLOC, + L"\nIncremented object of type %4.4s at page %u, offset %u to count %u", + ( ( char * ) object->header.tag.bytes ), pointer.page, + pointer.offset, object->header.count ); + if ( strncmp( object->header.tag.bytes, VECTORPOINTTAG, TAGLENGTH ) == 0 ) { + debug_printf( DEBUG_ALLOC, + L"; pointer to vector object of type %4.4s.\n", + ( ( char * ) ( object->header.payload.vectorp.tag.bytes ) ) ); + } else { + debug_println( DEBUG_ALLOC ); + } +#endif + } + + return pointer; +} + +/** + * Decrement the reference count of the object at this cons pointer. + * + * If a count has reached MAXREFERENCE it cannot be decremented. + * If a count is decremented to zero the object should be freed. + * + * Returns the `pointer`, or, if the object has been freed, a pointer to `nil`. + */ +struct pso_pointer dec_ref( struct pso_pointer pointer ) { + struct pso2 *object = pointer_to_object( pointer ); + + if ( object->count > 0 && object->count != MAXREFERENCE ) { + object->count--; +#ifdef DEBUG + debug_printf( DEBUG_ALLOC, + L"\nDecremented object of type %4.4s at page %d, offset %d to count %d", + ( ( char * ) object->tag.bytes ), pointer.page, + pointer.offset, object->count ); + if ( strncmp( ( char * ) object->tag.bytes, VECTORPOINTTAG, TAGLENGTH ) + == 0 ) { + debug_printf( DEBUG_ALLOC, + L"; pointer to vector object of type %4.4s.\n", + ( ( char * ) ( object->payload.vectorp.tag.bytes ) ) ); + } else { + debug_println( DEBUG_ALLOC ); + } +#endif + + if ( object->header.count == 0 ) { + free_cell( pointer ); + pointer = NIL; + } + } + + return pointer; +} + +/** + * @brief Prevent an object ever being dereferenced. + * + * @param pointer pointer to an object to lock. + */ +void lock_object( struct pso_pointer pointer) { + struct pso2* object = pointer_to_object( pointer ); + + object->header.header.count = MAXREFERENCE; +} + + +/** + * @brief Get the numeric value of the tag bytes of the object indicated + * by this pointer + * + * @param pointer a pointer to an object. + * @return the tag value of the object indicated. + */ +uint32_t get_tag_value( struct pso_pointer pointer) { + result = (pointer_to_object( pointer)->tag.value & 0xffffff; + + // TODO: deal with the vector pointer issue + + return result; } \ No newline at end of file diff --git a/src/c/memory/pso.h b/src/c/memory/pso.h index 90b9d57..9fd7cc1 100644 --- a/src/c/memory/pso.h +++ b/src/c/memory/pso.h @@ -13,13 +13,17 @@ #include #include "memory/header.h" +#include "memory/pointer.h" #include "payloads/cons.h" +#include "payloads/exception.h" #include "payloads/free.h" #include "payloads/function.h" +#include "payloads/hashtable.h" #include "payloads/integer.h" -#include "payloads/ketwod.h" +#include "payloads/keyword.h" #include "payloads/lambda.h" #include "payloads/mutex.h" +#include "payloads/namespace.h" #include "payloads/nlambda.h" #include "payloads/read_stream.h" #include "payloads/special.h" @@ -38,8 +42,8 @@ struct pso2 { struct pso_header header; union { - char[16] bytes; - uint64_t[2] words; + char bytes[16]; + uint64_t words[2]; struct cons_payload cons; struct free_payload free; struct function_payload function; @@ -60,8 +64,8 @@ struct pso2 { struct pso3 { struct pso_header header; union { - char[48] bytes; - uint64_t[6] words; + char bytes[48]; + uint64_t words[6]; struct exception_payload exception; struct free_payload free; struct mutex_payload mutex; @@ -76,8 +80,8 @@ struct pso3 { struct pso4 { struct pso_header header; union { - char[112] bytes; - uint64_t[14] words; + char bytes[112]; + uint64_t words[14]; struct free_payload free; struct stack_frame_payload stack_frame; } payload; @@ -91,8 +95,8 @@ struct pso4 { struct pso5 { struct pso_header header; union { - char[240] bytes; - uint64_t[30] words; + char bytes[240]; + uint64_t words[30]; struct free_payload free; } payload; }; @@ -105,8 +109,8 @@ struct pso5 { struct pso6 { struct pso_header header; union { - char[496] bytes; - uint64_t[62] words; + char bytes[496]; + uint64_t words[62]; struct free_payload free; struct hashtable_payload hashtable; struct namespace_payload namespace; @@ -121,8 +125,8 @@ struct pso6 { struct pso7 { struct pso_header header; union { - char[1008] bytes; - uint64_t[126] words; + char bytes[1008]; + uint64_t words[126]; struct free_payload free; } payload; }; @@ -135,8 +139,8 @@ struct pso7 { struct pso8 { struct pso_header header; union { - char[2032] bytes; - uint64_t[254] words; + char bytes[2032]; + uint64_t words[254]; struct free_payload free; } payload; }; @@ -149,8 +153,8 @@ struct pso8 { struct pso9 { struct pso_header header; union { - char[4080] bytes; - uint64_t[510] words; + char bytes[4080]; + uint64_t words[510]; struct free_payload free; } payload; }; @@ -163,8 +167,8 @@ struct pso9 { struct psoa { struct pso_header header; union { - char[8176] bytes; - uint64_t[1022] words; + char bytes[8176]; + uint64_t words[1022]; struct free_payload free; } payload; }; @@ -177,8 +181,8 @@ struct psoa { struct psob { struct pso_header header; union { - char[16368] bytes; - uint64_t[2046] words; + char bytes[16368]; + uint64_t words[2046]; struct free_payload free; } payload; }; @@ -191,8 +195,8 @@ struct psob { struct psoc { struct pso_header header; union { - char[32752] bytes; - uint64_t[4094] words; + char bytes[32752]; + uint64_t words[4094]; struct free_payload free; } payload; }; @@ -205,8 +209,8 @@ struct psoc { struct psod { struct pso_header header; union { - char[65520] bytes; - uint64_t[8190] words; + char bytes[65520]; + uint64_t words[8190]; struct free_payload free; } payload; }; @@ -219,8 +223,8 @@ struct psod { struct psoe { struct pso_header header; union { - char[131056] bytes; - uint64_t[16382] words; + char bytes[131056]; + uint64_t words[16382]; struct free_payload free; } payload; }; @@ -233,8 +237,18 @@ struct psoe { struct psof { struct pso_header header; union { - char[262128] bytes; - uint64_t[32766] words; + char bytes[262128]; + uint64_t words[32766]; struct free_payload free; } payload; }; + +struct pso_pointer allocate( char* tag, uint8_t size_class); + +struct pso_pointer dec_ref( struct pso_pointer pointer ); + +struct pso_pointer inc_ref( struct pso_pointer pointer ); + +void lock_object( struct pso_pointer pointer); + +#endif \ No newline at end of file diff --git a/src/c/payloads/cons.c b/src/c/payloads/cons.c new file mode 100644 index 0000000..5eaf2b6 --- /dev/null +++ b/src/c/payloads/cons.c @@ -0,0 +1,86 @@ +/** + * payloads/cons.h + * + * A cons cell. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include + +#include "memory/node.h" +#include "memory/pointer.h" +#include "memory/pso.h" +#include "payloads/cons.h" + +/** + * @brief allocate a cons cell with this car and this cdr, and return a pointer + * to it. + * + * @param car the pointer which should form the car of this cons cell; + * @param cdr the pointer which should form the cdr of this cons cell. + * @return struct pso_pointer a pointer to the newly allocated cons cell. + */ +struct pso_pointer cons( struct pso_pointer car, struct pso_pointer cdr) { + struct pso_pointer result = allocate( CONSTAG, 2); + + struct pso2 *object = pointer_to_object( result ); + object->payload.cons.car = car; + object->payload.cons.cdr = cdr; + + inc_ref( car); + inc_ref( cdr); + + return result; +} + +/** + * @brief return true if `ptr` indicates a cons cell, else false. + * + * @param ptr a pointer. + * @return true if `ptr` indicates a cons cell. + * @return false otherwise + */ +bool consp( struct pso_pointer ptr) { + // TODO: make it actually work! + return false; +} + +/** + * @brief return the car of this cons cell. + * + * @param cons a pointer to the cell. + * @return the car of the indicated cell. + * @exception if the pointer does not indicate a cons cell. + */ +struct pso_pointer car( struct pso_pointer cons) { + struct pso_pointer result = nil; + struct pso2 *object = pointer_to_object( result ); + + if ( consp( cons)) { + result = object->payload.cons.car; + } + // TODO: else throw an exception + + return result; +} + +/** + * @brief return the cdr of this cons cell. + * + * @param cons a pointer to the cell. + * @return the cdr of the indicated cell. + * @exception if the pointer does not indicate a cons cell. + */ +struct pso_pointer cdr( struct pso_pointer cons) { + struct pso_pointer result = nil; + struct pso2 *object = pointer_to_object( result ); + + if ( consp( cons)) { + result = object->payload.cons.cdr; + } + // TODO: else throw an exception + + return result; +} \ No newline at end of file diff --git a/src/c/payloads/cons.h b/src/c/payloads/cons.h index a1b0d4d..a2e8129 100644 --- a/src/c/payloads/cons.h +++ b/src/c/payloads/cons.h @@ -9,6 +9,7 @@ #ifndef __psse_payloads_cons_h #define __psse_payloads_cons_h +#include #include "memory/pointer.h" @@ -16,6 +17,7 @@ * An ordinary cons cell: */ #define CONSTAG "CNS" +#define CONSTV 5459523 /** * @brief A cons cell. @@ -28,5 +30,12 @@ struct cons_payload { struct pso_pointer cdr; }; +struct pso_pointer car( struct pso_pointer cons); + +struct pso_pointer cdr( struct pso_pointer cons); + +struct pso_pointer cons( struct pso_pointer car, struct pso_pointer cdr); + +bool consp( struct pso_pointer ptr); #endif diff --git a/src/c/payloads/exception.h b/src/c/payloads/exception.h index 0363daa..d6fdc03 100644 --- a/src/c/payloads/exception.h +++ b/src/c/payloads/exception.h @@ -12,6 +12,9 @@ #include "memory/pointer.h" +#define EXCEPTIONTAG "EXP" +#define EXCEPTIONTV 5265477 + /** * @brief An exception; required three pointers, so use object of size class 3. */ @@ -21,7 +24,7 @@ struct exception_payload { /** @brief the stack frame at which the exception was thrown. */ struct pso_pointer stack; /** @brief the cause; expected to be another exception, or (usually) `nil`. */ - struct cons_pointer cause; + struct pso_pointer cause; }; diff --git a/src/c/payloads/free.h b/src/c/payloads/free.h index 3871c36..947a3e4 100644 --- a/src/c/payloads/free.h +++ b/src/c/payloads/free.h @@ -16,6 +16,7 @@ * @brief Tag for an unassigned object; may be of any size class. */ #define FREETAG "FRE" +#define FREETV 4543046 /** * @brief An unassigned object, on a freelist; may be of any size class. diff --git a/src/c/payloads/function.h b/src/c/payloads/function.h index 66ac8bc..2ef45c4 100644 --- a/src/c/payloads/function.h +++ b/src/c/payloads/function.h @@ -11,6 +11,7 @@ #define __psse_payloads_function_h #include "memory/pointer.h" +#include "memory/pso.h" /** * @brief Tag for an ordinary Lisp function - one whose arguments are pre-evaluated. @@ -18,6 +19,7 @@ * \see SPECIALTAG for functions whose arguments are not pre-evaluated. */ #define FUNCTIONTAG "FUN" +#define FUNCTIONTV 5133638 /** * @brief Payload of a function cell. @@ -32,16 +34,16 @@ struct function_payload { /** * pointer to metadata (e.g. the source from which the function was compiled). */ - struct cons_pointer meta; + struct pso_pointer meta; /** pointer to a function which takes a cons pointer (representing * its argument list) and a cons pointer (representing its environment) and a * stack frame (representing the previous stack frame) as arguments and returns * a cons pointer (representing its result). * \todo check this documentation is current! */ - struct cons_pointer ( *executable ) ( struct stack_frame *, - struct cons_pointer, - struct cons_pointer ); + struct pso_pointer ( *executable ) ( struct pso4 *, + struct pso_pointer, + struct pso_pointer ); }; #endif diff --git a/src/c/payloads/hashtable.h b/src/c/payloads/hashtable.h index 5fcced5..86664e5 100644 --- a/src/c/payloads/hashtable.h +++ b/src/c/payloads/hashtable.h @@ -3,7 +3,25 @@ * * an ordinary Lisp hashtable - one whose contents are immutable. * - * Can sensibly sit in any pso from size class 6 upwards. + * Can sensibly sit in any pso from size class 6 upwards. However, it's often + * considered a good thing to have a prime number of buckets in a hash table. + * Our total overhead on the full object size is two words header, and, for + * hashtables, one word for the pointer to the (optional) hash function, and + * one for the number of buckets, total four. + * + * | size class | words | less overhead | nearest prime | wasted | + * | ---------- | ----- | ------------- | ------------- | ------ | + * | 5 | 32 | 28 | 23 | 5 | + * | 6 | 64 | 60 | 59 | 1 | + * | 7 | 128 | 124 | 113 | 11 | + * | 8 | 256 | 252 | 251 | 1 | + * | 9 | 512 | 508 | 503 | 5 | + * | 10 | 1024 | 1020 | 1019 | 1 | + * + * So we can fit 59 buckets into a 64 word class 6 pso, wasting one word; + * 251 buckets in a 256 word class 8 again wasting one word; 1019 in a size + * class 10, also wasting only one word. In a 32 word class 5, the best prime + * we can do is 23 buckets, wasting five words. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. @@ -19,6 +37,8 @@ * \see NAMESPACETAG for mutable hashtables. */ #define HASHTABLETAG "HTB" +#define HASHTABLETV 4346952 + /** * The payload of a hashtable. The number of buckets is assigned at run-time, * and is stored in n_buckets. Each bucket is something ASSOC can consume: @@ -27,12 +47,7 @@ struct hashtable_payload { struct cons_pointer hash_fn; /* function for hashing values in this hashtable, or `NIL` to use the default hashing function */ - struct cons_pointer write_acl; /* it seems to me that it is likely that the - * principal difference between a hashtable and a - * namespace is that a hashtable has a write ACL - * of `NIL`, meaning not writeable by anyone */ uint32_t n_buckets; /* number of hash buckets */ - uint32_t unused; /* for word alignment and possible later expansion */ struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL` * or assoc lists or (possibly) further hashtables. */ }; diff --git a/src/c/payloads/integer.h b/src/c/payloads/integer.h index 69d0617..00ee92d 100644 --- a/src/c/payloads/integer.h +++ b/src/c/payloads/integer.h @@ -12,6 +12,9 @@ #include +#define INTEGERTAG "INT" +#define INTEGERTV 5525065 + /** * @brief An integer . * @@ -20,7 +23,7 @@ * in the Lisp layer, not the substrate. */ struct integer_payload { - int128_t value; + __int128_t value; }; diff --git a/src/c/payloads/keyword.h b/src/c/payloads/keyword.h index 164d31c..de89749 100644 --- a/src/c/payloads/keyword.h +++ b/src/c/payloads/keyword.h @@ -16,6 +16,7 @@ * Tag for a keyword - an interned, self-evaluating string. */ #define KEYTAG "KEY" +#define KEYTV 5850443 /* TODO: for now, Keyword shares a payload with String, but this may change. * Strings are of indefinite length, but keywords are really not, and might diff --git a/src/c/payloads/lambda.h b/src/c/payloads/lambda.h index f457339..cfa9bde 100644 --- a/src/c/payloads/lambda.h +++ b/src/c/payloads/lambda.h @@ -17,6 +17,7 @@ * \see FUNCTIONTAG. */ #define LAMBDATAG "LMD" +#define LAMBDATV 4345164 /** * @brief payload for lambda and nlambda cells. diff --git a/src/c/payloads/mutex.h b/src/c/payloads/mutex.h index 11a81df..ca5704b 100644 --- a/src/c/payloads/mutex.h +++ b/src/c/payloads/mutex.h @@ -20,6 +20,7 @@ * \see FUNCTIONTAG. */ #define MUTEXTAG "MTX" +#define MUTEXTV 5788749 /** * @brief payload for mutex objects. @@ -29,7 +30,7 @@ */ struct mutex_payload { pthread_mutex_t mutex; -} +}; struct pso_pointer make_mutex(); @@ -63,4 +64,6 @@ struct pso_pointer with_lock( struct pso_pointer lock, struct pso_pointer forms) * @param forms a list of arbitrary Lisp forms. * @return struct pso_pointer the result. */ -struct pso_pointer attempt_with_lock( struct pso_pointer lock, struct pso_pointer forms); \ No newline at end of file +struct pso_pointer attempt_with_lock( struct pso_pointer lock, struct pso_pointer forms); + +#endif diff --git a/src/c/payloads/namespace.h b/src/c/payloads/namespace.h index 4bb5ae0..b494e93 100644 --- a/src/c/payloads/namespace.h +++ b/src/c/payloads/namespace.h @@ -3,7 +3,28 @@ * * a Lisp namespace - a hashtable whose contents are mutable. * - * Can sensibly sit in any pso from size class 6 upwards. + * Can sensibly sit in any pso from size class 6 upwards. However, it's often + * considered a good thing to have a prime number of buckets in a hash table. + * Our total overhead on the full object size is two words header, and, for + * namespaces, one word for the pointer to the (optional) hash function, + * one for the number of buckets, one for the pointer to the write ACL, one + * for the pointer to the mutex, total six. + * + * There are no really good fits until you get up to class 9, which might + * make sense for some namespaces, but it's quite large! + * + * | size class | words | less overhead | nearest prime | wasted | + * | ---------- | ----- | ------------- | ------------- | ------ | + * | 5 | 32 | 26 | 23 | 3 | + * | 6 | 64 | 58 | 53 | 5 | + * | 7 | 128 | 122 | 113 | 9 | + * | 8 | 256 | 250 | 241 | 9 | + * | 9 | 512 | 506 | 503 | 3 | + * | 10 | 1024 | 1018 | 1013 | 5 | + * + * Although it may be *better* to have prime numbers of buckets, how much + * better is it? Is a bucket with 23 slots sufficiently better than one + * with 26 slots to make up for its inevitably-longer hash buckets? * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. @@ -19,6 +40,7 @@ * \see HASHTABLETAG for mutable hashtables. */ #define NAMESPACETAG "NSP" +#define NAMESPACETV 5264206 /** * The payload of a namespace. The number of buckets is assigned at run-time, @@ -28,13 +50,13 @@ struct namespace_payload { struct cons_pointer hash_fn; /* function for hashing values in this namespace, or * `NIL` to use the default hashing function */ + uint32_t n_buckets; /* number of hash buckets */ + uint32_t unused; /* for word alignment and possible later expansion */ struct cons_pointer write_acl; /* it seems to me that it is likely that the * principal difference between a hashtable and a * namespace is that a hashtable has a write ACL * of `NIL`, meaning not writeable by anyone */ struct cons_pointer mutex; /* the mutex to lock when modifying this namespace.*/ - uint32_t n_buckets; /* number of hash buckets */ - uint32_t unused; /* for word alignment and possible later expansion */ struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL` * or assoc lists or (possibly) further hashtables. */ }; diff --git a/src/c/payloads/nlambda.h b/src/c/payloads/nlambda.h index bf96361..1f0771f 100644 --- a/src/c/payloads/nlambda.h +++ b/src/c/payloads/nlambda.h @@ -15,7 +15,8 @@ /** * An ordinary nlambda cell: */ -#define CONSTAG "CNS" +#define NLAMBDATAG "NLM" +#define NLAMBDATV 5065806 /* nlambda shares a payload with lambda */ diff --git a/src/c/payloads/read_stream.h b/src/c/payloads/read_stream.h index 5489308..e271489 100644 --- a/src/c/payloads/read_stream.h +++ b/src/c/payloads/read_stream.h @@ -12,12 +12,15 @@ #include +#include + #include "memory/pointer.h" /** * An open read stream. */ #define READTAG "REA" +#define READTV 4277586 /** * payload of a read or write stream cell. diff --git a/src/c/payloads/special.h b/src/c/payloads/special.h index 96f616d..4c64545 100644 --- a/src/c/payloads/special.h +++ b/src/c/payloads/special.h @@ -18,6 +18,7 @@ * \see NLAMBDATAG. */ #define SPECIALTAG "SFM" +#define SPECIALTV 5064275 /** * @brief Payload of a special form cell. @@ -30,14 +31,14 @@ struct special_payload { * pointer to the source from which the special form was compiled, or NIL * if it is a primitive. */ - struct cons_pointer meta; + struct pso_pointer meta; /** pointer to a function which takes a cons pointer (representing * its argument list) and a cons pointer (representing its environment) and a * stack frame (representing the previous stack frame) as arguments and returns * a cons pointer (representing its result). */ - struct cons_pointer ( *executable ) ( struct stack_frame *, - struct cons_pointer, - struct cons_pointer ); + struct pso_pointer ( *executable ) ( struct pso4 *, + struct pso_pointer, + struct pso_pointer ); }; #endif diff --git a/src/c/memory/stack.c b/src/c/payloads/stack.c similarity index 51% rename from src/c/memory/stack.c rename to src/c/payloads/stack.c index ab98c93..a814699 100644 --- a/src/c/memory/stack.c +++ b/src/c/payloads/stack.c @@ -1,5 +1,5 @@ /** - * memory/stack.c + * payloads/stack.c * * The execution stack. * @@ -7,7 +7,9 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ -#include "memory/stack.h" +#include "memory/node.h" +#include "memory/pso.h" +#include "payloads/stack.h" /** * @brief The maximum depth of stack before we throw an exception. @@ -19,19 +21,20 @@ uint32_t stack_limit = 0; /** * Fetch a pointer to the value of the local variable at this index. */ -struct cons_pointer fetch_arg( struct stack_frame *frame, unsigned int index ) { - struct cons_pointer result = NIL; +struct pso_pointer fetch_arg( struct pso4 *frame, unsigned int index ) { + struct pso_pointer result = nil; + // TODO check that the frame is indeed a frame! if ( index < args_in_frame ) { - result = frame->arg[index]; + result = frame->payload.stack_frame.arg[index]; } else { - struct cons_pointer p = frame->more; + struct pso_pointer p = frame->payload.stack_frame.more; for ( int i = args_in_frame; i < index; i++ ) { - p = pointer2cell( p ).payload.cons.cdr; + p = pointer_to_object( p)->payload.cons.cdr; } - result = pointer2cell( p ).payload.cons.car; + result = pointer_to_object( p)->payload.cons.car; } return result; diff --git a/src/c/memory/stack.h b/src/c/payloads/stack.h similarity index 81% rename from src/c/memory/stack.h rename to src/c/payloads/stack.h index 7e0b2b0..ba0abd8 100644 --- a/src/c/memory/stack.h +++ b/src/c/payloads/stack.h @@ -1,17 +1,19 @@ /** - * memory/stack.h + * payloads/stack.h * - * The execution stack. + * a Lisp stack frame. + * + * Sits in a pso4. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ -#ifndef __psse_payloads_stack_frame_h -#define __psse_payloads_stack_frame_h -#include +#ifndef __psse_payloads_stack_h +#define __psse_payloads_stack_h #include "memory/pointer.h" + /* * number of arguments stored in a stack frame */ @@ -25,7 +27,7 @@ extern uint32_t stack_limit; /** - * A stack frame. + * A stack frame. */ struct stack_frame_payload { /** the previous frame. */ @@ -37,9 +39,9 @@ struct stack_frame_payload { /** the function to be called. */ struct pso_pointer function; /** the number of arguments provided. */ - int args; + uint32_t args; /** the depth of the stack below this frame */ - int depth; + uint32_t depth; }; #endif diff --git a/src/c/payloads/string.h b/src/c/payloads/string.h index dbc45ca..c08690d 100644 --- a/src/c/payloads/string.h +++ b/src/c/payloads/string.h @@ -22,6 +22,7 @@ * @brief Tag for string of characters, organised as a linked list. */ #define STRINGTAG "STR" +#define STRINGTV 5395539 /** * @brief payload of a string cell. @@ -36,7 +37,7 @@ struct string_payload { /** a hash of the string value, computed at store time. */ uint32_t hash; /** the remainder of the string following this character. */ - struct cons_pointer cdr; + struct pso_pointer cdr; }; #endif diff --git a/src/c/payloads/symbol.h b/src/c/payloads/symbol.h index 9e7afd5..fdc01c1 100644 --- a/src/c/payloads/symbol.h +++ b/src/c/payloads/symbol.h @@ -17,6 +17,7 @@ * Tag for a symbol: just like a keyword except not self-evaluating. */ #define SYMBOLTAG "SYM" +#define SYMBOLTV 5069139 /* TODO: for now, Symbol shares a payload with String, but this may change. * Strings are of indefinite length, but symbols are really not, and might diff --git a/src/c/payloads/time.h b/src/c/payloads/time.h index e304e67..d9870b4 100644 --- a/src/c/payloads/time.h +++ b/src/c/payloads/time.h @@ -15,7 +15,8 @@ /** * @brief Tag for a time stamp. */ -#define TIMETAG "TIME" +#define TIMETAG "TIM" +#define TIMETV 5065044 /** * The payload of a time cell: an unsigned 128 bit value representing micro- diff --git a/src/c/payloads/write_stream.h b/src/c/payloads/write_stream.h index 757f7d0..deda598 100644 --- a/src/c/payloads/write_stream.h +++ b/src/c/payloads/write_stream.h @@ -16,6 +16,7 @@ * @brief Tag for an open write stream. */ #define WRITETAG "WRT" +#define WRITETV 5264214 /* write stream shares a payload with /see read_streem.h */ #endif diff --git a/utils_src/tagvalcalc/tagvalcalc.c b/utils_src/tagvalcalc/tagvalcalc.c index 67828bd..ad2e1a9 100644 --- a/utils_src/tagvalcalc/tagvalcalc.c +++ b/utils_src/tagvalcalc/tagvalcalc.c @@ -3,7 +3,7 @@ #include #include -#define TAGLENGTH 4 +#define TAGLENGTH 3 struct dummy { union { @@ -21,6 +21,6 @@ int main( int argc, char *argv[] ) { strncpy( &buffer.tag.bytes[0], argv[i], TAGLENGTH ); - printf( "%4.4s:\t%d\n", argv[i], buffer.tag.value); + printf( "%4.4s:\t%d\n", argv[i], buffer.tag.value & 0xffffff); } }