diff --git a/src/c/debug.c b/src/c/debug.c index 3c7b1bc..ecef2dd 100644 --- a/src/c/debug.c +++ b/src/c/debug.c @@ -123,7 +123,6 @@ void debug_printf( int level, int indent, wchar_t *format, ... ) { #ifdef DEBUG if ( level & verbosity ) { fwide( stderr, 1 ); - fputws( L"\n", stderr ); for ( int i = 0; i < indent; i++ ) { fputws( L" ", stderr ); } diff --git a/src/c/environment/environment.c b/src/c/environment/environment.c index 1c8ad1b..8dec0f3 100644 --- a/src/c/environment/environment.c +++ b/src/c/environment/environment.c @@ -25,6 +25,8 @@ #include "payloads/exception.h" #include "payloads/psse_string.h" +#include "ops/truth.h" + /** * @brief Flag to prevent re-initialisation. */ @@ -33,14 +35,14 @@ bool environment_initialised = false; /** * @brief Initialise a minimal environment, so that Lisp can be bootstrapped. * - * @param node theindex of the node we are initialising. + * @param node the index of the node we are initialising. * @return struct pso_pointer t on success, else an exception. */ struct pso_pointer initialise_environment( uint32_t node ) { struct pso_pointer result = initialise_memory( node ); - if ( !exceptionp( result ) ) { + if ( truep( result ) ) { debug_print( L"Initialising `nil`... ", DEBUG_BOOTSTRAP, 0); struct pso_pointer n = allocate( NILTAG, 2 ); @@ -50,6 +52,7 @@ struct pso_pointer initialise_environment( uint32_t node ) { object->payload.cons.cdr = nil; nil = n; + lock_object( nil); debug_print( L"success\n", DEBUG_BOOTSTRAP, 0); } else { result = @@ -63,12 +66,14 @@ struct pso_pointer initialise_environment( uint32_t node ) { debug_print( L"Initialising `t`... ", DEBUG_BOOTSTRAP, 0); struct pso_pointer n = allocate( TRUETAG, 2 ); - if ( ( n.page == 0 ) && ( n.offset == 1 ) ) { + // offset is in words, and size of a pso2 is four words + if ( ( n.page == 0 ) && ( n.offset == 4 ) ) { struct pso2 *object = pointer_to_object( n ); object->payload.string.character = L't'; object->payload.cons.cdr = t; t = n; + lock_object(t); debug_print( L"success\n", DEBUG_BOOTSTRAP, 0); } else { result = @@ -83,6 +88,7 @@ struct pso_pointer initialise_environment( uint32_t node ) { result = c_bind( c_string_to_lisp_symbol( L"t" ), t, result ); environment_initialised = true; + debug_print( L"\nEnvironment initialised successfully.\n", DEBUG_BOOTSTRAP, 0); } return result; diff --git a/src/c/memory/node.c b/src/c/memory/node.c index 5c70ec5..4cc9db0 100644 --- a/src/c/memory/node.c +++ b/src/c/memory/node.c @@ -41,9 +41,10 @@ struct pso_pointer nil = ( struct pso_pointer ) { 0, 0, 0 }; /** * @brief the canonical `t` (true) pointer. - * + * Offset 4, because `t` should be the second pso2 allocated, the offset is + * given in words, and the size of a pso2 should be four words. */ -struct pso_pointer t = ( struct pso_pointer ) { 0, 0, 1 }; +struct pso_pointer t = ( struct pso_pointer ) { 0, 0, 4 }; /** diff --git a/src/c/memory/page.c b/src/c/memory/page.c index 74ae5c7..4b27abc 100644 --- a/src/c/memory/page.c +++ b/src/c/memory/page.c @@ -36,6 +36,8 @@ #include "payloads/free.h" +#include "ops/truth.h" + /** * @brief The pages which have so far been initialised. * @@ -52,15 +54,11 @@ union page *pages[NPAGES]; uint32_t npages_allocated = 0; /** - * @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 pso_pointer the new head for the freelist for this size_class, + * Initialise arrays for objects of different size classes, in this case class 2. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? */ -struct pso_pointer initialise_page( union page *page_addr, uint16_t page_index, +struct pso_pointer initialise_pso2_array(union page *page_addr, uint16_t page_index, uint8_t size_class, struct pso_pointer freelist ) { struct pso_pointer result = freelist; @@ -68,18 +66,12 @@ struct pso_pointer initialise_page( union page *page_addr, uint16_t page_index, int obj_bytes = obj_size * sizeof( uint64_t ); int objs_in_page = PAGE_BYTES / obj_bytes; - debug_printf(DEBUG_ALLOC, 0, - L"Initialising page %d for objects of size class %d...", - page_index, size_class); - // 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 = - ( struct pso2 * ) ( page_addr + ( i * obj_bytes ) ); - + struct pso2 *object = + ( struct pso2 * ) &page_addr->pso2s[i]; object->header.tag.bytes.size_class = size_class; strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, TAGLENGTH ); @@ -90,7 +82,182 @@ struct pso_pointer initialise_page( union page *page_addr, uint16_t page_index, ( uint16_t ) ( i * obj_size ) ); } - debug_print( L"page allocated.\n", DEBUG_ALLOC, 0); + return result; +} +/** + * Initialise arrays for objects of different size classes, in this case class 3. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? + */ +struct pso_pointer initialise_pso3_array(union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_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; + + for ( int i = objs_in_page - 1; i >= 0; i-- ) { + struct pso3 *object = + ( struct pso3 * ) &page_addr->pso3s[i]; + object->header.tag.bytes.size_class = size_class; + strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, + TAGLENGTH ); + object->payload.free.next = result; + + result = + make_pointer( node_index, page_index, + ( uint16_t ) ( i * obj_size ) ); + } + + return result; +} +/** + * Initialise arrays for objects of different size classes, in this case class 4. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? + */ +struct pso_pointer initialise_pso4_array(union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_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; + + for ( int i = objs_in_page - 1; i >= 0; i-- ) { + struct pso4 *object = + ( struct pso4 * ) &page_addr->pso4s[i]; + object->header.tag.bytes.size_class = size_class; + strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, + TAGLENGTH ); + object->payload.free.next = result; + + result = + make_pointer( node_index, page_index, + ( uint16_t ) ( i * obj_size ) ); + } + + return result; +} +/** + * Initialise arrays for objects of different size classes, in this case class 5. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? + */ +struct pso_pointer initialise_pso5_array(union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_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; + + for ( int i = objs_in_page - 1; i >= 0; i-- ) { + struct pso5 *object = + ( struct pso5 * ) &page_addr->pso5s[i]; + object->header.tag.bytes.size_class = size_class; + strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, + TAGLENGTH ); + object->payload.free.next = result; + + result = + make_pointer( node_index, page_index, + ( uint16_t ) ( i * obj_size ) ); + } + + return result; +} +/** + * Initialise arrays for objects of different size classes, in this case class 6. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? + */ +struct pso_pointer initialise_pso6_array(union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_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; + + for ( int i = objs_in_page - 1; i >= 0; i-- ) { + struct pso6 *object = + ( struct pso6 * ) &page_addr->pso6s[i]; + object->header.tag.bytes.size_class = size_class; + strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, + TAGLENGTH ); + object->payload.free.next = result; + + result = + make_pointer( node_index, page_index, + ( uint16_t ) ( i * obj_size ) ); + } + + return result; +} +/** + * Initialise arrays for objects of different size classes, in this case class 7. + * This is boilerplate code and there must be some way of doing it better, but I don't + * know it. Macro? + */ +struct pso_pointer initialise_pso7_array(union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_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; + + for ( int i = objs_in_page - 1; i >= 0; i-- ) { + struct pso7 *object = + ( struct pso7 * ) &page_addr->pso7s[i]; + object->header.tag.bytes.size_class = size_class; + strncpy( &( object->header.tag.bytes.mnemonic[0] ), FREETAG, + TAGLENGTH ); + object->payload.free.next = result; + + result = + make_pointer( node_index, page_index, + ( uint16_t ) ( i * obj_size ) ); + } + + return result; +} + +/** + * @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 pso_pointer the new head for the freelist for this size_class, + */ +struct pso_pointer initialise_page( union page *page_addr, uint16_t page_index, + uint8_t size_class, + struct pso_pointer freelist ) { + struct pso_pointer result = nil; + int obj_size = pow( 2, size_class ); + int obj_bytes = obj_size * sizeof( uint64_t ); + int objs_in_page = PAGE_BYTES / obj_bytes; + + debug_printf(DEBUG_ALLOC, 0, + L"Initialising page %d for objects of size class %d...", + page_index, size_class); + + switch (size_class) { + case 2: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + case 3: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + case 4: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + case 5: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + case 6: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + case 7: result=initialise_pso2_array(page_addr, page_index, size_class, freelist); break; + default: + result = nil; + } + + debug_print( nilp(result)? L"fail.\n" : L"success.\n", DEBUG_ALLOC, 0); return result; } @@ -120,22 +287,19 @@ struct pso_pointer allocate_page( uint8_t size_class ) { memset( pg, 0, sizeof( union page ) ); pages[npages_allocated] = pg; debug_printf( DEBUG_ALLOC, 0, - L"Allocated page %d for objects of size class %x.\n", + L"\nAllocated page %d for objects of size class %x.\n", npages_allocated, size_class ); freelists[size_class] = initialise_page( ( union page * ) pg, npages_allocated, size_class, freelists[size_class] ); - debug_printf( DEBUG_ALLOC, 0, - L"Initialised page %d; freelist for size class %x updated.\n", - npages_allocated, size_class ); +// result = freelists[size_class]; - if ( npages_allocated == 0 ) { - // first page allocated; initialise nil and t - nil = lock_object( allocate( NILTAG, 2 ) ); - t = lock_object( allocate( TRUETAG, 2 ) ); - } + debug_printf( DEBUG_ALLOC, 0, + L"Initialised page %d; freelist for size class %x updated with head at page %d, offset %d.\n", + npages_allocated, size_class, + freelists[size_class].page, freelists[size_class].offset); npages_allocated++; } else { diff --git a/src/c/memory/pso.c b/src/c/memory/pso.c index 16ded6e..3daa4a9 100644 --- a/src/c/memory/pso.c +++ b/src/c/memory/pso.c @@ -15,6 +15,7 @@ */ #include +#include #include #include "debug.h" @@ -38,7 +39,8 @@ * @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; + // `t`, because if `allocate_page` fails it will be set to `nil`. + struct pso_pointer result = t; #ifdef DEBUG debug_printf( DEBUG_ALLOC, 0, L"Allocating object of size class %d with tag `%s`... ", size_class, tag); @@ -49,7 +51,14 @@ struct pso_pointer allocate( char *tag, uint8_t size_class ) { result = allocate_page( size_class ); } - if ( !exceptionp( result ) && not( freelists[size_class] ) ) { + if (nilp(result)) { + fputws( L"FATAL: Page space exhausted\n", stderr ); + exit(1); // TODO: we don't want to do this! Somehow, we need to + // recover a workable environment, ideally by throwing a pre-made + // exception. + } + + if ( !exceptionp( result ) && !nilp(result)) { result = freelists[size_class]; struct pso2 *object = pointer_to_object( result ); freelists[size_class] = object->payload.free.next; @@ -57,6 +66,8 @@ struct pso_pointer allocate( char *tag, uint8_t size_class ) { strncpy( ( char * ) ( object->header.tag.bytes.mnemonic ), tag, TAGLENGTH ); + debug_printf( DEBUG_ALLOC, 0, L"at page %d, offset %d... ", result.page, result.offset); + /* the object ought already to have the right size class in its tag * because it was popped off the freelist for that size class. */ if ( object->header.tag.bytes.size_class != size_class ) { @@ -67,7 +78,6 @@ struct pso_pointer allocate( char *tag, uint8_t size_class ) { if ( object->header.count != 0 ) { // TODO: return an exception instead? Or warn, set it, and continue? } - } } // TODO: else throw exception @@ -127,11 +137,11 @@ struct pso_pointer inc_ref( struct pso_pointer pointer ) { struct pso_pointer dec_ref( struct pso_pointer pointer ) { struct pso2 *object = pointer_to_object( pointer ); - if ( object->header.count > 0 && object->header.count != MAXREFERENCE ) { + if ( !nilp(pointer) && object->header.count > 0 && object->header.count != MAXREFERENCE ) { object->header.count--; #ifdef DEBUG debug_printf( DEBUG_ALLOC, 0, - L"\nDecremented object of type %4.4s at page %d, offset %d to count %d", + L"\nDecremented object of type %3.3s at page %d, offset %d to count %d", ( ( char * ) ( object->header.tag.bytes.mnemonic ) ), pointer.page, pointer.offset, object->header.count ); if ( vectorpointp( pointer ) ) { diff --git a/src/c/ops/string_ops.c b/src/c/ops/string_ops.c index 0f6741a..cb82abe 100644 --- a/src/c/ops/string_ops.c +++ b/src/c/ops/string_ops.c @@ -73,7 +73,7 @@ struct pso_pointer make_string_like_thing( wint_t c, struct pso_pointer tail, char *tag ) { struct pso_pointer pointer = nil; - if ( check_type( tail, tag ) || check_tag( tail, NILTV ) ) { + if ( check_type( tail, tag ) || nilp(tail) ) { pointer = allocate( tag, CONS_SIZE_CLASS ); struct pso2 *cell = pointer_to_object( pointer ); @@ -85,9 +85,10 @@ struct pso_pointer make_string_like_thing( wint_t c, struct pso_pointer tail, debug_println( DEBUG_ALLOC ); } else { // \todo should throw an exception! + struct pso2* tobj = pointer_to_object( tail); debug_printf( DEBUG_ALLOC, 0, - L"Warning: only %4.4s can be prepended to %4.4s\n", - tag, tag ); + L"Warning: %3.3s cannot be prepended to %3.3s\n", + tag, tobj->header.tag.bytes.mnemonic ); } return pointer; @@ -126,7 +127,7 @@ struct pso_pointer make_keyword( wint_t c, struct pso_pointer tail ) { * @param tail the symbol which is being built. */ struct pso_pointer make_symbol( wint_t c, struct pso_pointer tail ) { - return make_string_like_thing( c, tail, STRINGTAG ); + return make_string_like_thing( c, tail, SYMBOLTAG ); } diff --git a/src/c/ops/truth.c b/src/c/ops/truth.c index 8ffb2f5..7b0eb76 100644 --- a/src/c/ops/truth.c +++ b/src/c/ops/truth.c @@ -49,12 +49,15 @@ bool not( struct pso_pointer p ) { * each is considered equivalent. So we don't check the node when considering * whether `nil` really is `nil`, or `t` really is `t`. * + * Note that the offset is 4 because `t` should be the second pso2 allocated, + * the offset is given in words, and the size of a pso2 should be four words + * * @param p a pointer * @return true if `p` points to `t`. * @return false otherwise. */ bool truep( struct pso_pointer p ) { - return ( p.page == 0 && p.offset == 1 ); + return ( p.page == 0 && p.offset == 4 ); } /** diff --git a/src/c/payloads/psse_string.h b/src/c/payloads/psse_string.h index ea232ae..9b83d99 100644 --- a/src/c/payloads/psse_string.h +++ b/src/c/payloads/psse_string.h @@ -33,8 +33,6 @@ struct string_payload { struct pso_pointer cdr; }; -struct pso_pointer make_string( wint_t c, struct pso_pointer tail ); - struct pso_pointer destroy_string( struct pso_pointer fp, struct pso_pointer env ); diff --git a/src/c/payloads/stack.c b/src/c/payloads/stack.c index 3f144df..f342d92 100644 --- a/src/c/payloads/stack.c +++ b/src/c/payloads/stack.c @@ -78,19 +78,17 @@ struct pso_pointer destroy_stack_frame( struct pso_pointer fp, struct pso_pointer env ) { if ( stackp( fp ) ) { struct pso4 *frame = pointer_to_pso4( fp ); - struct pso4 *casualty = - pointer_to_pso4( frame->payload.stack_frame.arg[0] ); - dec_ref( casualty->payload.stack_frame.previous ); - dec_ref( casualty->payload.stack_frame.function ); - dec_ref( casualty->payload.stack_frame.more ); + dec_ref( frame->payload.stack_frame.previous ); + dec_ref( frame->payload.stack_frame.function ); + dec_ref( frame->payload.stack_frame.more ); for ( int i = 0; i < args_in_frame; i++ ) { - dec_ref( casualty->payload.stack_frame.arg[i] ); + dec_ref( frame->payload.stack_frame.arg[i] ); } - casualty->payload.stack_frame.args = 0; - casualty->payload.stack_frame.depth = 0; + frame->payload.stack_frame.args = 0; + frame->payload.stack_frame.depth = 0; } return nil;