UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL
INSTITUTO DE INFORMÁTICA
CURSO DE PÓS-GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO
 
 
 
Máquinas para Linguagens OO
 
por
 
 
SÉRGIO AKIRA ITO
 
Novembro/1998
 
 
Avaliação I
 
Disciplina:
 
Arquiteturas Especiais de Computadores
 
 
 
UFRGS - II - CPGCC
Caixa Postal 15064 - CEP 91509-900
Porto Alegre - RS - BRASIL
Telefone: (051) 316-6155
Fax: (051) 319-1776
Email: cpgcc@inf.ufrgs.br

 

 



 
Índice
 

Resumo *

1. Introdução *
2. Orientação a objetos e IA *
3. Arquiteturas Abordadas *

3.1 SOAR (Smalltalk On A RISC) *

3.1.1 Checagem de tipos *
3.1.2 Interpretação *
3.1.3 Chamadas de procedimento eficientes *
3.1.4 Armazenagem de objetos *
3.2 FAIM-1 * 3.2.1 A Linguagem OIL *
3.2.2 Estrutura do Hardware *
3.3 COM (Caltech Object Machine) * 3.3.1 Novos conceitos incorporados na Arquitetura *
3.3.2 A máquina de Objetos *
3.4 Sword32 * 3.4.1 Características da Arquitetura * 3.5 Hitachi AI32 * 3.5.1 Características da arquitetura * 4. Discussão e Conclusão *
5. Bibliografia *

 



 
 
Lista de Figuras
 

Figura 1 - Os 2 tipos de dados suportados no SOAR *
Figura 2 - Instruções SOAR *
Figura 3 - Chamadas de subrotinas no SOAR *
Figura 4 - O apontador contém o endereço do objeto alvo *
Figura 5 - Topologia básica (mesh hexagonal) *
Figura 6 - Organização hierárquica do FAIM-1 *
Figura 7 - Estrutura do Hectogon *
Figura 8 - Decodificação de instruções *
Figura 9 - Formato de Instruções da COM *
Figura 10 - Diagrama da Máquina COM *
Figura 11 - Representação dos dados *

 



 

 

Lista de Tabelas

 

Quadro 1 - Máquinas para processamento de Linguagens OO. *
Quadro 2 - Sumário das Máquinas OO *

 


 
 
Máquinas para Linguagens OO

 

Resumo

Desde o lançamento do projeto de computadores de quinta geração no Japão e outros similares nos Estados Unidos e Europa, têm se questionado o paradigma de computação utilizado e o modelo das máquinas existentes. Aplicações de Inteligência Artificial demandam por formas eficientes de representar e manipular o conhecimento, principalmente através de computação simbólica.

A orientação a objetos fornece algumas características interessantes ao desenvolvimento de aplicações de IA, principalmente a hierarquia de classes, abstração e encapsulamento de dados, troca de mensagens e também facilidade de manutenção de programas. No entanto, linguagens como Smalltalk eram restritas a poucas plataformas de hardware na década de 80, devido ao limitado poder de processamento da maioria das máquinas existentes.

Neste contexto, este trabalho tem o objetivo de apresentar algumas máquinas utilizadas no processamento de aplicações escritas em linguagens orientadas a objetos, e que contribuíram de alguma forma à incorporação de novos conceitos ou estruturas de hardware para melhorar o desempenho de aplicações orientadas a objetos, sobretudo àquelas destinadas à IA.
 

Palavras-chave

Arquiteturas especiais de computadores, Orientação a objetos, IA
 
 


1. Introdução
 

Aplicações numéricas convencionais podem ser expressas através de algoritmos que são executados de maneira eficiente e com uma boa estimativa de desempenho nos computadores comercialmente disponíveis. Este fato sem dúvida está ligado à natureza da aplicação, às técnicas e ferramentas utilizadas para resolver os problemas (algoritmos, linguagens de programação, compiladores) e também à plataforma de hardware que se adapta bem à esse tipo de tarefa.

Entretanto, existem aplicações cujos requisitos de tratamento contrastam com a maioria dos problemas numéricos, expondo a deficiência das estruturas existentes nos computadores atuais para realizá-las de forma eficiente. As aplicações de IA são um bom exemplo, pois são caracterizadas pelo processamento simbólico, computações não determinísticas, execução dinâmica, grande potencial para processamento paralelo e distribuído, gerenciamento de conhecimento, características evolutivas dos sistemas.

As Linguagens de programação imperativas convencionais são inadequadas para programação de IA devido à sua ineficiência no processamento simbólico e de padrões e a inaceitável complexidade de programação. Linguagens específicas para IA são fortemente declarativas, possuem construções de suporte ao processamento simbólico, representação de informação através de listas, uso de recursão como o único mecanismo de controle. Na década de 80 os paradigmas de linguagens mais utilizados em IA foram linguagens funcionais, lógicas e orientadas a objetos, com o desenvolvimento de algumas linguagens híbridas. Estas linguagens se diferenciam pelo poder de expressão, facilidade de implementação, habilidade de expressar paralelismo e de incluir conhecimento heurístico [WAH 87].

A taxonomia de máquinas apresentada em [HWA 87], classifica as arquiteturas de computadores para IA em 3 grandes classes: máquinas baseadas em linguagens, máquinas baseadas no conhecimento e máquinas de interface inteligente. Ainda segundo esta taxonomia, o conceito de objetos pode ser usado para expressar o conhecimento, enquadrando as máquinas baseadas em objetos na classe de arquiteturas baseadas na representação e manipulação do conhecimento.

