Pila de llamadas

Si, por ejemplo, una subrutina DibujaCuadrado llama a una subrutina DibujaLinea desde cuatro lugares diferentes, el código de DibujaLinea debe tener una manera de saber a dónde retornar.

Si el empujar (push) consume todo el espacio asignado para la pila de llamadas, ocurre un error llamado desbordamiento de pila.

Usualmente hay exactamente una pila de llamadas asociada a un programa en ejecución (o más precisamente, con cada tarea o hilo de un proceso), aunque pilas adicionales pueden ser creados para el manejo de señales o la multitarea cooperativa (como con setcontext).

En algunos ambientes puede haber más o menos funciones asignadas a la pila de llamadas.

Alternativamente, la memoria dentro del marco de pila (Stack Frame) se puede acceder mediante un registro separado, a menudo llamado puntero del marco (Frame Pointer); típicamente apunta a un cierto lugar fijo en la estructura del marco, tal como la localización de la dirección de retorno.

El valor es guardado al entrar en la subrutina y es restaurado pare el retorno.

Para algunos propósitos, el marco de pila de una subrutina y el de la rutina que la llama pueden ser considerados como un solapado (overlap), el solapado consiste en el área donde los parámetros son pasados desde la rutina que llama a la rutina que es llamada.

En algunos ambientes, la rutina que llama, empuja (push) cada argumento sobre la pila, extendiendo así su marco de pila; después invoca a la subrutina (la cual usará esos parámetros).

La manipulación de la pila de llamadas que se necesita en el lugar donde se realiza la llamada a una subrutina es mínima (lo que es bueno puesto que pueden haber muchos lugares de donde se llama cada subrutina).

Los valores para los argumentos reales son evaluados en el sitio de la llamada, puesto que son específicos para una particular llamada, y pueden ser o empujados (push) sobre la pila o colocados en los registros, según lo determinado por la convención de llamada utilizada.

Cuando una subrutina está lista para retornar, ejecuta un epílogo que deshace los pasos del prólogo.

Algunos lenguajes (como Pascal) permiten una sentencia goto global para transferir el control fuera de una función anidada y llevarlo hacia dentro de función externa previamente invocada.

Esta operación requiere que la pila sea desenrolado, quitando tantos marcos de pila como se necesiten para restaurar el contexto apropiado para transferir el control a la declaración de destino dentro de la función externa que la envuelve.

Otras lenguajes (tales como Object Pascal/Delphi) proporcionan el manejo de excepciones, que también requiere desenrollar la pila.

El Common Lisp permite el control de lo que sucede cuando la pila es desenrollada usando el operador especial unwind-protect.

Esta no es la única manera de ejecutar continuaciones; por ejemplo, usando múltiples pilas explícitas, la aplicación de una continuación pueden simplemente activar su pila y enrollar un valor que será pasado.

Estructura de la pila de llamadas.
En la figura se ve una pila, creciendo de abajo hacia arriba.
La subrutina DrawSquare (DibujaCuadrado) es llamada y se crea un stack frame para ella (en azul). Luego, DrawSquare llama a la subrutina DrawLine (DibujaLinea) , la cual tiene su propio stack frame (en verde).
El stack frame de cada subrutina tiene, en este caso, tres partes: * una dirección de retorno que indica la siguiente dirección a ejecutar después de que termine la subrutina, * los parámetros con que fue llamada la subrutina (que se cargan antes de llamarla), * y un espacio reservado para las variables y las constantes locales de la subrutina.