/** * payloads/stack.h * * 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. */ #include #include "debug.h" #include "memory/node.h" #include "memory/pointer.h" #include "memory/pso.h" #include "memory/pso2.h" #include "memory/pso4.h" #include "memory/tags.h" #include "payloads/cons.h" #include "ops/reverse.h" /** * @brief Construct a stack frame with this `previous` pointer, and arguments * taken from the remaining arguments to this function, which should all be * struct pso_pointer. * * @return a pso_pointer to the stack frame. */ struct pso_pointer make_frame( int arg_count, struct pso_pointer previous, ... ) { va_list args; va_start( args, previous ); struct pso_pointer frame_pointer = allocate( STACKTAG, 4 ); struct pso4 *frame = ( struct pso4 * ) pointer_to_object( frame_pointer ); #ifdef DEBUG debug_printf( DEBUG_ALLOC, 0, L"\nAllocating stack frame with %d arguments at page %d, " L"offset %d...\n", arg_count, frame_pointer.page, frame_pointer.offset ); #endif frame->payload.stack_frame.previous = previous; if ( stackp( previous ) ) { struct pso4 *op = pointer_to_pso4( previous ); frame->payload.stack_frame.depth = op->payload.stack_frame.depth + 1; } else { frame->payload.stack_frame.depth = 0; } debug_printf( DEBUG_ALLOC, 1, L"depth is %d...\n", frame->payload.stack_frame.depth ); int cursor = 0; frame->payload.stack_frame.args = arg_count; for ( ; cursor < arg_count && cursor < args_in_frame; cursor++ ) { struct pso_pointer argument = va_arg( args, struct pso_pointer ); frame->payload.stack_frame.arg[cursor] = inc_ref( argument ); } if ( cursor < arg_count ) { struct pso_pointer more_args = nil; for ( ; cursor < arg_count; cursor++ ) { more_args = c_cons( va_arg( args, struct pso_pointer ), more_args ); } frame->payload.stack_frame.more = c_reverse( more_args ); } else { for ( ; cursor < args_in_frame; cursor++ ) { frame->payload.stack_frame.arg[cursor] = nil; } } debug_printf( DEBUG_ALLOC, 1, L"Allocation of frame at page %d, offset %d completed.\n", frame_pointer.page, frame_pointer.offset ); return frame_pointer; } /** * @brief When a stack frame is freed, all its pointers must be decremented. * * Lisp calling conventions; one expected arg, the pointer to the object to * be destroyed. */ struct pso_pointer destroy_stack_frame( struct pso_pointer fp, struct pso_pointer env ) { if ( stackp( fp ) ) { struct pso4 *frame = pointer_to_pso4( fp ); 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( frame->payload.stack_frame.arg[i] ); } frame->payload.stack_frame.args = 0; frame->payload.stack_frame.depth = 0; } return nil; }