A programação orientada a objetos é baseada no encapsulamento dos dados, juntamente com os métodos que os manipulam, formando uma entidade uniforme denominada objeto, permitindo ainda agrupar entidades logicamente relacionadas em classes. Algumas das principais máquinas para processamento de linguagens orientadas a objetos estão relacionadas no quadro 1.

Atualmente, linguagens orientadas a objetos são utilizadas em diversas áreas da computação, não se restringindo somente à Inteligência Artificial. Entretanto, muitas das linguagens ditas orientadas a objetos como C++, agregam características existentes em linguagens baseadas em procedimentos como C e Pascal, e excluíram muitos dos conceitos encontrados em linguagens como Smalltalk, na qual a programação é totalmente baseada em objetos. Esta tendência permite que essas linguagens consigam um melhor desempenho nas arquiteturas de computadores atuais, em detrimento de muitas das características interessantes da orientação a objetos.

 
 

Nome e Empresa Arquitetura e Linguagem Paradigma de Execução
 

iAPX 432, Intel Corp.

 

Multiprocessador baseado em barramento compartilhado; para Ada e linguagens orientadas a objeto puras

 

Modelo stack e também baseado em 3 endereços

SOAR*, UC Berkeley Monoprocessador para Smalltalk Avaliação de expressões baseado em registradores com checagem de tipos usando tags
FAIM-1*, Fairchild, Palo Alto, Calif. Multiprocessador com interconexão mesh hexagonal; executa a linguagem OIL Modelo stack com hardware paralelo dedicado à checagem de tags
Dragon, Xerox, Palo Alto, Calif. Multiprocessador com barramento compartilhado; suporta Cedar, Interlisp e Smalltalk Executa instruções stack e memória-memória.
Sword32*, Univ. de Tokyo Sistema multiprocessador baseado em barramento compartilhado; para execução de Smalltalk Modelo stack emulador de máquina virtual
COM*, California Institute of Technology Monoprocessador para Smalltalk Instruções de três endereços
AI-32*, Hitachi, Japan processador escravo microprogramado que suporta Smalltalk e outras linguagens. Modelo stack com tags para operandos.
PicoJava, Sun Microsystems, Inc. Microprocessador que suporta bytecodes da máquina virtual linguagem Java Modelo stack com opcodes específicos as tipos de dados; utiliza folding de instruções.
                                                                      * abordados neste trabalho
Quadro 1 - Máquinas para processamento de Linguagens OO.
 

Entretanto, como citado acima algumas arquiteturas foram propostas para o processamento eficiente de linguagens orientadas a objetos, sobretudo àquelas destinadas a aplicações de IA na década de 80. Portanto, este trabalho têm o objetivo de discutir as principais estruturas propostas para elevar o desempenho de máquinas para linguagens OO através da apresentação de algumas dessas arquiteturas.

O texto esta organizado da segundo a seguinte estrutura: a seção 2 apresenta a orientação em perspectiva à inteligência artificial, a seção 3 relaciona algumas máquinas para o processamento de programas escritos em linguagens baseadas em objetos e seção 5 encerra o texto apresentando as conclusões.
 



 

2. Orientação a objetos e IA

A inteligência artificial foi vista como uma área de pesquisa durante décadas. Porém, aplicações de IA comerciais começaram a ser disponibilizadas nos anos 80, sobretudo sistemas especialistas e de processamento de linguagem natural. Este último com menos sucesso devido à sua extrema dificuldade. Segundo Tello em [TEL 89], as oito áreas da IA no final da década de 80 eram:
 

Uma das principais características das aplicações de IA é o chamado processamento simbólico. O termo procura enfatizar a diferença de requisitos de processamento entre aplicações de IA e as técnicas de computação numérica e dados convencionais. O processamento simbólico se caracteriza pela maior similaridade ao processo de pensamento humano, pois é uma forma de representar coisas do mundo e uma maneira de manipulá-los eficientemente.

Muitas aplicações de IA se caracterizam por serem sistemas baseados no conhecimento. Portanto, há uma grande importância em conceber formas adequadas de representar o conhecimento. Outro componente importante nestes sistemas é a máquina de inferência, que consiste em um programa que torna "executável" o conhecimento armazenado, fazendo com que os dados tenham características ativas, ao invés de dados passivos.

Diversos paradigmas e linguagens foram propostas para representar e manipular adequadamente o conhecimento em aplicações de IA. Dentre os paradigmas propostos, podemos citar o lógico, funcional e também o orientado a objetos. Em função de diversas linguagens ditas orientadas a objetos (C++, Java), atualmente sejam utilizadas para o desenvolvimento de aplicações convencionais, pode-se questionar a sua adequabilidade a problemas de IA. Entretanto, linguagens como Smalltalk (puramente orientada a objetos) ou OIL (mescla de paradigmas) apresentam muitas diferenças com relação a linguagens como C++, e eram consideradas mais adequadas para implementar aplicações de IA.

Características interessantes de linguagens como Smalltalk são a modularidade do programa, abstração de dados e classificação hierárquica dos objetos. O conceito de herança é útil na representação do conhecimento quando há uma implícita hierarquia de classes e para evitar replicação de informações. Uma discussão mais detalhada sobre as diferenças entre a programação em IA e a programação convencional, podem ser encontrados em [TEL 89] e [RAM 87]. Um exemplo de sistemas de IA que utilizam o conceito de orientação a objetos são aqueles cuja representação do conhecimento se baseia em frames [RAM 87].

Algumas razões para utilizar a orientação a objetos na implementação de máquinas de inferência são: eliminação de código redundante, evolução facilitada sem grande esforço de re-escrita de código, e permitir múltiplas instâncias da máquina de inferência sendo executadas ao mesmo tempo. O projeto e implementação de uma máquina de inferência utilizando orientação a objetos pode ser encontrada em [TEL 89].



 
 

