NAME ^

src/stacks.c - Stack handling routines for Parrot

DESCRIPTION ^

The stack is stored as a linked list of chunks (Stack_Chunk), where each chunk has room for one entry.

Functions ^

void stack_system_init

Called from make_interpreter() to initialize the interpreter's register stacks.

Stack_Chunk_t *cst_new_stack_chunk

Get a new chunk either from the freelist or allocate one.

Stack_Chunk_t *new_stack

Create a new stack and name it. stack->name is used for debugging/error reporting.

void mark_stack

Mark entries in a stack structure during DOD.

void stack_destroy

stack_destroy() doesn't need to do anything, since GC does it all.

size_t stack_height

Returns the height of the stack. The maximum "depth" is height - 1.

Stack_Entry_t *stack_entry

If depth >= 0, return the entry at that depth from the top of the stack, with 0 being the top entry. If depth < 0, then return the entry |depth| entries from the bottom of the stack. Returns NULL if |depth| number> of entries in stack.

void rotate_entries

Rotate the top N entries by one. If N > 0, the rotation is bubble up, so the top most element becomes the Nth element. If N < 0, the rotation is bubble down, so that the Nth element becomes the top most element.

*/

PARROT_API void rotate_entries(PARROT_INTERP, ARGMOD(Stack_Chunk_t **stack_p), INTVAL num_entries) { Stack_Chunk_t * const stack = *stack_p;

    if (num_entries >= -1 && num_entries <= 1) {
        return;
    }

    if (num_entries < 0) {
        INTVAL i;
        Stack_Entry_t temp;
        INTVAL depth;

        num_entries = -num_entries;
        depth = num_entries - 1;

        if (stack_height(interp, stack) < (size_t)num_entries)
            Parrot_ex_throw_from_c_args(interp, NULL, ERROR_STACK_SHALLOW,
                "Stack too shallow!");

        /* XXX Dereferencing stack_entry here is a cavalcade of danger */
        temp = *stack_entry(interp, stack, depth);
        for (i = depth; i > 0; i--) {
            *stack_entry(interp, stack, i) =
                *stack_entry(interp, stack, i - 1);
        }

        *stack_entry(interp, stack, 0) = temp;
    }
    else {
        INTVAL i;
        Stack_Entry_t temp;
        INTVAL depth = num_entries - 1;

        if (stack_height(interp, stack) < (size_t)num_entries)
            Parrot_ex_throw_from_c_args(interp, NULL, ERROR_STACK_SHALLOW,
                "Stack too shallow!");

        /* XXX Dereferencing stack_entry here is a cavalcade of danger */
        temp = *stack_entry(interp, stack, 0);

        for (i = 0; i < depth; i++) {
            *stack_entry(interp, stack, i) =
                *stack_entry(interp, stack, i + 1);
        }

        *stack_entry(interp, stack, depth) = temp;
    }
}
/*

Stack_Entry_t *stack_prepare_push

Return a pointer, where new entries go for push.

void stack_push

Push something on the generic stack.

Note that the cleanup pointer, if non-NULL, points to a routine that'll be called when the entry is removed from the stack. This is handy for those cases where you need some sort of activity to take place when an entry is removed, such as when you push a lexical lock onto the call stack, or localize (or tempify, or whatever we're calling it) variable or something.

*/

PARROT_API void stack_push(PARROT_INTERP, ARGMOD(Stack_Chunk_t **stack_p), ARGIN(void *thing), Stack_entry_type type, NULLOK(Stack_cleanup_method cleanup)) { Stack_Entry_t * const entry = (Stack_Entry_t *)stack_prepare_push(interp, stack_p);

    /* Remember the type */
    entry->entry_type = type;

    /* Remember the cleanup function */
    entry->cleanup = cleanup;

    /* Store our thing */
    switch (type) {
        case STACK_ENTRY_MARK:
            UVal_int(entry->entry) = *(INTVAL *)thing;
            break;
        case STACK_ENTRY_DESTINATION:
            UVal_ptr(entry->entry) = thing;
            break;
        case STACK_ENTRY_ACTION:
        case STACK_ENTRY_PMC:
            UVal_pmc(entry->entry) = (PMC *)thing;
            break;
        default:
            Parrot_ex_throw_from_c_args(interp, NULL, ERROR_BAD_STACK_TYPE,
                "Invalid Stack_Entry_type!");
    }
}
/*

Stack_Entry_t *stack_prepare_pop

Return a pointer, where new entries are popped off.

void *stack_pop

Pop off an entry and return a pointer to the contents.

*/

PARROT_API PARROT_CAN_RETURN_NULL void * stack_pop(PARROT_INTERP, ARGMOD(Stack_Chunk_t **stack_p), ARGOUT_NULLOK(void *where), Stack_entry_type type) { Stack_Chunk_t *cur_chunk = *stack_p; Stack_Entry_t * const entry = (Stack_Entry_t *)stack_prepare_pop(interp, stack_p);

    /* Types of 0 mean we don't care */
    if (type && entry->entry_type != type)
        Parrot_ex_throw_from_c_args(interp, NULL, ERROR_BAD_STACK_TYPE,
            "Wrong type on top of stack!\n");

    /* Cleanup routine? */
    if (entry->cleanup != STACK_CLEANUP_NULL)
        (*entry->cleanup) (interp, entry);

    /* Sometimes the caller cares what the value was */
    if (where) {
        /* Snag the value */
        switch (type) {
        case STACK_ENTRY_MARK:
            *(INTVAL *)where   = UVal_int(entry->entry);
            break;
        case STACK_ENTRY_DESTINATION:
            *(void **)where    = UVal_ptr(entry->entry);
            break;
        case STACK_ENTRY_ACTION:
        case STACK_ENTRY_PMC:
            *(PMC **)where     = UVal_pmc(entry->entry);
            break;
        default:
            Parrot_ex_throw_from_c_args(interp, NULL, ERROR_BAD_STACK_TYPE,
                "Wrong type on top of stack!\n");
        }
    }

    /* recycle this chunk to the free list if it's otherwise unreferenced */
    if (cur_chunk->refcount <= 0) {
        Small_Object_Pool * const pool = cur_chunk->pool;

        pool->dod_object(interp, pool, (PObj *)cur_chunk);
        pool->add_free_object(interp, pool, (PObj *)cur_chunk);
    }

    return where;
}
/*

void *pop_dest

Pop off a destination entry and return a pointer to the contents.

void *stack_peek

Peek at stack and return pointer to entry and the type of the entry.

Stack_entry_type get_entry_type

Returns the stack entry type of entry.

void Parrot_dump_dynamic_environment

Print a representation of the dynamic stack to the standard error (using PIO_eprintf). This is used only temporarily for debugging.

static void run_cleanup_action

Runs the sub PMC from the Stack_Entry_t pointer with an INTVAL arg of 0. Used in Parrot_push_action.

void Parrot_push_action

Pushes an action handler onto the dynamic environment.

void Parrot_push_mark

Push a cleanup mark onto the dynamic environment.

void Parrot_pop_mark

Pop items off the dynamic environment up to the mark.

SEE ALSO ^

include/parrot/stacks.h and include/parrot/enums.h.


parrot