Chcę zbudować maszynę wirtualną, czy są jakieś dobre referencje? [Zamknięte]

22

Chcę zbudować maszynę wirtualną jako niezależny od platformy sposób uruchamiania kodu gry (w zasadzie skryptów).

Maszyny wirtualne, które znam w grach, są raczej stare: Z-Machine Infocom , SCUMM LucasArtsa , Quake 3 id Software . Jako programista .net znam CLR i zapoznałem się z instrukcjami CIL, aby uzyskać przegląd tego, co faktycznie wdrażasz na poziomie maszyny wirtualnej (w porównaniu do poziomu języka). W ubiegłym roku trochę się też bawiłem w asemblerze 6502 .

Chodzi o to, że teraz, gdy chcę wdrożyć jedną, muszę głębiej kopnąć. Wiem, że istnieją maszyny wirtualne oparte na stosie i oparte na rejestrach, ale tak naprawdę nie wiem, która z nich jest lepsza w czym i czy jest więcej lub podejście hybrydowe. Muszę poradzić sobie z zarządzaniem pamięcią, zdecydować, które typy niskiego poziomu są częścią maszyny wirtualnej i muszę zrozumieć, dlaczego rzeczy takie jak ldstr działają w ten sposób.

Moją jedyną książką referencyjną (oprócz elementów Z-Machine) jest CLI Annotated Standard , ale zastanawiam się, czy jest lepszy, bardziej ogólny / podstawowy wykład dla maszyn wirtualnych? Zasadniczo coś w rodzaju Dragon Book , ale dla maszyn wirtualnych? Zdaję sobie sprawę z sztuki programowania komputerowego Donalda Knutha, która wykorzystuje maszynę wirtualną opartą na rejestrach, ale nie jestem pewien, w jaki sposób ta seria wciąż ma zastosowanie, zwłaszcza, że ​​wciąż jest niedokończona?

Wyjaśnienie: Celem jest zbudowanie specjalistycznej maszyny wirtualnej. Na przykład Z-Machine Infocom zawiera kody OpC do ustawiania koloru tła lub odtwarzania dźwięku. Muszę więc dowiedzieć się, ile idzie na maszynę wirtualną jako OpCodes vs. kompilator, który pobiera skrypt (język TBD) i generuje z niego kod bajtowy, ale w tym celu muszę zrozumieć, co naprawdę robię.


¹ Wiem, że nowoczesna technologia pozwoliłaby mi na bieżąco interpretować język skryptowy wysokiego poziomu. Ale gdzie jest w tym zabawa? :) Google jest również trochę trudny, ponieważ maszyny wirtualne są obecnie często kojarzone z wirtualizacją systemu operacyjnego VMWare ...

Michael Stum
źródło
6
Zwróć uwagę, że aby maszyna oparta na stosie była kompletna, potrzebuje pamięci poza stosem, w przeciwnym razie jest to tylko PDA
maniak zapadkowy
1
Pierwsze pytanie brzmi: jak daleko chcesz się posunąć? Nigdy nie patrzyłem na SCUMM / SCUMMVM, ale zakładam, że to dość wysoki poziom wiedzy na temat poruszających się grafik itp., Podczas gdy CIL jest ... więc musisz zdefiniować swój model pamięci (oparty na stosie rejestru, mikstura, bałagan, ...) i kody operacyjne ( tj. instrukcje asemblera), a następnie pierwsza wersja maszyny wirtualnej to pętla, do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);a może może kompilator ... i wtedy zaczyna się zabawa - optymalizacja, aby rzeczywiście działała
John
3
Spróbuj rozpocząć od wdrożenia prostego środowiska wykonawczego Forth.
SK-logic
1
Jak dokładnie jest Quake 3wirtualna maszyna?
Ramhound,
3
@Ramhound Silniki id tech od dawna stosują jakąś formę wewnętrznej wirtualizacji, ten artykuł lub informacje z Wikipedii mogą wyjaśnić lepiej.
Daniel B

Odpowiedzi:

18

Zacznę od sprawdzenia Lua . Zarówno jako przykładowa implementacja, jak i bardzo użyteczna maszyna wirtualna / język po wyjęciu z pudełka, jeśli w końcu zdecydujesz się nie rzucać własnym.

Kod źródłowy jest bardzo czytelny, a także kod źródłowy z adnotacjami . I niektóre dokumenty projektowe napisane przez głównego autora, Roberto Ierusalimschy.

Wreszcie, jeśli zdecydujesz się użyć go zamiast własnego, przekonasz się, że od dawna jest on ulubieńcem twórców gier i istnieje bardzo wydajna implementacja JIT .

Jeśli chodzi o stosy vs rejestry, myślę, że maszyny wirtualne oparte na stosie są łatwiejsze do zaprojektowania, ale kompilator może być bardziej złożony. Jak zauważa papier Iesualimschy, Lua była jedną z pierwszych maszyn wirtualnych w języku opartym na rejestrach, ale później pojawiło się kilka innych, w szczególności LLVM, Dalvik i niektóre nowoczesne maszyny wirtualne JavaScript.