3. Arquiteturas Abordadas

 Durante a década de 80 diversos projetos surgiram com o intuito de conceber máquinas que executassem eficientemente linguagens orientadas a objetos, dadas as vantagens que poderiam ser alcançadas mediante a utilização das mesmas. O quadro 1 relaciona as principais máquinas que agregavam estruturas para elevar o desempenho da execução de programas escritos em linguagens orientadas a objetos, sobretudo Smaltalk.

Entretanto, as máquinas abordadas neste trabalho serão basicamente: SOAR de Berkeley, FAIM-1 da Fairchild, Sword32 da Universidade de Tokyo, COM da Caltech e AI32 da Hitachi. Estas máquinas são apresentadas sucintamente dando ênfase nas estruturas de hardware que se destacam pelo objetivo de ganhar desempenho, dadas as características das linguagens OO. O iAPX 432 e a máquina Dragon da Xerox não serão abordados, dada à dificuldade de reunir informações suficientes para inclui-las a tempo. Quanto ao processador PicoJava da Sun informações mais detalhadas podem ser encontradas em [ITO 98].
 

3.1 SOAR (Smalltalk On A RISC)

A linguagem Smalltalk-80 é orientada a objetos, dinâmica e é definida em termos de uma máquina virtual que executa instruções de pilha denominados bytecodes. A linguagem Smalltalk foi concebida num esforço de obter um ambiente de programação altamente produtivo, oferecendo características interessantes como:

 As técnicas de implementação da máquina virtual determinavam a eficiência na execução dos programas Smalltalk-80, pois em geral era necessário um hardware especial ou uma máquina de alto desempenho para sobrepujar o overhead existente entre a máquina virtual e a máquina nativa. Em adição à estas características, o baixo desempenho de Smalltalk-80 era agravado pelas seguintes razões [PAT 86]: O objetivo do projeto SOAR na universidade de Berkeley foi produzir um sistema de alto desempenho para execução da linguagem Smalltalk-80. Um dos pontos chaves desse projeto era a concepção de um processador RISC estendido para dar suporte à Smalltalk. O processador foi projetado em conjunto com o restante do sistema, e juntos permitiam obter resultados significativamente melhores que implementações convencionais da linguagem [UNG 87].

No projeto SOAR uma das razões para o ganho de desempenho era a compilação de bytecodes Smalltalk para o conjunto de instruções SOAR. Portanto, o compilador atuava como um tradutor de bytecodes de arquitetura stack para instruções de load/store e registrador-registrador do estilo RISC.


3.1.1 Checagem de tipos

Como comentado acima, em operações Smalltalk os tipos dos operandos podem variar, portando devem ser checados em tempo de execução. As implementações existentes até então, usavam microcódigo ou software para checar tipos antes de realizar operações como adição penalizando o desempenho obtido. Em geral, tags podem ser checados pelo hardware para descobrir erros em um programa. Entretanto, no projeto SOAR, os tags tinham a finalidade de elevar o desempenho através da previsão de tipos, permitindo iniciar uma operação e checar o tag para confirmar a previsão de forma simultânea.

 

 

Figura 1 - Os 2 tipos de dados suportados no SOAR
 

No caso trivial, os dois operandos são do tipo inteiro e o resultado correto esta disponível após um ciclo de relógio. Porém, quando algum dos operandos não é do tipo inteiro, o SOAR aborta a operação e provoca um desvio para rotina que efetuará as computações adequadas para aquele tipo de dado. Como pode ser observado na figura 1, os dados no SOAR possuem um bit (tag) indicando se o dado é do tipo inteiro, ou um apontador para a estrutura de dado contendo a informação.

As instruções de desvio condicional também foram influenciados pela checagem dinâmica de tipos exigida por Smalltalk. Basicamente há duas formas clássicas de se implementar desvios condicionais: instruções de comparação explícitas ou códigos de condição. Esta última técnica permite economizar uma instrução quando a condição depende da comparação do resultado da operação anterior e zero. Entretanto, não é possível aplicá-la desde que em Smalltalk o tipo do resultado pode variar. Desde que 32 bits não seriam suficientes para codificar uma instrução do tipo compare-and-brach, SOAR utiliza uma instrução do tipo compare-and-skip.



 

3.1.2 Interpretação

Como o sistema Smalltalk-80 ser baseado em uma máquina virtual de arquitetura estilo stack, cada instrução compreende de um a três bytes, correspondendo em geral a cada token do programa fonte. Esta abordagem apresenta algumas vantagens como simplificação do compilador e depurador, e portabilidade alcançada pela implementação de emuladores. Entretanto, a decodificação requer uma estrutura de hardware adicional e toma uma quantidade de tempo maior, e instruções de alto nível requerem múltiplos ciclos para executar e exigem uma unidade de controle dedicada.

A filosofia RISC busca um conjunto de instruções ortogonal, razão pelo qual os projetistas do SOAR abandonaram a abordagem baseada em bytecodes da máquina virtual. Portanto, cada instrução SOAR ocupa 32 bits e a maioria toma um ciclo de relógio para executar, com exceção das instruções de load/store e return que tomam 2 ciclos.

 

Figura 2 - Instruções SOAR

 
Uma arquitetura que utiliza tags e não possui microcódigo exige que o compilador mescle instruções de inspeção e manipulação dos tags e as demais instruções. Cada instrução SOAR possui um bit que habilita ou desabilita a checagem dos tags (indicado por % no assembly). No modo "untagged" os bits de tag são tratados como dados, permitindo que programas escritos em linguagens convencionais como C possam executar no SOAR. Os dois formatos de instrução do SOAR podem ser observados na figura 2.
 

3.1.3 Chamadas de procedimento eficientes

Smalltalk explora ao extremo a modularidade dos programas através da utilização de subrotinas. Portanto, os programas escritos em Smalltalk possuem uma alta taxa de chamadas à subrotinas. Além disso, estas chamadas são mais complexas, por duas razões:

SOAR explora o fato de que as subrotinas Smalltalk em geral utilizam um número menor de variáveis locais e argumentos, organizando seus registradores em janelas de 8 registradores, e evitando a necessidade do armazenamento do seu conteúdo à cada chamada [PAT 87].
 

 

Figura 3 - Chamadas de subrotinas no SOAR
 

O banco de registradores do SOAR possui 32 registradores. Quando sua capacidade é excedida, o SOAR invoca uma rotina em software para salvar o conteúdo dos registradores em memória. Entretanto, para acelerar esse processo existem instruções especiais que podem transferir 8 registradores em apenas nove ciclos (um ciclo de busca de instrução e 8 de acesso a dados). O SOAR também pode inicializar todos os registradores de uma janela através da instrução return, que realiza esta tarefa em paralelo com o cálculo do endereço de retorno, deixando os registradores inicializados para a próxima chamada.

Uma terceira técnica para reduzir o overhead associado às chamadas de subrotinas é armazenar o endereço destino obtido na consulta da tabela de endereços no próprio fluxo de instruções, dispensando novas consultas (Figura 3). Porém, esta técnica não permite o uso de código reentrante e o chaveamento de processos deve ser evitado. As instruções SOAR de call e jump possuem um bit para especificar se é seguro realizar o chaveamento de processo, permitindo o uso de interrupção por software necessário para implementação de sistemas operacionais.
 

3.1.4 Armazenagem de objetos

Em Smalltalk-80, os objetos são pequenos (56 bytes para o SOAR) e voláteis. O gerenciamento do armazenamento dessas estruturas de dados são gerenciadas através do uso de três técnicas, que estão descritas sucintamente a seguir.

 
 Figura 4 - O apontador contém o endereço do objeto alvo
 
 
A técnica chamada Generation Scavening era utilizada desalocar memória eficientemente. Esta técnica é baseada na observação de gerações de objetos.  

3.2 FAIM-1

O FAIM-1 era um sistema destinado ao processamento simbólico de aplicações de inteligência artificial. O objetivo principal deste projeto era obter uma arquitetura escalável à uma configuração capaz de obter um desempenho de duas a três ordens de magnitude sobre as arquiteturas convencionais. Considerou-se ainda neste projeto, fatores como programabilidade, desempenho, extensibilidade, tolerância a falhas e um custo compatível com a tecnologia existente.

A arquitetura do FAIM-1 foi concebida para ser uma máquina de alto desempenho para a avaliação de programas escritos na linguagem concorrente OIL (Our Intermediate Language), e suportar um estilo de multiprocessamento distribuído embutido no sistema operacional [HON 87].
 

3.2.1 A Linguagem OIL
 

OIL é uma linguagem de programação de alto nível, concorrente e de natureza simbólica. O projeto desta linguagem foi influenciada pelas diversas linguagens existentes utilizadas na implementação de programas de IA. Basicamente, são três os estilos de programação suportados por OIL: orientado a objetos, lógica e funcional. Seus projetistas argumentavam que complexas aplicações de IA, poderiam requerer os três estilos de programação.

Um programa OIL é constituído de um conjunto de objetos que se comunicam através da troca de mensagens. Objetos consistem de informações de estado (variáveis) e diversos ports usados para troca de mensagens (recebidos segundo uma política de fila). Um comportamento é associado a cada port, descrevendo a resposta do objeto a uma determinada mensagem. Objetos atômicos de OIL podem ser dos tipos logical (escritos de forma declarativa semelhante a algumas versões paralelas do Prolog) e procedural (descritos de forma imperativa como alguns dialetos de Lisp).

Para suportar chamadas de rotinas de forma distribuída e sincronização de processos paralelos, subconjuntos de ports podem ser agrupados em entries. Quando todos os ports de um entry possuem uma mensagem, então o comportamento associado a este entry é dito fireable. Os componentes lógicos são usados para expressar buscas não determinísticas dirigida por padrões, enquanto componentes funcionais são usados para especificação de algoritmos seqüenciais, exibindo um comportamento determinístico.

O funcionamento de um componente lógico é baseado na manipulação de uma cadeia de metas, e a produção de uma lista de soluções (em geral, diversas soluções por meta). Ao contrário, um componente funcional aceita uma seqüência de chamadas à funções e produz uma lista de mensagens (geralmente, uma resposta para cada chamada de função).

Ao programador são fornecidos flexíveis e poderosos recursos de programação, como os chamados pragmas, que podem descrever o comportamento esperado de um fragmento de código em tempo de execução, permitindo por exemplo uma melhor alocação de recursos e consequentemente afetar o desempenho do programa. Na realidade os pragmas podem ser utilizados para 3 finalidades: estimar a probabilidade de um desvio ser tomado em uma decisão, estimar o tamanho de estruturas de dados dinâmicas e tomar decisões sobre a alocação de recursos.

Programas escritos em OIL são compilados em código objeto em uma máquina Lisp hospedeira. Este código é depois enviado para execução no FAIM-1. Decisões de como proceder a alocação de cada objeto é realizado durante a fase de compilação denominada alocação de recursos. Isto permite balancear o hardware de execução paralela e o custo de comunicação em tempo de execução.
 

