Faculdade de Ciências e Tecnologia Departamento de Matemática e Computação
Bacharelado em Ciência da Computação
Conceitos de Linguagens de
Programação
Aula 07
Rogério Eduardo Garcia
([email protected]) 11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Aula 7
Implementação de Subprogramas
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 3
Semântica Geral de Chamadas e
Retornos
Definição
– As operações de chamada e retorno de uma linguagem são conhecidas como linkagem de subprogramas 11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Implementando subprogramas
“Simples”
Semântica de chamada:
1. Salva o status de execução do chamador 2. Faz a passagem de parâmetros
3. Passa o endereço de retorno para o chamado 4. Transfere o controle para o chamado
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 5
Implementando subprogramas
“Simples”
Semântica de Retorno:
1. Se passagem-por-valor-resultado são usadas, move os valores correntes dos parâmetros para os seus respectivos pares
2. Se é uma função, move o valor funcional a um lugar que o chamador possa ter acesso
3. Restaura o status da execução do chamador 4. Transfere o controle de volta ao chamador
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Registro de Ativação
Registro de ativação
– O formato, ou leiaute, da parte não codificada de um subprograma em execução é chamado de registro de ativação
Uma instância de um registro de ativação é um
exemplo concreto de um RA (coleção de
dados para a ativação de um subprograma em
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 7
Implementando subprogramas
“Simples”
Armazenamento
Requerido:
Status
do
chamador, parâmetros, endereço de retorno, e
valor funcional (se for função)
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Código e RA de um programa
Dados + Código Compilação separada – 4 unidades Linker11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 9
Implementando Subprogramas com
Variáveis Locais Stack-Dynamic
Mais complicado porque:
– O compilador deve gerar código para causar a alocação implícita e liberação de variáveis locais – Recursão deve ser suportada (adiciona a
possibilidade de múltiplas ativações de um subprograma)
– Passagem de parâmetro
– Escopo estático e subprogramas aninhados
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Exemplo de RA
Static link11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 11
Implementando Subprogramas com
Variáveis Locais Stack-Dynamic
O RA é estático, mas o tamanho pode ser
dinâmico
O
dynamic link
aponta para o topo do RA do
chamador
Uma instância de RA é dinamicamente criada
quando um subprograma é chamado
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Exemplo de uma função em C
void sub(float total, int part) { int list[5]; float sum;
…
} [4] [3] [2] [1] [0]11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 13
Um exemplo em C sem recursão
void A(int x) { int y; ... C(y); ... } void B(float r) { int s, t; ... A(s); ... } void C(int q) { ... } void main() { float p; ... B(p); ... } 11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Conteúdo da Pilha
Note that: main calls B B calls A A calls C
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 15
Implementando Subprogramas em
Linguagens baseadas em ALGOL
A coleção de dynamic links na pilha em um
dado tempo é chamado de
dynamic chain
, ou
call chain
Variáveis locais pode ser acessadas por seus
offset a partir do início do RA. Este offset é
chamado de
local_offset
O local_offset de uma variável local pode ser
determinado pelo compilador
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Recursão
O RA usado no exemplo anterior suporta
recursão, e.g.
int factorial(int n) {
<---1 if (n <= 1)
return 1;
else return (n * factorial(n - 1)); <---2 } void main() { int value; value = factorial(3); <---3 }
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 17
RA para
factorial
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc iaSubprogramas Aninhados
Algumas linguagens non-C-based que usam escopo estático (Fortran 95, Ada, JavaScript) usam variáveis locais stack-dynamic e permitem subprogramas ser aninhados
Observação: todas variáveis que podem ser não localmente acessadas “residem” em alguma instância de registro de ativação na pilha
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 19
Localizando uma Referência
Não-Local
Encontrar o offset: fácil
Encontrar a instância de RA correta:
– Regras de semântica estática garantem que todas variáveis não-locais que podem ser referenciadas sejam alocadas em alguma instância do registro de ativação, que está na pilha, quando uma referência é feita 11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Subprogramas Aninhados
Técnica - Static Chains
Uma
static chain
é uma cadeia de links
estáticos que conecta certas instâncias de
registro de ativação
O
static link
em uma instância de RA para um
subprograma
A
aponta
para
uma
das
instâncias de RAs de ancestrais estáticos de A
A
static chain
de uma instância de RA conecta
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 21
Static Chains (continuação)
Para encontrar a declaração para uma
referência a uma variável não-local:
– É possível percorrer a static chain até que a instância de registro de ativação (IRA) que contém a variável seja encontrada (nomes de variáveis armazenados na IRA)
Definição:
static_depth
é um inteiro associado
com o escopo estático cujo valor é a
profundidade do aninhamento no escopo
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Static Chains (continuação)
main --- static_depth = 0 A --- static_depth = 1
B --- static_depth = 2
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 23
Static Chains (continuação)
Definição: O
chain_offset
ou
nesting_depth
de
uma referência não-local é a diferença entre
static_depth da referência e o contido no
escopo onde foi declarado
Uma referência pode ser representada pelo
par
(chain_offset, local_offset)
onde local_offset é o deslocamento no IRA da
variável sendo referenciada
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Exemplo em Pascal
program MAIN_2; var X : integer; procedure BIGSUB; var A, B, C : integer; procedure SUB1; var A, D : integer; begin { SUB1 } A := B + C; <---1 end; { SUB1 }procedure SUB2(X : integer); var B, E : integer; procedure SUB3; var C, E : integer; begin { SUB3 } SUB1; E := B + A: <---2 end; { SUB3 } begin { SUB2 } SUB3; A := D + E; <---3 end; { SUB2 } begin { BIGSUB } SUB2(7); end; { BIGSUB } begin BIGSUB;
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 25
Exemplo em Pascal
Seqüência de chamada paraMAIN_2 MAIN_2 chamaBIGSUB
BIGSUBchamaSUB2 SUB2chamaSUB3 SUB3chamaSUB1
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Conteúdo da Pilha:
posição 1
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 27
Exemplo em Pascal
Posição 1 em SUB1: A- (0, 3) B- (1, 4) C- (1, 5) Posição 2 em SUB3: E- (0, 4) B- (1, 4) A- (2, 3) Posição 3 em SUB2: A - (1, 3) D- error E- (0, 5) 11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc iaSubprogramas aninhados
Manutenção da Static Chain
– Na chamada (assumindo que não há parâmetros que sejam subprogramas e sem passagem de parâmetros por nome):
O IRA deve ser construída
O dynamic link é um ponteiro para o topo da pilha (anterior) O static link deve apontar para o mais recente IRA do
ancestral estático (na maioria das situações)
– Dois métodos:
1. Busca a dynamic chain até o primeiro IRA para o ancestral estático (fácil, mas lento)
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 29
Subprogramas aninhados
2. Tratar chamadas e definições como
referências a variáveis e definições (o
compilador computa o nesting depth, ou
número de escopos entre o chamador e o
procedimento
que
declarou
o
procedimento chamado; armazena esse
nesting depth e envia para o chamado)
– Veja MAIN_2 o conteúdo da pilha. A chamada para SUB1 em SUB3, esse nesting depth é 1, que é enviado para SUB1 com o chamado. O static link na nova IRA para SUB1 aponta para IRA que é apontada para o segundo static link na static chain para a IRA para SUB3
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Exemplo em Pascal
program MAIN_2; var X : integer; procedure BIGSUB; var A, B, C : integer; procedure SUB1; var A, D : integer; begin { SUB1 } A := B + C; <---1 end; { SUB1 }procedure SUB2(X : integer); var B, E : integer; procedure SUB3; var C, E : integer; begin { SUB3 } SUB1; E := B + A: <---2 end; { SUB3 } –Veja MAIN_2 o conteúdo da pilha. A chamada para SUB1 em SUB3, esse nesting depth é 1, que é enviado para SUB1 com o chamado. O static link na nova IRA para SUB1 aponta para IRA que é apontada para o segundo static link na static chain para a IRA para SUB3
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 31
Subprogramas aninhados
Avaliação do Método de Static Chain
– Problemas:
1. Uma referência não-local é lenta se o número de escopos entre a referência e a declaração da variável referenciada é grande
2. Código time-critical é difícil pois os custos de referência a variáveis não locais não são iguais e podem mudar com atualizações de código ou manutenções (corretivas ou adaptativas)
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Subprogramas aninhados
Técnica 2 - Displays
– Ideia: Colocar os static links em uma pilha separada, chamada de display. As entradas no display são ponteiros para IRA’s que têm as variáveis no ambiente de referência
– Representa referências como (display_offset, local_offset)
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 33
Displays (continuação)
Mecanismos de referência:
– Usar o display_offset para obter o ponteiro no display para o IRA com a variável
– Usar o local_offset para obter a variável dentro do IRA 11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Displays (continuação)
Manutenção do Display (assumindo que não
haja parâmetros que são subprogramas e sem
passagem de parâmetros por nome)
– Note que display_offset depende apenas de static depth do procedimento cujo IRA está sendo construído. É exatamente a static_depth do procedimento
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 35
Displays (continuação)
Para uma chamada ao procedimento P com
uma static_depth k:
a. Armazene, na nova IRA, uma cópia do ponteiro do display na posição k
b. Coloque o link para a IRA para P na posição k no display
Na saída, coloque o ponteiro do display salvo
(do IRA) de volta no display da posição k
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia
Displays (continuação)
Para ver que isso funciona:
– Faça Psd ser a static_depth de P, e Qsd ser a static_depth de Q
– Assuma que Q chama P – Há 3 casos possíveis: 1. Qsd = Psd
2. Qsd < Psd 3. Qsd > Psd
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 37
Subprogramas aninhados
O display pode ser mantido em registros –
acelera o acesso e manutenção
Comparando Static Chain e Display
1. Referências a locais
Sem diferença significativa
2. Referências a não-locais
Se um nível de diferença, são iguais Se mais “longe”, display é mais rápido
Display é melhor para códigos time-critical, pois todos os acesso a não-locais custam o mesmo
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc ia
Subprogramas aninhados
3. Procedure calls Para um ou dois níveis de profundidade, static chain é mais rápido
Caso contrário, display é mais rápido
4. Retorno de procedimentos
– Ambos têm tempo fixo, mas static chain é um pouco mais rápido
Faculdade de Ciências e Tecnologia Departamento de Matemática e Computação
Bacharelado em Ciência da Computação
Linguagens com Escopo
Dinâmico
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc iaImplementando Escopo Dinâmico
1.
Deep Access
– referências não-locais são
encontradas pela busca nas IRA na dynamic
chain
– Tamanho da cadeia não pode ser estaticamente determinada
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 41
Conteúdo da Pilha
para programa de
escopo dinâmico
11 /0 7 /2 0 1 7 g é ri o E d u a rd o G a rc iaImplementando Escopo Dinâmico
2. Acesso superficial – coloca coisas locais em
um lugar central
Métodos:
a. Uma pilha para cada nome de variável
b. Tabela central com uma entrada para cada nome de variável
11 /0 7 /2 0 1 7 R o g é ri o E d u a rd o G a rc ia 43
Usando Acesso Superficial para
implementar Escopo Dinâmico
Os nomes nas células da pilha indicam as unidades do programa em que as variáveis foram declaradas