Esta artigo é sobre a infraestrutura necessária para executar programas. Para a fase de execução de software, ver
tempo de execução.
Execução de Programa |
---|
Conceitos gerais |
---|
|
Tipos de código |
---|
|
Estratégia de compilação |
---|
|
Runtimes notáveis |
---|
|
Compiladores notáveis e toolchain |
---|
|
|
Um sistema de tempo de execução, também chamado de ambiente de tempo de execução, implementa principalmente partes de um modelo de execução. Isso não deve ser confundido com a fase do ciclo de vida de tempo de execução de um programa, durante o qual o sistema de tempo de execução está em operação. A maioria das linguagens de programação possui algum tipo de sistema de tempo de execução que fornece um ambiente no qual os programas são executados. Esse ambiente pode resolver vários problemas, incluindo o layout da memória do aplicativo, como o programa acessa variáveis, mecanismos para passar parâmetros entre procedimentos, fazer interface com o sistema operacional e outros. O compilador faz suposições dependendo do sistema de tempo de execução específico para gerar o código correto. Normalmente, o sistema de tempo de execução terá alguma responsabilidade pela configuração e gerenciamento da pilha e do heap e pode incluir recursos como coleta de lixo, encadeamentos ou outros recursos dinâmicos incorporados à linguagem de programação.[1]
Visão global
Toda linguagem de programação especifica um modelo de execução e muitos implementam pelo menos parte desse modelo em um sistema de tempo de execução. Uma possível definição de comportamento do sistema em tempo de execução é, entre outros, qualquer comportamento não diretamente atribuível ao próprio programa. Essa definição inclui, como parte do sistema de tempo de execução, coisas como colocar parâmetros na pilha antes de uma chamada de função, o comportamento da E/S de disco e a execução paralela de comportamentos relacionados.
Por essa definição, essencialmente, cada idioma possui um sistema de tempo de execução, incluindo linguagens compiladas, linguagens interpretadas e linguagens específicas de domínio incorporadas. Mesmo os modelos de execução autônomos da API, como o Pthreads, possuem um sistema de tempo de execução que é a implementação do comportamento do modelo de execução.
A maioria dos trabalhos acadêmicos sobre sistemas de tempo de execução concentra-se nos detalhes da implementação de sistemas de tempo de execução paralelos. Um exemplo notável de um sistema de tempo de execução paralelo é o de Cilk, um modelo popular de programação paralela.[2] Além disso, o kit de ferramentas de proto-runtime foi criado para simplificar a criação de sistemas de tempo de execução paralelos.[3]
Além do comportamento do modelo de execução, um sistema de tempo de execução também pode executar serviços de suporte, como verificação de tipo, depuração ou geração e otimização de código.[4]
O sistema de tempo de execução também é o gateway pelo qual um programa em execução interage com o ambiente de tempo de execução, que contém não apenas valores de estado acessíveis durante a execução do programa, mas também entidades ativas que podem ser interagidas durante a execução do programa, como unidades de disco e pessoas através de teclados. Por exemplo, variáveis de ambiente são recursos de muitos sistemas operacionais e fazem parte do ambiente de tempo de execução; um programa em execução pode acessá-los através do sistema de tempo de execução. Da mesma forma, dispositivos de hardware, como uma unidade de DVD, são entidades ativas com as quais um programa pode interagir por meio de um sistema de tempo de execução.
A aplicação única de um ambiente de tempo de execução (RTE) está dentro de um sistema operacional (OS) que só permite que a RTE para executar, ou seja, a partir de inicialização até que a energia para baixo o sistema operacional inteiro é dedicado a apenas a aplicação (s) em execução dentro desse RTE. Qualquer outro código que tente executar ou qualquer falha no(s) aplicativo(s) quebra o RTE que interrompe o sistema operacional, interrompendo todo o processamento e exigindo uma reinicialização. Se a inicialização for da memória somente leitura, será criado um sistema extremamente simples, simples e de missão única.
Exemplos
Como um exemplo simples de um sistema de tempo de execução básico, o sistema de tempo de execução da linguagem C é um conjunto particular de instruções inseridas na imagem executável pelo compilador. Entre outras coisas, essas instruções gerenciam a pilha do processador, criam espaço para variáveis locais e copiam parâmetros de chamada de função no topo da pilha. Geralmente, não há critérios claros para decidir qual comportamento de idioma é considerado dentro do sistema de tempo de execução versus qual comportamento faz parte do programa de origem. Para C, a configuração da pilha faz parte do sistema de tempo de execução, em oposição a parte da semântica de um programa individual, porque mantém uma invariante global que se mantém sobre todas as execuções. Esse comportamento sistemático implementa o modelo de execução da linguagem, em oposição à implementação da semântica do texto do programa específico que é traduzido diretamente em código que calcula os resultados.
Uma maneira de observar essa separação entre a semântica de um programa em particular e o ambiente de tempo de execução é compilar um programa em um arquivo de objeto contendo todas as funções versus compilar um programa inteiro para um binário executável. O arquivo objeto conterá apenas o código de montagem relevante para essas funções, enquanto o binário executável conterá código adicional usado para implementar o ambiente de tempo de execução. O arquivo objeto, por um lado, pode estar faltando informações do ambiente de tempo de execução que serão resolvidas por meio da vinculação. Por outro lado, o código no arquivo objeto ainda depende de suposições no sistema de tempo de execução; por exemplo, uma função pode ler parâmetros de um registro ou local de pilha específico, dependendo da convenção de chamada usada pelo ambiente de tempo de execução.
Outro exemplo é o caso de usar uma interface de programação de aplicativos (API) para interagir com um sistema de tempo de execução. As chamadas para essa API parecem as mesmas que as chamadas para uma biblioteca de software comum, no entanto, em algum momento durante a chamada, o modelo de execução é alterado. O sistema de execução implementa um modelo de execução diferente daquele da linguagem em que a biblioteca é escrita. Uma pessoa lendo o código de uma biblioteca normal seria capaz de entender o comportamento da biblioteca apenas conhecendo a linguagem em que a biblioteca foi escrita. No entanto, uma pessoa lendo o código da API que invoca um sistema de tempo de execução não seria capaz de entender o código. comportamento da chamada API apenas por conhecer a linguagem em que a chamada foi escrita. Em algum momento, através de algum mecanismo, o modelo de execução deixa de ser aquele da linguagem em que a chamada é escrita e passa a ser o modelo de execução implementado pela execução sistema. Por exemplo, a instrução trap é um método para alternar modelos de execução. Essa diferença é o que distingue um modelo de execução chamado por API, como encadeamentos POSIX, de uma biblioteca de software comum. Chamadas de threads POSIX e chamadas de biblioteca de software são chamadas por meio de uma API, mas o comportamento de threads POSIX não pode ser entendido em termos do idioma da chamada. Em vez disso, as chamadas de encadeamentos POSIX colocam em funcionamento um modelo de execução externa, que é implementado pelo sistema de tempo de execução de encadeamentos POSIX (esse sistema de tempo de execução é geralmente o kernel do sistema operacional).
Como um exemplo extremo, a própria CPU física pode ser vista como uma implementação do sistema de tempo de execução de uma linguagem assembly específica. Nessa visão, o modelo de execução é implementado pelos sistemas físicos de memória e CPU. Como analogia, os sistemas de tempo de execução para linguagens de nível superior são implementados usando algumas outras linguagens. Isso cria uma hierarquia de sistemas de tempo de execução, com a própria CPU - ou, na verdade, sua lógica na camada de microcódigo ou abaixo - atuando como o sistema de tempo de execução de nível mais baixo.
Características avançadas
Algumas linguagens compiladas ou interpretadas fornecem uma interface que permite que o código do aplicativo interaja diretamente com o sistema de tempo de execução. Um exemplo é a classe Thread
na linguagem Java. A classe permite que o código (que é animado por um thread) faça coisas como iniciar e parar outros threads. Normalmente, os principais aspectos do comportamento de uma linguagem, como o agendamento de tarefas e o gerenciamento de recursos, não são acessíveis dessa maneira.
Comportamentos de nível superior implementados por um sistema de tempo de execução podem incluir tarefas como desenhar texto na tela ou fazer uma conexão com a Internet. Geralmente, os sistemas operacionais fornecem esses tipos de comportamento também e, quando disponíveis, o sistema de tempo de execução é implementado como uma camada de abstração que traduz a invocação do sistema de tempo de execução em uma invocação do sistema operacional. Isso oculta a complexidade ou as variações nos serviços oferecidos por diferentes sistemas operacionais. Isso também implica que o próprio kernel do sistema operacional pode ser visto como um sistema de tempo de execução e que o conjunto de chamadas do SO que invocam os comportamentos do sistema operacional pode ser visto como interações com um sistema de tempo de execução.
No limite, o sistema de tempo de execução pode fornecer serviços como uma máquina de código P ou máquina virtual, que ocultam até mesmo o conjunto de instruções do processador. Essa é a abordagem seguida por muitas linguagens interpretadas, como AWK, e algumas linguagens como Java, que devem ser compiladas em algum código de representação intermediário independente de máquina (como bytecode). Esse arranjo simplifica a tarefa de implementação da linguagem e sua adaptação a diferentes máquinas e melhora a eficiência de recursos de linguagem sofisticados, como a reflexão. Também permite que o mesmo programa seja executado em qualquer máquina sem uma etapa de recompilação explícita, uma característica que se tornou muito importante desde a proliferação da World Wide Web. Para acelerar a execução, alguns sistemas de tempo de execução apresentam compilação just-in-time para código de máquina.
Um aspecto moderno dos sistemas de tempo de execução são os comportamentos de execução paralela, como os comportamentos exibidos pelas construções mutex em construções Pthreads e de seção paralela no OpenMP. Um sistema de tempo de execução com tais comportamentos paralelos de execução pode ser modularizado de acordo com a abordagem de proto-runtime.
História
Exemplos iniciais notáveis de sistemas de tempo de execução são os interpretadores de BASIC e Lisp. Esses ambientes também incluíam um coletor de lixo. Forth é um dos primeiros exemplos de uma linguagem projetada para ser compilada em código de representação intermediária; seu sistema de tempo de execução era uma máquina virtual que interpretava esse código. Outro exemplo popular, se teórico, é o computador MIX de Donald Knuth.
Em C e em linguagens posteriores que suportavam a alocação de memória dinâmica, o sistema de tempo de execução também incluía uma biblioteca que gerenciava o conjunto de memórias do programa.
Nas linguagens de programação orientadas a objetos, o sistema de tempo de execução também era frequentemente responsável pela verificação de tipos dinâmicos e pela resolução de referências de métodos.
Ver também
Referências