3.2.2 Estrutura do Hardware

A arquitetura do FAIM-1 consiste de diversos elementos de processamento independentes, chamados Hectogons, interconectados por uma mesh hexagonal. Portanto, os elementos de processamento podem se comunicar diretamente com até 6 elementos adjacentes.

 

 
Figura 5 - Topologia básica (mesh hexagonal)
 

A figura 5 ilustra a topologia básica, na qual as linhas pontilhadas completam as conexões. Este tipo de interconexão resulta em um simples algoritmo de roteamento. As conexões "extra-hexágono" permitem a comunicação com dispositivos de I/O ou com outros hexágonos.

 

 

Figura 6 - Organização hierárquica do FAIM-1

 

 
Figura 7 - Estrutura do Hectogon

 
O tamanho de cada hexágono é determinado pelo número de processadores contido em cada lado do hexágono. A escalabilidade pode ainda ser alcançada organizando o FAIM-1 de forma hierárquica, através de múltiplos hexágonos, como demonstra a figura 6, onde 133 elementos de processamento estão conectados.

Cada Hectogon pode ser visto como um elemento de processamento homogêneo da arquitetura do FAIM-1, que se caracteriza por ser um sistema multiprocessador de memória compartilhada, altamente concorrente e de média granulosidade. Internamente os hectogons são compostos de diversos subsistemas, como pode ser observado na figura 7.

O desempenho do sistema, depende da taxa de processadores ativos, a eficiência da comunicação, do total de processadores e também do desempenho de cada processador. Internamente cada hectogon é composto por:
 

 
O datapath é de 28 bits, dos quais 8 são reservados para tags que são processados em paralelo por uma unidade de hardware específica para manipulação de tags. O processador também possui uma ULA de 20 bits que suporta operações lógicas, aritméticas sobre inteiros e instruções de deslocamento. Apesar de ser baseado no conceito de operações do tipo stack, o processador de avaliação incorpora algumas características da arquitetura RISC, como modelo load/store, registradores de propósito geral e execução da maioria das instruções em apenas um ciclo. Quando ocorre a troca de contexto, o processador de chaveamento também troca o conjunto de registradores ativos, examina a lista de processos para determinar a próxima tarefa e move este contexto do bloco de controle de processos para o conjunto de registradores inativos, e atualiza os flags de validação de contexto. O envio de mensagens é iniciado pelo processador de avaliação que gera o cabeçalho da mensagem e um apontador para o corpo da mensagem, armazenando esta informação na SRAM. O Post Office extrai a mensagem e envia para rede de comunicação. A recepção da mensagem é feita através do seu armazenamento na SRAM e a notificação de nova mensagem ao processador de avaliação.

A maior porção do paralelismo explorado pelo FAIM-1 é tipo OU. O paralelismo do tipo E só é explorado quando suas cláusulas são independentes e as checagens de consistência complexas não são necessárias. A técnica de balanceamento de carga é predominantemente estático, com limitado suporte ao balanceamento dinâmico devido ao seu overhead [HWA 89].
 

3.3 COM (Caltech Object Machine)

O projeto da máquina COM tinha o objetivo de obter alto desempenho na execução das linguagens orientadas a objetos que utilizam o conceito de late biding. Seus projetistas utilizavam principalmente duas técnicas para alcançar esta meta: alocação de contexto eficiente e um buffer de tradução para instruções (translation lookaside buffer). A proposta destas estruturas de hardware era baseada na necessidade de novos mecanismos a serem incorporados aos processadores von Newmann convencionais, altamente penalizados na execução de linguagens orientadas a objetos. Diversos outros projetos, como por exemplo das máquinas Xerox Dorado e SOAR, inspiraram o projeto da COM [KAJ 85].
 

3.3.1 Novos conceitos incorporados na Arquitetura

Os projetistas da máquina COM utilizaram o conceito de "instruções abstratas" como método para interpretar instruções de máquina. Neste esquema, o opcode e a classe determinam qual instrução deve ser executada, dando ainda a informação se a instrução é primitiva ou definida.

Entretanto, a decodificação de uma instrução é muito mais complexa e lenta se realizada por software. Entretanto, o mecanismo ITLB (Instruction Translation Lookaside Buffer) pode diminuir o overhead da utilização desta técnica. Cada entrada na ITLB contem 3 campos: uma chave composta pelo opcode e um conjunto de classes; um bit que indica se o método é primitivo ou definido; e um campo que indica o resultado de uma unidade funcional ou uma porção de código, dependendo do bit descritor do método. A figura 8 apresenta a estrutura do ITLB.
 

 

 Figura 8 - Decodificação de instruções
 

Portanto a decodificação de instruções era realizada em 3 etapas. Primeiro o opcode e a classe de cada operando constituíam uma chave, através do qual uma memória associativa realizava a busca da entrada correspondente. Caso tal chave fosse encontrada a decodificação era imediata, caso contrário era utilizado a técnica padrão de "method lookup", comum na execução de programas escritos em Smalltalk.

Os projetistas da máquina COM também propuseram um método para eliminar o conhecido problema de objetos pequenos, que leva ao dilema de optar por um número de maior segmentos ou por segmentos maiores. Utilizando a técnica o endereço por ponto flutuante, na qual cada endereço possui um "expoente" e uma "mantissa" onde exp = é lg manù . O expoente codifica na realidade o tamanho do offset representado pela mantissa.

A máquina COM utiliza uma memória provida de tags de 4 bits usados para identificar os tipos primitivos: unintialized , small integer, floating point, atom, instruction and object pointer. Um tag de 16 bits é armazenado no contexto para indicar a classe de um objeto que será utilizado no processo de method lookup.

