2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/stacks.c - Stack handling routines for Parrot
11 The stack is stored as a linked list of chunks (C<Stack_Chunk>),
12 where each chunk has room for one entry.
22 #include "parrot/parrot.h"
23 #include "parrot/stacks.h"
25 /* HEADERIZER HFILE: include/parrot/stacks.h */
29 =item C<void stack_system_init>
31 Called from C<make_interpreter()> to initialize the interpreter's
40 stack_system_init(SHIM_INTERP
)
46 =item C<Stack_Chunk_t * cst_new_stack_chunk>
48 Get a new chunk either from the freelist or allocate one.
55 PARROT_WARN_UNUSED_RESULT
56 PARROT_CANNOT_RETURN_NULL
58 cst_new_stack_chunk(PARROT_INTERP
, ARGIN(const Stack_Chunk_t
*chunk
))
60 Small_Object_Pool
* const pool
= chunk
->pool
;
61 Stack_Chunk_t
* const new_chunk
= (Stack_Chunk_t
*)pool
->get_free_object(interp
, pool
);
63 PObj_bufstart(new_chunk
) = NULL
;
64 PObj_buflen(new_chunk
) = 0;
66 new_chunk
->pool
= chunk
->pool
;
67 new_chunk
->name
= chunk
->name
;
74 =item C<Stack_Chunk_t * new_stack>
76 Create a new stack and name it. C<< stack->name >> is used for
77 debugging/error reporting.
84 PARROT_CANNOT_RETURN_NULL
85 PARROT_WARN_UNUSED_RESULT
87 new_stack(PARROT_INTERP
, ARGIN(const char *name
))
89 Small_Object_Pool
* const pool
= make_bufferlike_pool(interp
, sizeof (Stack_Chunk_t
));
90 Stack_Chunk_t
* const chunk
= (Stack_Chunk_t
*)(pool
->get_free_object
)(interp
, pool
);
92 chunk
->prev
= chunk
; /* mark the top of the stack */
94 chunk
->pool
= pool
; /* cache the pool pointer, for ease */
102 =item C<void mark_stack>
104 Mark entries in a stack structure during DOD.
112 mark_stack(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
*chunk
))
114 for (; ; chunk
= chunk
->prev
) {
115 Stack_Entry_t
*entry
;
117 pobject_lives(interp
, (PObj
*)chunk
);
119 if (chunk
== chunk
->prev
)
122 entry
= STACK_DATAP(chunk
);
124 if (entry
->entry_type
== STACK_ENTRY_PMC
&& UVal_pmc(entry
->entry
))
125 pobject_lives(interp
, (PObj
*)UVal_pmc(entry
->entry
));
131 =item C<void stack_destroy>
133 stack_destroy() doesn't need to do anything, since GC does it all.
141 stack_destroy(SHIM(Stack_Chunk_t
*top
))
148 =item C<size_t stack_height>
150 Returns the height of the stack. The maximum "depth" is height - 1.
157 PARROT_WARN_UNUSED_RESULT
159 stack_height(SHIM_INTERP
, ARGIN(const Stack_Chunk_t
*chunk
))
163 for (; ; chunk
= chunk
->prev
) {
164 if (chunk
== chunk
->prev
)
175 =item C<Stack_Entry_t * stack_entry>
177 If C<< depth >= 0 >>, return the entry at that depth from the top of the
178 stack, with 0 being the top entry. If C<depth < 0>, then return the
179 entry C<|depth|> entries from the bottom of the stack. Returns C<NULL>
180 if C<|depth| > number> of entries in stack.
187 PARROT_CAN_RETURN_NULL
188 PARROT_WARN_UNUSED_RESULT
190 stack_entry(PARROT_INTERP
, ARGIN(Stack_Chunk_t
*stack
), INTVAL depth
)
192 Stack_Chunk_t
*chunk
;
193 size_t offset
= (size_t)depth
;
202 if (chunk
== chunk
->prev
)
208 if (chunk
== chunk
->prev
)
211 return STACK_DATAP(chunk
);
216 =item C<void rotate_entries>
218 Rotate the top N entries by one. If C<< N > 0 >>, the rotation is bubble
219 up, so the top most element becomes the Nth element. If C<< N < 0 >>, the
220 rotation is bubble down, so that the Nth element becomes the top most
227 rotate_entries(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
**stack_p
), INTVAL num_entries
)
229 Stack_Chunk_t
* const stack
= *stack_p
;
231 if (num_entries
>= -1 && num_entries
<= 1) {
235 if (num_entries
< 0) {
240 num_entries
= -num_entries
;
241 depth
= num_entries
- 1;
243 if (stack_height(interp
, stack
) < (size_t)num_entries
) {
244 real_exception(interp
, NULL
, ERROR_STACK_SHALLOW
, "Stack too shallow!");
247 /* XXX Dereferencing stack_entry here is a cavalcade of danger */
248 temp
= *stack_entry(interp
, stack
, depth
);
249 for (i
= depth
; i
> 0; i
--) {
250 *stack_entry(interp
, stack
, i
) =
251 *stack_entry(interp
, stack
, i
- 1);
254 *stack_entry(interp
, stack
, 0) = temp
;
259 INTVAL depth
= num_entries
- 1;
261 if (stack_height(interp
, stack
) < (size_t)num_entries
) {
262 real_exception(interp
, NULL
, ERROR_STACK_SHALLOW
, "Stack too shallow!");
264 /* XXX Dereferencing stack_entry here is a cavalcade of danger */
265 temp
= *stack_entry(interp
, stack
, 0);
266 for (i
= 0; i
< depth
; i
++) {
267 *stack_entry(interp
, stack
, i
) =
268 *stack_entry(interp
, stack
, i
+ 1);
271 *stack_entry(interp
, stack
, depth
) = temp
;
277 =item C<Stack_Entry_t* stack_prepare_push>
279 Return a pointer, where new entries go for push.
286 PARROT_WARN_UNUSED_RESULT
287 PARROT_CANNOT_RETURN_NULL
289 stack_prepare_push(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
**stack_p
))
291 Stack_Chunk_t
* const chunk
= *stack_p
;
292 Stack_Chunk_t
* const new_chunk
= cst_new_stack_chunk(interp
, chunk
);
294 new_chunk
->prev
= chunk
;
295 *stack_p
= new_chunk
;
297 return STACK_DATAP(new_chunk
);
302 =item C<void stack_push>
304 Push something on the generic stack.
306 Note that the cleanup pointer, if non-C<NULL>, points to a routine
307 that'll be called when the entry is removed from the stack. This is
308 handy for those cases where you need some sort of activity to take place
309 when an entry is removed, such as when you push a lexical lock onto the
310 call stack, or localize (or tempify, or whatever we're calling it)
311 variable or something.
317 stack_push(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
**stack_p
),
318 ARGIN(void *thing
), Stack_entry_type type
, NULLOK(Stack_cleanup_method cleanup
))
320 Stack_Entry_t
* const entry
= (Stack_Entry_t
*)stack_prepare_push(interp
, stack_p
);
322 /* Remember the type */
323 entry
->entry_type
= type
;
325 /* Remember the cleanup function */
326 entry
->cleanup
= cleanup
;
328 /* Store our thing */
330 case STACK_ENTRY_MARK
:
331 UVal_int(entry
->entry
) = *(INTVAL
*)thing
;
333 case STACK_ENTRY_DESTINATION
:
334 UVal_ptr(entry
->entry
) = thing
;
336 case STACK_ENTRY_ACTION
:
337 case STACK_ENTRY_PMC
:
338 UVal_pmc(entry
->entry
) = (PMC
*)thing
;
341 real_exception(interp
, NULL
, ERROR_BAD_STACK_TYPE
,
342 "Invalid Stack_Entry_type!");
348 =item C<Stack_Entry_t* stack_prepare_pop>
350 Return a pointer, where new entries are popped off.
357 PARROT_WARN_UNUSED_RESULT
358 PARROT_CANNOT_RETURN_NULL
360 stack_prepare_pop(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
**stack_p
))
362 Stack_Chunk_t
* const chunk
= *stack_p
;
364 /* the first entry (initial top) refers to itself */
365 if (chunk
== chunk
->prev
)
366 real_exception(interp
, NULL
, ERROR_STACK_EMPTY
,
367 "No entries on %s Stack!", chunk
->name
);
369 *stack_p
= chunk
->prev
;
371 return STACK_DATAP(chunk
);
376 =item C<void * stack_pop>
378 Pop off an entry and return a pointer to the contents.
383 PARROT_CAN_RETURN_NULL
385 stack_pop(PARROT_INTERP
, ARGMOD(Stack_Chunk_t
**stack_p
),
386 ARGOUT_NULLOK(void *where
), Stack_entry_type type
)
388 Stack_Chunk_t
*cur_chunk
= *stack_p
;
389 Stack_Entry_t
* const entry
=
390 (Stack_Entry_t
*)stack_prepare_pop(interp
, stack_p
);
392 /* Types of 0 mean we don't care */
393 if (type
&& entry
->entry_type
!= type
) {
394 real_exception(interp
, NULL
, ERROR_BAD_STACK_TYPE
,
395 "Wrong type on top of stack!\n");
398 /* Cleanup routine? */
399 if (entry
->cleanup
!= STACK_CLEANUP_NULL
)
400 (*entry
->cleanup
) (interp
, entry
);
402 /* Sometimes the caller cares what the value was */
406 case STACK_ENTRY_MARK
:
407 *(INTVAL
*)where
= UVal_int(entry
->entry
);
409 case STACK_ENTRY_DESTINATION
:
410 *(void **)where
= UVal_ptr(entry
->entry
);
412 case STACK_ENTRY_ACTION
:
413 case STACK_ENTRY_PMC
:
414 *(PMC
**)where
= UVal_pmc(entry
->entry
);
417 real_exception(interp
, NULL
, ERROR_BAD_STACK_TYPE
,
418 "Wrong type on top of stack!\n");
422 /* recycle this chunk to the free list if it's otherwise unreferenced */
423 if (cur_chunk
->refcount
<= 0) {
424 Small_Object_Pool
* const pool
= cur_chunk
->pool
;
426 pool
->dod_object(interp
, pool
, (PObj
*)cur_chunk
);
427 pool
->add_free_object(interp
, pool
, (PObj
*)cur_chunk
);
435 =item C<void * pop_dest>
437 Pop off a destination entry and return a pointer to the contents.
444 PARROT_WARN_UNUSED_RESULT
445 PARROT_CANNOT_RETURN_NULL
447 pop_dest(PARROT_INTERP
)
449 /* We don't mind the extra call, so we do this: (previous comment
450 * said we *do* mind, but I say let the compiler decide) */
452 (void)stack_pop(interp
, &interp
->dynamic_env
,
453 &dest
, STACK_ENTRY_DESTINATION
);
459 =item C<void * stack_peek>
461 Peek at stack and return pointer to entry and the type of the entry.
468 PARROT_CAN_RETURN_NULL
469 PARROT_WARN_UNUSED_RESULT
471 stack_peek(PARROT_INTERP
, ARGIN(Stack_Chunk_t
*stack_base
),
472 ARGMOD_NULLOK(Stack_entry_type
*type
))
474 const Stack_Entry_t
* const entry
= stack_entry(interp
, stack_base
, 0);
479 *type
= entry
->entry_type
;
481 if (entry
->entry_type
== STACK_ENTRY_DESTINATION
)
482 return UVal_ptr(entry
->entry
);
484 return (void *) UVal_pmc(entry
->entry
);
489 =item C<Stack_entry_type get_entry_type>
491 Returns the stack entry type of C<entry>.
497 PARROT_WARN_UNUSED_RESULT
500 get_entry_type(ARGIN(const Stack_Entry_t
*entry
))
502 return entry
->entry_type
;
507 =item C<void Parrot_dump_dynamic_environment>
509 Print a representation of the dynamic stack to the standard error (using
510 C<PIO_eprintf>). This is used only temporarily for debugging.
518 Parrot_dump_dynamic_environment(PARROT_INTERP
, ARGIN(Stack_Chunk_t
*dynamic_env
))
520 int height
= (int) stack_height(interp
, dynamic_env
);
522 while (dynamic_env
->prev
!= dynamic_env
) {
523 const Stack_Entry_t
* const e
= stack_entry(interp
, dynamic_env
, 0);
525 real_exception(interp
, NULL
, 1, "Control stack damaged");
528 PIO_eprintf(interp
, "[%4d: chunk %p entry %p "
529 "type %d cleanup %p]\n",
530 height
, dynamic_env
, e
,
531 e
->entry_type
, e
->cleanup
);
532 if (e
->entry_type
== STACK_ENTRY_PMC
533 || e
->entry_type
== STACK_ENTRY_ACTION
) {
534 PMC
* const thing
= UVal_pmc(e
->entry
);
536 PIO_eprintf(interp
, "[ PMC %p type %d => %Ss]\n",
537 thing
, thing
->vtable
->base_type
,
538 VTABLE_get_string(interp
, thing
));
540 else if (e
->entry_type
== STACK_ENTRY_MARK
) {
541 PIO_eprintf(interp
, "[ mark %d]\n",
544 dynamic_env
= dynamic_env
->prev
;
547 PIO_eprintf(interp
, "[%4d: chunk %p %s base]\n",
548 height
, dynamic_env
, dynamic_env
->name
);
557 F<include/parrot/stacks.h> and F<include/parrot/enums.h>.
566 * c-file-style: "parrot"
568 * vim: expandtab shiftwidth=4: