Estou procurando construir uma Máquina Virtual como uma maneira independente de plataforma para executar algum código do jogo (essencialmente scripts).
As máquinas virtuais de que conheço os jogos são bastante antigas: a Z-Machine da Infocom , a SCUMM da LucasArts , o Quake 3 da id Software . Como desenvolvedor .net, conheço o CLR e examinei as instruções do CIL para obter uma visão geral do que você realmente implementa no nível da VM (versus o nível do idioma). Eu também me envolvi um pouco no 6502 Assembler durante o ano passado.
O problema é que agora que eu quero implementar um, preciso cavar um pouco mais fundo. Eu sei que existem VMs baseadas em pilha e registradas, mas realmente não sei qual é a melhor em que e se há mais abordagens híbridas. Preciso lidar com o gerenciamento de memória, decidir quais tipos de baixo nível fazem parte da VM e entender por que coisas como o ldstr funcionam da maneira que funcionam.
Meu único livro de referência (além do material Z-Machine) é o CLI Annotated Standard , mas me pergunto se existe uma palestra melhor, mais geral / fundamental para VMs? Basicamente, algo como o Dragon Book , mas para VMs? Estou ciente da Art of Computer Programming de Donald Knuth, que usa uma VM baseada em registro, mas não tenho certeza de quão aplicável essa série ainda é, especialmente porque ainda está inacabada?
Esclarecimento: O objetivo é construir uma VM especializada. Por exemplo, o Z-Machine da Infocom contém OpCodes para definir a cor de fundo ou reproduzir um som. Então, eu preciso descobrir o quanto a OpCodes usa na VM versus o compilador que pega um script (linguagem TBD) e gera o bytecode a partir dele, mas para isso eu preciso entender o que estou realmente fazendo.
¹ Eu sei que a tecnologia moderna me permitiria interpretar rapidamente uma linguagem de script de alto nível. Mas onde está a diversão nisso? :) Também é um pouco difícil de pesquisar no Google porque hoje em dia as Máquinas Virtuais estão frequentemente associadas à Virtualização de SO do tipo VMWare ...
fonte
do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);
, então talvez um compilador ... e, em seguida, começa a diversão - otimização para torná-lo realmente trabalhoQuake 3
uma máquina virtual?Respostas:
Eu começaria verificando Lua . Tanto como uma implementação de amostra quanto como uma VM / linguagem muito útil, se você finalmente decidir não lançar o seu próprio.
O código fonte é muito legível e também existe o código fonte anotado . E alguns documentos de design escritos pelo autor principal, Roberto Ierusalimschy.
Finalmente, se você optar por usá-lo em vez de seu próprio país, você vai descobrir que tem sido por muito tempo um favorito entre os desenvolvedores de jogos, e há um muito alto desempenho implementação JIT .
Sobre pilha versus registro, acho que VMs baseadas em pilha são mais fáceis de projetar, mas o compilador pode ser mais complexo. Como observa o artigo de Iesualimschy, Lua foi uma das primeiras VMs de linguagem baseada em registros, mas depois várias outras surgiram, principalmente LLVM, Dalvik e algumas VMs JavaScript modernas.
fonte
No momento, não tenho recursos específicos para vinculá-lo, mas pesquisei um tópico semelhante no passado e achei a VM do Smalltalk uma boa ajuda para o aprendizado. Existem muitos artigos e artigos acadêmicos escritos sobre os códigos de bytes usados pelo Smalltalk, além de intérpretes e VMs para escrever para usar esse bytecode. Uma pesquisa no Google por
smalltalk vm implementation
ousmalltalk bytecode interpreter
deve render muito material de leitura.Se você quiser ver algum código-fonte ou experimentar uma implementação, recomendo as versões Squeak ou Pharo.
O idioma relacionado / VM Self também pode lhe interessar, pois Self é basicamente Smalltalk com objetos baseados em protótipo (semelhante ao JavaScript).
fonte
Eu começaria analisando como o código-fonte [script] entra na sua máquina ou no ambiente de tempo de execução.
Se você tem algo parecido em documentos HTML
<a onclick="dosomething();">
, precisará de um compilador muito rápido, pois a velocidade de execução do bytecode não importa muito nesse caso. Se seus casos de uso estiverem mais próximos do Java / .NET, onde você pode permitir a compilação completa, a arquitetura da VM e a estrutura de bytecode estarão mais próximos dos bytecodes Java ou IL.Outro critério é o que chamo de "glueness". Originalmente, os scripts foram desenvolvidos como linguagens de cola - os scripts apenas definem a maneira de conectar várias funções nativas (Perl, Python, Ruby, JS). Nesse caso, a eficácia da VM e do bytecode é muito menos crítica do que no caso do Java / .NET, quando a maior parte do seu código são funções escritas na própria linguagem.
E o último critério importante que eu usaria é a extensibilidade do seu idioma. Se você planeja adicionar ao tempo de execução da linguagem muitos objetos / funções nativos implementados, digamos, em C ++, sua arquitetura de VM deve ser "conveniente" para integração com o C ++. Por exemplo: se você planeja expor aos objetos C ++ de script como eles são, a única opção para você será a contagem de referência como um gerenciamento de heap (como Python, consulte boost :: python como um exemplo de integração). Se você planeja usar heap / GC móvel / compactador, será uma história diferente. A maneira de Lua de adicionar coisas nativas ao tempo de execução é um pouco complicada [para desenvolvedores de C ++].
Em outras palavras, tente definir primeiro seu caso de uso típico e será mais fácil sugerir o que ler para você.
fonte