O mecanismo de alocação de contextos utiliza o tamanho fixo de 32 palavras para os contextos. Métodos que necessitem mais de 32 palavras podem alocar espaço adicional fora da pilha. Entretanto, como em programas orientados a objetos em geral os métodos são menos exigentes quanto ao tamanho dos contextos, esta restrição é justificada. Uma cache de contextos associativa por conjuntos é utilizada para acesso eficiente aos contextos. Outro mecanismo interessante é o gerenciamento da cache, que começa a mover os contextos à medida que a cache vai atingindo seu limite máximo e copia-os de volta quando metade da cache está livre. Este mecanismo possui função semelhante às janelas de registradores adotadas no projeto SOAR.
 

3.3.2 A máquina de Objetos

A máquina COM incorporava não somente as características destacadas na seção 3.3.1, mas também uma série de características bem conhecidas para suportar a execução eficiente de programas orientados a objetos. A memória da máquina COM possuía tags para identificar os diferentes tipos de objetos. A velocidade de processamento era atribuída principalmente ao suporte em hardware para o processo de method lookup e para permitir acesso e alocação de contextos.

O mecanismo de endereçamento na máquina COM era bem sofisticado, possuindo 3 espaços de endereçamento: espaço virtual (espaço de endereçamento local a um grupo de processos), espaço absoluto (espaço de nomes global, onde existe um identificador único para cada objeto), e espaço físico (endereçamento em dispositivos físicos). A resolução de nomes é feita através da tradução do espaço virtual para o espaço absoluto. A alocação de recursos era tratada através da tradução do espaço absoluto para o espaço físico. Processos como o garbage collector utilizam o espaço de endereçamento absoluto. Completo suporte em hardware para tradução dos 3 tipos de endereçamento estão disponíveis na máquina COM, bem como um ATLB (Address Translation Lookaside Buffer).

 

 
Figura 9 - Formato de Instruções da COM

 
O conjunto de instruções da máquina COM foi projetada para ser regular e facilitar a introdução de execução pipeline. Todas as instruções são de 32 bits de tamanho e contém de zero ou três operandos. Portanto, uma instrução de 3 operandos pode substituir em torno de 2 instruções do tipo stack da máquina virtual Smalltalk-80. Os formatos das palavras de instrução são apresentadas na figura 9. As instruções podem ser classificadas em: aritméticas, múltipla precisão, lógica e de acesso a bits, comparações, movimento de dados, acesso a tags, de controle (jumps).
 

 

Figura 10 - Diagrama da Máquina COM
 

Como pode ser observado na figura 10, a interpretação das instruções são realizadas em 5 etapas:

  1. O apontador de instrução é utilizado para buscar a próxima instrução na cache.
  2. Os operandos e seus tags são buscados. Os operandos são obtidos da cache de contexto ou do gerador de constantes.
  3. O opcode e os tipos de operandos são utilizados para determinar se a instrução é primitiva ou um método. Apenas neste estágio uma outra instrução estará sendo buscada, caracterizando o pipeline, pois não é possível realizar escritas e leituras simultâneas à cache de contexto.
  4. Nesta fase as operações primitivas são executadas.
  5. O resultado da operação é armazenada e o IP é incrementado.
3.4 Sword32

O Sword32 foi um microprocessador de 32 bits com 4K palavras de memória para microinstruções, uma grande pilha e mecanismos para emular bytecodes Smalltalk eficientemente. A motivação para concepção deste processador, derivou de estudos sobre a viabilidade da utilização de Smalltalk como linguagem principal de desenvolvimento de sistemas no núcleo de pesquisas do departamento de Engenharia Matemática da Universidade de Tokyo. Através desses estudos comprovou-se que além de Smalltalk apresentar diversas características de interesse, esta linguagem sofria de problemas de desempenho, limitando sua utilização à poucas plataformas de hardware [SUZ 84].
 

3.4.1 Características da Arquitetura

Para fornecer um ambiente com um bom tempo resposta à interação e superar o problema de limitação de memória, foi usado uma técnica de garbage collection chamada transaction. Não há suporte especial em hardware para efetuar este processo, a não ser o fato de que o programa foi implementado na maioria em micro-código.

A referência à objetos em geral é feita através de apontadores, cuja implementação pode variar de sistema para sistema. Por exemplo, o SOAR utiliza apontadores com o endereço absoluto para os objetos, o Dolphin (máquina da Xerox) utiliza índices para uma tabela contendo o endereço dos objetos e o Sword32 adotou uma solução intermediária, fazendo referência aos objetos através do endereço efetivo dentro de uma tabela de endereços para objetos.

 

 Figura 11 - Representação dos dados
 

Os inteiros no Sword32 tem 31 bits devido ao uso de um tag que o diferencia dos apontadores como pode ser observado na figura 11. A codificação direta do valor inteiro permite acelerar o processamento, pois não é necessário efetuar a consulta à tabela de objetos. O acesso à memória pode ser feita através de instruções de load/store de 8 ou 32 bits.

Nos sistemas Smalltalk em geral se utiliza um sistema de cache para acelerar o processo de method lookup. O Sword32 utiliza uma técnica chamada method cache com algumas modificações. O método original consiste de uma tabela hash global, na qual as chaves são o identificador da mensagem e a classe do receptor, e os valores são o índice de um método ou primitiva. No Sword32 os valores contidos na tabela são o endereços do primeiro bytecode (método) ou do microcódigo (primitiva), permitindo uma aceleração da execução. Um tag é utilizado no bit mais significativo da palavra de endereço da instrução para indicar se corresponde à um bytecode (valor 0) ou uma microinstrução (valor 1).