Javier
źródło
2
O stosach vs maszynach rejestrujących: Pamiętam cytat z twórców Parrot / Perl6: „zbudowanie maszyny opartej na rejestrze jest trudniejsze, ale korzystamy z mnóstwa istniejących badań po naszej stronie kompilatora” (nie dosłownie)
John
+1 Lua ma doskonałą implementację kodu bajtowego i bardzo czysty projekt do nauki o maszynach wirtualnych. Ponadto przekonasz się, że wiele osób dostosowało Luę do własnych potrzeb, pokazując, że jest dość rozszerzalna, jeśli nie chcesz zaczynać od zera.
CodexArcanum,
Nadal przez to przechodzę. Kolejny świetny dokument od dewelopera na temat VM: inf.puc-rio.br/~roberto/talks/lua-ll3.pdf
Michael Stum
2

W tej chwili nie mam żadnych konkretnych zasobów, z którymi mogę cię połączyć, ale w przeszłości badałem podobny temat i odkryłem, że VM Smalltalk jest również dobrą pomocą do nauki. Istnieje wiele prac naukowych i artykułów o kodach bajtów używanych przez Smalltalk, a także pisanie interpretatorów i maszyn wirtualnych do korzystania z tego kodu bajtowego. Wyszukiwarka Google powinna smalltalk vm implementationlub smalltalk bytecode interpreterpowinna dostarczyć dużo materiałów do czytania.

Jeśli chcesz zobaczyć kod źródłowy lub wypróbować implementację, polecam wersje Squeak lub Pharo.

Powiązany język / VM Self może również Cię zainteresować, ponieważ Self jest w zasadzie Smalltalk z obiektami opartymi na prototypach (podobnym do JavaScript).

CodexArcanum
źródło
0

Zacznę od analizy, w jaki sposób kod źródłowy [skrypt] dostaje się do komputera lub środowiska wykonawczego.

Jeśli masz coś takiego jak w dokumentach HTML <a onclick="dosomething();">, będziesz potrzebować bardzo szybkiego kompilatora, prędkość wykonania kodu bajtowego nie ma w tym przypadku tak wielkiego znaczenia. Jeśli twoje przypadki użycia są bliższe Java / .NET, gdzie możesz sobie pozwolić na pełną kompilację, wówczas architektura VM i struktura kodu bajtowego będą bliższe kodom bajtowym Java lub IL.

Kolejnym kryterium jest to, co nazywam „kleistością”. Oryginalnie skrypty opracowano jako języki kleju - skrypty po prostu określają sposób łączenia różnych funkcji natywnych (Perl, Python, Ruby, JS). W takim przypadku efektywność VM i kodu bajtowego jest znacznie mniej istotna niż w przypadku Java / .NET, gdy większość kodu to funkcje napisane w samym języku.

Ostatnim ważnym kryterium, którego bym użył, jest rozszerzalność twojego języka. Jeśli planujesz dodać do swojego środowiska wykonawczego wiele rodzimych obiektów / funkcji zaimplementowanych, powiedzmy, w C ++, twoja architektura VM powinna być „wygodna” do integracji z C ++. Na przykład: jeśli planujesz wystawić na działanie skryptów obiekty C ++, ponieważ są one jedyną opcją dla ciebie, liczenie referencji jako zarządzanie stertami (jak Python, zobacz boost :: python jako przykład integracji). Jeśli planujesz użyć ruchomej / zagęszczającej sterty / GC, będzie to inna historia. Sposób dodawania natywnych rzeczy przez Luę w środowisku wykonawczym jest nieco trudny [dla programistów C ++].

Innymi słowy, spróbuj najpierw zdefiniować typowy przypadek użycia, a łatwiej będzie zasugerować, co dla ciebie przeczytać.

c-uśmiech
źródło
1
Współczesne kompilatory JavaScript są dość złożone, a pytanie, czy istnieje optymalizacja wygenerowanego kodu, jest dość skomplikowane.
John
Liczy się wydajność wykonywania Javascript. Nie dla małych skryptów, ale dla większych witryn obciążonych JS, które na lepsze lub gorsze stanowią znaczną część bardziej popularnych witryn. Jest powód, silniki JS użyciu kompilatorów JIT (V8 nawet nie mieć tłumacza, to idzie prosto do kodu maszynowego).
@delnan: Przypadek użycia JS jest zupełnie inny niż, powiedzmy, Python. W Pythonie, gdy potrzebujesz czegoś w rodzaju implementacji algorytmu śledzenia promieni, będziesz robił bibliotekę natywną i wywoływał ją ze skryptu. To zawsze będzie szybsze (lub przynajmniej nie wolniejsze) niż jakiekolwiek rozwiązanie JIT. W dziedzinie JS nie masz takiego luksusu jak kod natywny, więc jedyną opcją jest próba uczynienia maszyny wirtualnej JS tak szybką, jak to możliwe. Ale znowu z ceną. Ocena „dosomethingnative ()” w HTML ”<button onclick =„ dosomethingnative () ”> w prostym tłumaczu może być o rząd wielkości szybszy niż w V8.
c-smile
@ c-smile Mój punkt dokładnie.
@delnan: ale mój punkt widzenia jest zupełnie inny: analizuj typowe przypadki użycia i tylko wtedy możesz zdecydować, jakiej architektury VM, składni języka itp. będziesz potrzebować.
c-smile