Como os "objetos" e "classes" da OOP são organizados na memória em termos de linguagem assembly?

13

Como os objetos são organizados na memória?

Por exemplo, eu sei que uma função é um pedaço de código na memória, que espera parâmetros via pilha e / ou registradores e manipula seu próprio quadro de pilha.

Mas os objetos são uma estrutura muito mais complicada. Como eles estão organizados? Cada objeto tem "links" para métodos e passa o endereço para esse método?

Seria ótimo ver uma boa explicação sobre esse tópico.

UPD. Fiz a pergunta mais exata e estou principalmente interessado em linguagens de digitação estaticamente.

Nikolai Golub
fonte
4
Pode variar muito entre idiomas diferentes, especialmente entre idiomas de tipo dinâmico e estaticamente. Você pode restringir sua pergunta aos idiomas OO nos quais está mais interessado?
Bart van Ingen Schenau
Como atualizei a pergunta, acho que as linguagens dinamicamente digitadas são mais difíceis de entender.
Nikolai Golub

Respostas:

17

Se não houver despacho dinâmico (polimorfismo), "métodos" são apenas funções açucaradas, talvez com um parâmetro adicional implícito. Consequentemente, instâncias de classes sem comportamento polimórfico são essencialmente Cs structpara fins de geração de código.

Para despacho dinâmico clássico em um sistema de tipo estático, existe basicamente uma estratégia predominante: vtables. Cada instância obtém um ponteiro adicional que se refere a (uma representação limitada) de seu tipo, o mais importante é a vtable: Uma matriz de ponteiros de função, um por método. Como o conjunto completo de métodos para cada tipo (na cadeia de herança) é conhecido em tempo de compilação, é possível atribuir índices consecutivos (0..N para métodos N) aos métodos e invocar os métodos procurando o ponteiro de função em a vtable usando esse índice (passando novamente a referência da instância como parâmetro adicional).

Para linguagens baseadas em classes mais dinâmicas, normalmente as próprias classes são objetos de primeira classe e cada objeto tem uma referência ao seu objeto de classe. O objeto de classe, por sua vez, possui os métodos de alguma maneira dependente da linguagem (no Ruby, os métodos são uma parte essencial do modelo de objeto, no Python são apenas objetos funcionais com pequenos invólucros ao seu redor). As classes normalmente armazenam referências também às suas superclasses e delegam a pesquisa de métodos herdados nessas classes para ajudar na metaprogramação que adiciona e altera métodos.

Existem muitos outros sistemas que não são baseados em classes, mas diferem significativamente; portanto, selecionarei apenas uma alternativa interessante de design: quando você pode adicionar novos (conjuntos de) métodos a todos os tipos à vontade em qualquer lugar do programa ( por exemplo, classes de tipo em Haskell e características em Rust), o conjunto completo de métodos não é conhecido durante a compilação. Para resolver isso, cria-se uma vtable por característica e as transmite quando a implementação da característica é necessária. Ou seja, código como este:

void needs_a_trait(SomeTrait &x) { x.method2(1); }
ConcreteType x = ...;
needs_a_trait(x);

é compilado para isso:

functionpointer SomeTrait_ConcreteType_vtable[] = { &method1, &method2, ... };
void needs_a_trait(void *x, functionpointer vtable[]) { vtable[1](x, 1); }
ConcreteType x = ...;
needs_a_trait(x, SomeTrait_ConcreteType_vtable);

Isso também significa que as informações da tabela não estão incorporadas no objeto. Se você deseja referências a uma "instância de uma característica" que se comportará corretamente quando, por exemplo, armazenada em estruturas de dados que contêm muitos tipos diferentes, é possível criar um ponteiro de gordura (instance_pointer, trait_vtable) . Esta é realmente uma generalização da estratégia acima.


fonte
5

Esta é a resposta no sentido do provérbio "se você dá a um homem um peixe, você o alimenta por um dia, enquanto se você o ensina a pescar, você o alimenta por toda a vida", pois sua pergunta é muito ampla.

1. pesquisar fontes de informação abertas

O Google para "programação orientada a objetos de montagem" lista muitos recursos relevantes diferentes.

por exemplo, Programação Orientada a Objetos em Assembléia, Ethan J. Eldridge, 15 de dezembro de 2011, foi o terceiro elo e parece ser bom

2. aprenda com o código manuscrito existente

Você pode ver como isso funciona estudando códigos-fonte escritos com algumas linguagens assembly populares com OOP declarado explicitamente, por exemplo

3. aprender com os padrões de código gerados pelos compiladores

Você pode ver como isso funciona estudando os arquivos intermediários da linguagem assembly produzidos pelos compiladores OOP de sua escolha. Os compiladores C ++ e FreePascal podem ser configurados para que você possa ver como é a transcrição do código OOP de alto nível no código da linguagem assembly

4. resolva o quebra-cabeça com seu bom senso

Agora é tarde demais, pois você já conhece as dicas de outras respostas. Mas antes que a internet fosse tão fácil de pesquisar e antes que houvesse sites em que você pudesse obter sua resposta sem nenhum esforço dentro de algumas horas de graça de algum voluntário que aprendeu da maneira mais difícil, o único método de trabalho disponível gratuitamente para qualquer pessoa era

Pergunte a si mesmo: "como eu o implementaria?"

Muitas vezes, após vários dias do processo de reflexão em segundo plano em execução em sua mente e depois de jogar fora vários projetos de rascunho de papel, você descobriria que a solução que você apresentou é muito semelhante à solução que outros programadores criaram e já implementaram


Agora, minha resposta é baseada na opinião, não responde diretamente à pergunta da OP e os usuários seniores de alto representante podem me rebaixar livremente

xmojmr
fonte