Para permitir chamadas rápidas à métodos, o Sword32 provê amplo suporte à troca de contexto através de uma grande pilha dentro do chip (128 palavras) e 32 registradores de propósito geral. No Sword32 até 8 contextos podem estar armazenados simultaneamente na pilha.

A parte operativa do Sword32 foi projetada de maneira simples e possui apenas 2 estágios de pipeline (busca de instrução e acesso a operandos/operação/write-back). Nenhum suporte especial em hardware está disponível para a busca de instruções, sendo de responsabilidade do microprogramador garantir que a busca não ocorra enquanto uma instrução de acesso à memória esteja sendo realizada.
 

3.5 Hitachi AI32

O ganho de desempenho proposto no projeto do Hitachi AI32 originava-se da otimização de instruções complexas e freqüentes como checagem dinâmica de tipos, chamadas à subrotinas e o gerenciamento de memória. Para melhorar o desempenho destas operações eram utilizados grandes bancos de registradores intra-chip, grande capacidade em EPROM para armazenar microinstruções, engenhosos mecanismos de despacho de instruções e manipulação de tags.

O objetivo era obter um microprocessador capaz de executar eficientemente programas escritos em linguagens orientadas a objetos e outras linguagens destinadas à IA, através do uso de microprogramas adequados. O projeto do AI32 pela Hitachi foi influenciado pelo Sword32 desenvolvido pela Universidade de Tokyo. Basicamente, as diferenças incorporadas no AI32 se concentram na estrutura do datapath, o método de acesso ao banco de registradores, mecanismos de manipulação de tag e codificação das micro-instruções.
 

3.5.1 Características da arquitetura

O AI32 foi projetado para ser um processador escravo, operando sob a supervisão da MPU (Micro Processing Unit) hospedeira, ambas acessando o mesmo espaço de endereçamento. O AI32 compõe-se de 5 unidades principais: unidade de sequenciamento das microinstruções, unidade de controle de barramento, unidade de execução, 2 bancos de registradores.

A unidade de sequenciamento é composta por uma grande EPROM (4K palavras de 64 bits) para o armazenamento das microinstruções, mecanismos de despacho de instruções e manipulação de tags. A unidade de execução possui uma ULA e um barrel-shifter. Cada banco de registradores possui 256 palavras de 32-bits de memória RAM e uma unidade aritmética privada com registradores de endereço. Cada unidade é controlada independentemente por um campo da microinstrução [KAW 86].

Programas escritos em linguagens orientadas a objetos são traduzidas em seqüências de macro-instruções, os quais são executados através de microinstruções pelo AI32. No AI32, o contexto da chamada de métodos é armazenado na pilha de execução e é chamada "contexto volátil".

O datapath do AI32 foi projetado para alcançar bom desempenho com recursos limitados. Os dois grandes banco de registradores provém maior eficiência na transferência de dados, explorando a localidade dos mesmos. A estratégia de separar os registadores em dois bancos é uma questão tecnológica, pois o aumento do número de registradores eleva o tempo de propagação. O datapah é de 32 bits e as operações realizadas são: ler 2 operandos dos bancos de registradores, realizar operações de ULA ou shift e armazenar o resultado da operação nos latches de saída. Dados da memória podem ser lidos a partir dos registradores AOR (Address Output Register), DIR (Data Input Register) e DOR (Data Output Register).

Na realidade a seqüência de micro-instruções é determinada por um campo de 12 bits NMA (Next Micro-Address) para eliminar a necessidade de uma unidade complexa para determinar a seqüência de microinstruções. Esta técnica diminui a quantidade de instruções de desvio explícitas, numerosas devido ao compartilhamento de grandes porções do micro-código.

Cada apontador possui um bit de tag (bit menos significativo) para indicar seu tipo. Caso este bit tenha o valor 1, significa que corresponde à uma referência a um objeto, se o valor for 0, o apontador é tratado como um valor do tipo inteiro. Na realidade, esta arquitetura não apresenta inovações muito significativas, recorrendo à microprogramação para a execução de linguagens orientadas a objetos.
 



 

4. Discussão e Conclusão

Durante o texto pudemos observar diversas técnicas e estruturas de hardware utilizadas para melhorar o desempenho na execução de programas escritos em orientadas a objetos, principalmente Smalltalk. Basicamente os projetos procuram explorar 3 grandes gargalos das aplicações orientadas a objetos: passagem de mensagens, grande exigência de memória, e troca de contexto.

Foram diversas as formas com que os projetistas tentaram contornar os problemas encontrados: uso de grande quantidade de registradores, pilhas, instruções virtuais, memória virtual, memória associativa, inline cache e method cache, ITLB, novos modos de endereçamento, janelas de registradores, dentre outras. Muitas destas técnicas parecem não ser grande novidade, mas na época foram motivo de grande inovação e discussão.

Pode-se observar ainda que os projetistas seguiram 3 linhas de projeto distintas: maciço uso de microcódigo, uso de monoprocessador RISC e uso de um multiprocessador para explorar o paralelismo. Cada uma delas privilegia um fator, seja ele desempenho, simplicidade, velocidade de implementação, ou tão somente dar suporte adequado à linguagem alvo. Por exemplo, o uso maciço de microcódigo se deve ao fato de suportar as instruções da máquina virtual da linguagem diretamente, primando por portabilidade. A linguagem OIL, por tentar incorporar os 3 paradigmas mais utilizados em IA possui grande quantidade de paralelismo a ser explorado e um tratamento adequado das troca de mensagem.

