Subrutinas - Pasaje de Parámetros

Anuncio
Subrutinas
Parámetros
Lenguajes de Programación I
Subrutinas - Pasaje de Parámetros
Ernesto Hernández-Novich
<emhn@usb.ve>
c 2006-2010
Copyright Subrutinas
Parámetros
Subrutinas
Mecanismo principal para abstracción de control.
Asocian un nombre a una secuencia de instrucciones.
Comportamiento varía según parámetros.
Funciones – cuando retornan valores.
Puras – No causan efectos de borde.
Impuras – Causan efectos de borde.
Procedimientos – cuando no retornan valores.
En la mayoría de los lenguajes, deben ser declaradas
antes de ser utilizadas.
Subrutinas
Parámetros
Registro de Activación
Profundizando lo que ya estudiamos
Cada rutina invocada tiene un Registro de Activación en
la Pila de Ejecución.
Se arma en parte por el llamador y en parte por el llamado.
Se desarma cuando la rutina retorna.
Construcción basada en aprovechar características del
hardware subyacente.
Stack Pointer – registro que apunta al último elemento
utilizado de la Pila de Ejecución.
Frame Pointer – registro que apunta a una ubicación fija
dentro del Registro de Activación.
CALL y RETURN – auxilian al código generado por el
compilador.
En lenguajes dinámicos parte o todo este comportamiento
debe ser simulado en el heap.
Subrutinas
Parámetros
Registro de Activación
La importancia de ser Frame Pointer
Posiciones de objetos expresada como desplazamientos a
partir del frame pointer.
Objetos con Tamaño Fijo
Desplazamientos son conocidos a tiempo de compilación.
Ubicados cerca del frame pointer – ambos “lados”.
Acceso directo a tiempo de ejecución.
Objetos con Tamaño Variables
Desplazamientos desconocido a tiempo de compilación.
Ubicados lejos del frame pointer – ambos “lados”.
Acceso indirecto a tiempo de ejecución (dope vector).
Aplica para argumentos y variables – orientación diferente
Locales – después de la parte estática en el llamado.
Argumentos – antes de la parte estática en el llamador.
Subrutinas
Parámetros
Cadenas Dinámica y Estática
Criterios de inclusión y dependencia de ejecución
Cadena Dinámica – representa el orden de llamadas
Se mantiene conservando en cada Registro de Activación,
el apuntador al Registro de Activación anterior.
Responsabilidad del llamado a tiempo de ejecución.
Indispensable para alcance dinámico y excepciones.
La Cadena Estática – representa el anidamiento de rutinas
(en lenguajes donde tenga sentido).
Responsabilidad del llamador a tiempo de compilación.
Indispensable para alcance estático a objetos no locales.
Aprovecha acceso indirecto del procesador de ser posible.
Subrutinas
Parámetros
Mantenimiento del Registro de Activación
Responsabilidad compartida entre llamador y llamado
Usualmente tres fragmentos de código generados a
tiempo de compilación:
Secuencia de Llamada – código ejecutado por el llamador
inmediatamente antes de transferir el control a la subrutina.
Prólogo – código ejecutado por el llamado justo al entrar
en la subrutina.
Epílogo – código ejecutado por el llamado justo antes de
retornar de la subrutina.
Subrutinas
Parámetros
¿Qué se hace en la Secuencia de Llamada?
Salvar registros cuyo valor sea necesario al retornar.
Evaluar y colocar parámetros en la pila – tamaño variable
van antes que tamaño fijo.
Reserva espacio para valores de retorno en caso que
usen la pila (si aplica).
Calcular Cadena Estática y colocarla en la pila (si aplica).
Saltar a la Subrutina (instrucción especial si es posible).
La subrutina ejecuta y eventualmente retorna.
Tomar los valores de retorno (si aplica).
Restaurar registros salvados.
Subrutinas
Parámetros
¿Qué se hace en el Prólogo?
Salvar valor actual del frame pointer – esto extiende la
cadena dinámica.
Apuntar el frame pointer a la ubicación apropiada –
usualmente el tope actual de la pila.
Reservar espacio en la pila para las variables locales –
modificación directa del stack pointer.
Salvar registros que sean utilizados en la subrutina.
Subrutinas
Parámetros
¿Qué se hace en el Epílogo?
Colocar el valor de retorno en la posición adecuada del
Registro de Activación del llamador (si aplica).
Restaurar registros que fueron utilizados en la subrutina.
Restaurar los valores del stack pointer y frame pointer.
Asignar frame pointer al stack pointer.
Desempilar frame pointer.
Retornar el control al llamador – instrucción especial si es
posible.
Subrutinas
Parámetros
¿Cómo se mantiene la Cadena Estática?
A tiempo de compilación se sabe
El anidamiento de rutinas.
Quién llama a quién.
Cada vez que el compilador va a generar código para una
llamada, debe hacer una observación simple:
Si el llamado está anidado dentro del llamador:
La Cadena Estática del llamado debe apuntar al llamador.
Trivial – basta copiar el frame pointer propio como cadena
estática del llamado.
Si el llamado está k ≥ 0 alcances hacia afuera:
k alcances envuelven al llamador.
El llamador debe seguir su cadena estática k veces y copiar
ese valor como cadena estática del llamado.
Subrutinas
Parámetros
Pasaje de Parámetros
Permiten influir sobre el comportamiento de la subrutina.
Formales – indicados simbólicamente en la definición
proc foo(int bar, bool baz, float qux)
Reales – pasados efectivamente a tiempo de ejecución
foo(42,true,3.1415)
También llamados argumentos o actuales.
Invocación
Notación prefija en la mayoría de los lenguajes.
LISP asume que primer símbolo de expresión es la función.
Notación infija opcional (ML, Haskell).
Notación mezclada como en Smalltalk.
Subrutinas
Parámetros
Modalidades para el Pasaje de Parámetros
Pasaje por Valor (Call by Value)
Pasaje por Valor
Implantación – simple
Calcular el valor del parámetro actual.
Espacio para el formal en la pila recibe una copia del valor
calculado.
Puede optimizarse usando un registro en lugar de espacio
en la pila.
Ventaja – imposible que la rutina modifique los actuales.
Desventaja – costoso pasar objetos grandes.
Subrutinas
Parámetros
Modalidades para el Pasaje de Parámetros
Pasaje por Referencia
Pasaje por Referencia
Implantación – simple
Calcular la dirección del parámetro actual.
Espacio para el formal en la pila recibe una copia del valor
calculado – es una referencia.
Se usa en la subrutina como un l-value.
Ventaja – eficiente, pues no hay copia de valores ni
requiere espacio adicional.
Desventajas
Acceso más lento – al menos una indirección.
Los actuales deben ser l-values.
Crean aliases.
Subrutinas
Parámetros
La diferencia...
x : integer
procedure foo( y : integer )
y := 3;
print x;
end
x := 2
foo(x)
print x
Si y es pasada por valor, imprime 2 2.
Si y es pasada por referencia, imprime 3 3.
Subrutinas
Parámetros
Variaciones en las Modalidades
¿Por valor o por referencia?
Lenguajes que sólo pasan por valor – la mayoría.
Simular pasaje por referencia pasando un apuntador.
Casos especiales (arreglos en C).
Lenguajes que sólo pasan por referencia – Fortran.
Lenguajes que ofrecen ambos mecanismos a través de
palabras reservadas – (var en Pascal).
Subrutinas
Parámetros
Variaciones en las Modalidades
Parámetros Sólo-Lectura (Modula-3, C)
Eficiencia de pasaje por referencia.
Seguridad de pasaje por valor.
Se indica en declaración del formal que no pueda ser
modificado dentro de la subrutina.
Dirección del Pasaje (Ada)
in, out y inout.
Los parámetros deben ser copiados al entrar.
in es equivalente a pasaje por valor.
out es denominado llamada por resultado.
inout es denominado llamada por valor/resultado.
El efecto de los cambios para un inout puede o no ser
inmediato.
Subrutinas
Parámetros
Clausuras
En lenguajes que permiten pasar subrutinas como
parámetros actuales
Debe pasarse la referencia al cuerpo de la subrutina.
Debe pasarse el ambiente de referencia solamente si el
lenguaje soporta anidamiento de subrutinas.
Rutinario y simple en lenguajes funcionales porque los
ambientes de referencia sólo interesan por sus valores.
En lenguajes imperativos el ambiente de referencia incluye
referencias a los objetos alcanzables al momento de
construir la clausura.
Subrutinas
Parámetros
Parámetros de Propósito Especial
Arreglos con Forma Dinámica (Conformant Arrays).
Cuando la forma del arreglo sólo se conoce a tiempo de
ejecución.
Pasar una referencia a la base y las dimensiones.
Valores por defecto para parámetros omitidos.
Parámetros nombrados (keyword parameters) vs.
parámetros posicionales.
Número variable de argumentos.
Recibir todo como una lista y manipularla (LISP, Perl).
Utilizar macros/librerías para acceder a ellos en la pila de
ejecución (C).
Obligar a que todos sean del mismo tipo (C#, Java).
Subrutinas
Parámetros
Valores de Retorno
La mayoría de los lenguajes son restrictivos al respecto:
Un valor escalar.
...que podría ser un apuntador.
Lenguajes más flexibles permiten retornar elementos de
tipos compuestos (registros y listas) o funciones.
¿Cómo retornarlo?
Instrucción explícita de retorno (return).
Valor de la última expresión evaluada.
Descargar