O ponto chave desempenho não foi abordado de forma quantitativa, não constando gráficos ilustrativos de speed-up obtidos por cada máquina. Este fato se deve por diversos motivos: os dados constantes nos documentos pesquisados estão desatualizados, não há uma padronização efetiva da metodologia de benchmark entre os projetos, não existe uma análise comparativa de desempenho de muitas máquinas da época, muitos dos projetos não explicitavam o tipo de tecnologia utilizada na implementação das máquinas.
 
 

Sumário Características das Máquinas OO
  SOAR FAIM-1 COM Sword32 AI32
Interface com a Linguagem
compilador estático
compilador estático
microcodigo
microcódigo
microcódigo
Arquitetura
Monoproc. RISC
multiproc.
monoproc. CISC
multiproc.
monoproc. (Slave)
Ponteiro de Objeto
28 bits
??
32 bits (?)
32 bits
??
Tabela de Objetos
não
??
não
sim
??
Garbage Collector
Generation Scavenger
??
não (somente mem. virutal)
Transaction
??
Instrução
código nativo
código nativo
bytecode
bytecode
bytecode
Method lookup
Inline cache
conceito de fireable
ITLB
Method cache
??
Tags
sim
sim
sim
sim
sim
Alocação de Contexto
Stack
coprocessador dedicado
Cache de contexto
Stack
Stack
 
Quadro 2 - Sumário das Máquinas OO

 
Ressalta-se porém, que durante o texto procurou-se abordar cada máquina de forma resumida, atendo-se aos pontos mais importantes de cada uma. Muitas dos detalhes foram omitidos por simplicidade atendo-se principalmente às estratégias utilizadas por cada projeto no atendimento aos requisitos citados acima. Um resumo das características das máquinas é apresentado no quadro 2.

Um ponto mais filosófico é a questão das linguagens orientadas a objetos atuais produzirem programas razoavelmente eficientes. Programas escritos em linguagens como C++ são amplamente difundidos e podem ser utilizados em qualquer computador pessoal. Entretanto, o que devemos considerar é que muitas linguagens abandonaram a idéia de serem puramente orientadas a objetos em detrimento do desempenho a ser obtido nas máquinas convencionais. Em adição à este fato, também a tecnologia de implementação se alterou profundamente, permitindo que problemas de gerenciamento de memória fossem amenizados.

A grande pergunta a ser respondida é se linguagens orientadas a objeto necessitam realmente de suporte especial em hardware. Algumas discussões podem ser encontradas em [UNG 95], no qual Ungar argumenta que da linguagem SELF (tão orientada a objetos como Smalltalk-80) pode resultar em código objeto semelhante ao produzido a partir de C. Segundo Ungar, estes resultados foram obtidos com a utilização de técnicas sofisticadas de compilação, contradizendo trabalhos realizados no passado.

 
5. Bibliografia
 

 [HON 87] HON, Robert W. et al. The Architecture of FAIM-1. Computer, IEEE Computer Society, Vol. 20, N 1, January, 1987.

[ITO 98] ITO, Sérgio A. Arquitetura dos Processadores Java. Monografia apresentada como trabalho final da disciplina CMP 114. CPGCC-UFRGS, agosto de 1998.

[KAJ 85] KAJIYA, James T.; DALLY, Willian J. An Object Oriented Architecture. Proceedings of 12th Annual International Symposium on Computer Architecture. Massachusetts: IEEE Computer Society Press, 1985.

[KAW 86] KAWASAKI, Shumpei et al. Microprogrammable Processor for Object-Oriented Architecture. Proceedings of 13th Annual International Symposium on Computer Architecture. Tokyo: IEEE Computer Society Press, 1986.

[PAT 86] PATTERSON, David et al. Architecture of SOAR: Smalltalk on a RISC. Tutorial: Software-Oriented Computer Architecture. Washington: IEEE Computer Society Press, 1986.

[PAT 87] PATTERSON, David; UNGAR, David. What Price Smalltalk? Computer, IEEE Computer Society, Vol. 20, N 1, January, 1987.

[RAM 87] RAMAMOORTHY, C. V. et al.. Software Development Support for AI Programs. Computer, IEEE Computer Society, Vol. 20, N 1, January, 1987.

[SUZ 84] SUZUKI, Norihisa et al. Sword32: A Bytecode Emulating Microprocessor for Object-Oriented Languages. Procedings of the International Conference on Fifth Generation Computer Systems. Japan: ICOT, 1984.

[TEL 89] TELLO, Ernest R. Object-Oriented Programming for Artificial Inteligence. Addison-Wesley Publishing Company, Inc, 1989.

[UNG 87] UNGAR, David et al. Compiling Smalltalk-80 to a RISC. Proceedings of Second International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS II), California: IEEE Computer Society Press, 1987.

[UNG 95] UNGAR, David; URS Hölzle. Do object-oriented languages need special hardware support? ECOOP '95 Conference Proceedings. Springer Verlag Lecture Notes in Computer Science 952. p.253-282, Aug. 1995.

[WAH 87] WAH, Benjamin W. Guest Editor's Introduction: New Computers for Artificial Intelligence Processing. Computer, IEEE Computer Society, Vol. 20, N 1, January, 1987.

[HWA 87] HWANG, Kai et al. Computer Architectures for Artificial Intelligence Processing. Computer, IEEE Computer Society, Vol. 20, N 1, January, 1987.

[HWA 89] HWANG, Kai et al. Parallel Architectures for Implementing Artificial Intelligence Systems. Parallel Processing for Supercomputers & Artificial Intelligence. Cap. 7. Editors: Hwang and Degroot, McGraw-Hill, 1989.