stroj s p -kódem - p-code machine
V počítačovém programování je stroj s p-kódem ( přenosný stroj s kódem ) virtuální stroj určený k provádění kódu p ( kód sestavy nebo strojový kód hypotetické centrální procesorové jednotky (CPU)). Tento termín je aplikován jak genericky na všechny takové stroje (jako je Java virtuální stroj (JVM) a předkompilovaný kód MATLAB ), tak na konkrétní implementace, nejznámější je p-Machine systému Pascal-P , zejména UCSD Pascal implementace, mezi jehož vývojáři se p v p-kód byl chápán pseudo častěji než přenosné , čímž pseudo-code znamenat instrukce pro pseudo-stroj.
Ačkoli byl koncept poprvé implementován kolem roku 1966 (jako O-kód pro základní kombinovaný programovací jazyk ( BCPL ) a P kód pro jazyk Euler ), termín p-kód se poprvé objevil na začátku 70. let minulého století. Dva rané kompilátory generující p-kód byly kompilátor Pascal-P v roce 1973, Kesav V. Nori, Urs Ammann, Kathleen Jensen, Hans-Heinrich Nägeli a Christian Jacobi, a kompilátor Pascal-S v roce 1975, Niklaus Wirth .
Programy, které byly přeloženy do p-kódu, mohou být interpretovány softwarovým programem, který emuluje chování hypotetického CPU, nebo je lze přeložit do strojového kódu CPU, na kterém má program běžet, a poté ho spustit. Pokud existuje dostatečný komerční zájem, může být postavena hardwarová implementace specifikace CPU (např. Pascal MicroEngine nebo verze procesoru Java ).
Výhody a slabé stránky implementace p-kódu
Ve srovnání s přímým překladem do nativního strojového kódu nabízí dvoustupňový přístup zahrnující překlad do p-kódu a provádění interpretací nebo kompilací just-in-time (JIT) několik výhod.
- Je mnohem snazší napsat malý p-kódový tlumočník pro nový počítač, než upravit překladač tak, aby generoval nativní kód pro stejný počítač.
- Generování strojového kódu je jednou z komplikovanějších částí psaní kompilátoru. Pro srovnání, generování p-kódu je mnohem snazší, protože při generování bajtkódu není třeba brát v úvahu žádné chování závislé na stroji . To je užitečné pro rychlé spuštění kompilátoru.
- Protože p-kód je založen na ideálním virtuálním stroji, program p-kódu je často mnohem menší než stejný program přeložený do strojového kódu.
- Při interpretaci p-kódu může interpret použít další kontroly za běhu, které je obtížné implementovat pomocí nativního kódu.
Jednou z významných nevýhod p-kódu je rychlost provádění, kterou lze někdy napravit kompilací JIT. P-kód je často také snazší zpětně analyzovat než nativní kód.
Na začátku 80. let dosáhly nejméně dva operační systémy nezávislosti na stroji rozsáhlým používáním p-kódu. Operační systém Business (BOS) byl operační systém cross-platform určen ke spuštění pouze programy p-kódu. UCSD p-systém , vyvinutý na University of California v San Diegu, byl self-kompilaci a self-hosting operační systém založený na p-kód optimalizovaný pro generování podle Pascal jazykem.
V devadesátých letech se překlad do p-kódu stal populární strategií pro implementaci jazyků, jako je Python , Microsoft P-Code ve Visual Basicu a Java bytecode v Javě .
Jazyk Go používá generickou, přenosnou sestavu jako formu p-kódu, kterou implementoval Ken Thompson jako rozšíření práce na plánu 9 od Bell Labs . Na rozdíl od bytecode Common Language Runtime (CLR) nebo JVM bytecode neexistuje stabilní specifikace a nástroje Go build nevydávají formát bytecode pro pozdější použití. Sestavovač Go používá generický jazyk sestavení jako přechodnou reprezentaci a spustitelné soubory Go jsou staticky propojené binární soubory specifické pro počítač .
UCSD p-stroj
Architektura
Stejně jako mnoho jiných strojů s kódem p je UCSD p-Machine stohovací stroj , což znamená, že většina instrukcí odebírá své operandy ze zásobníku a výsledky ukládá zpět do zásobníku. To znamená, že addinstrukce nahradí dvě nejvrchnější prvky stohu s jejich součtu. Několik pokynů vyžaduje okamžitý argument. Stejně jako Pascal je p-kód nativně typovaný , podporuje datové typy boolean (b), znak (c), integer (i), real (r), set (s) a pointer (a) nativně.
Několik jednoduchých pokynů:
Insn. Stack Stack Description
before after
adi i1 i2 i1+i2 add two integers
adr r1 r2 r1+r2 add two reals
inn i1 s1 is1 set membership; b1 = whether i1 is a member of s1
ldi i1 i1 i1 load integer constant
mov a1 a2 a2 move
not b1 b1 -b1 boolean negation
životní prostředí
Na rozdíl od jiných prostředí založených na zásobníku (jako je Forth a virtuální stroj Java ), ale velmi podobných skutečnému cílovému CPU, má p-System pouze jeden zásobník sdílený rámečky zásobníku procedur (poskytuje zpáteční adresu atd.) A argumenty pro místní pokyny. Tři z registrů stroje směřují do zásobníku (který roste nahoru):
- SP ukazuje na vrchol zásobníku ( ukazatel zásobníku ).
- MP označuje začátek aktivního rámce zásobníku ( ukazatel značky ).
- EP ukazuje na nejvyšší umístění zásobníku použité v aktuálním postupu ( extrémní ukazatel ).
Rovněž je přítomna konstantní oblast a pod tím hromada narůstající dolů ke hromádce. Register NP ( nový ukazatel ) ukazuje na vrchol (nejnižší používanou adresu) haldy. Když je EP větší než NP, paměť stroje je vyčerpána.
Pátý registr, PC, ukazuje na aktuální instrukci v oblasti kódu.
Konvence volání
Rámečky zásobníku vypadají takto:
EP ->
local stack
SP -> ...
locals
...
parameters
...
return address (previous PC)
previous EP
dynamic link (previous MP)
static link (MP of surrounding procedure)
MP -> function return value
Sekvence volání procedury funguje následovně: Volání se zavádí pomocí
mst n
kde nurčuje rozdíl v úrovních vnoření (nezapomeňte, že Pascal podporuje vnořené procedury). Tato instrukce označí zásobník, tj. Rezervuje prvních pět buněk výše uvedeného rámce zásobníku, a inicializuje předchozí EP, dynamický a statický odkaz. Volající poté vypočítá a odešle všechny parametry pro proceduru a poté vydá
cup n, p
volání uživatelské procedury ( npočet parametrů, padresa procedury). Tím se počítač uloží do buňky zpáteční adresy a adresa postupu se nastaví jako nové PC.
Uživatelské postupy začínají dvěma pokyny
ent 1, i ent 2, j
První nastaví SP na MP + i, druhý nastaví EP na SP + j. V ipodstatě tedy určuje prostor vyhrazený pro místní obyvatele (plus počet parametrů plus 5) a judává počet položek potřebných místně pro zásobník. V tomto okamžiku je zkontrolováno vyčerpání paměti.
Návrat k volajícímu se provádí prostřednictvím
retC
s Cuvedením návratového typu (i, r, c, b, a jako výše, a p pro žádnou návratovou hodnotu). Návratová hodnota musí být dříve uložena v příslušné buňce. U všech typů kromě p vrátí návrat tuto hodnotu v zásobníku.
Místo volání uživatelské procedury (cup) lze standardní proceduru qvyvolat pomocí
csp q
Tyto standardní postupy jsou Pascalovy procedury jako readln()( csp rln), sin()( csp sin) atd. Zvláště eof()je místo toho instrukce p-Code.
Příklad stroje
Niklaus Wirth specifikoval jednoduchý stroj s p-kódem v knize Algoritmy + datové struktury = programy z roku 1976 . Stroj měl 3 registry- čítač programu p , základní registr b a registr t -top-of-stack . Bylo tam 8 pokynů:
- svítí 0, a : zatěžovací konstanta a
- opr 0, a : provedení operace a (13 operací: RETURN, 5 matematických funkcí a 7 porovnávacích funkcí)
- lod l , a : proměnná zatížení l, a
- sto l , a : uložit proměnnou l, a
- cal l , a : volání procedury a na úrovni l
- int 0, a : přírůstek t-registru o a
- jmp 0, a : skok na a
- jpc 0, a : skok podmíněný a
Toto je kód pro stroj napsaný v Pascalu:
const
amax=2047; {maximum address}
levmax=3; {maximum depth of block nesting}
cxmax=200; {size of code array}
type
fct=(lit,opr,lod,sto,cal,int,jmp,jpc);
instruction=packed record
f:fct;
l:0..levmax;
a:0..amax;
end;
var
code: array [0..cxmax] of instruction;
procedure interpret;
const stacksize = 500;
var
p, b, t: integer; {program-, base-, topstack-registers}
i: instruction; {instruction register}
s: array [1..stacksize] of integer; {datastore}
function base(l: integer): integer;
var b1: integer;
begin
b1 := b; {find base l levels down}
while l > 0 do begin
b1 := s[b1];
l := l - 1
end;
base := b1
end {base};
begin
writeln(' start pl/0');
t := 0; b := 1; p := 0;
s[1] := 0; s[2] := 0; s[3] := 0;
repeat
i := code[p]; p := p + 1;
with i do
case f of
lit: begin t := t + 1; s[t] := a end;
opr:
case a of {operator}
0:
begin {return}
t := b - 1; p := s[t + 3]; b := s[t + 2];
end;
1: s[t] := -s[t];
2: begin t := t - 1; s[t] := s[t] + s[t + 1] end;
3: begin t := t - 1; s[t] := s[t] - s[t + 1] end;
4: begin t := t - 1; s[t] := s[t] * s[t + 1] end;
5: begin t := t - 1; s[t] := s[t] div s[t + 1] end;
6: s[t] := ord(odd(s[t]));
8: begin t := t - 1; s[t] := ord(s[t] = s[t + 1]) end;
9: begin t := t - 1; s[t] := ord(s[t] <> s[t + 1]) end;
10: begin t := t - 1; s[t] := ord(s[t] < s[t + 1]) end;
11: begin t := t - 1; s[t] := ord(s[t] >= s[t + 1]) end;
12: begin t := t - 1; s[t] := ord(s[t] > s[t + 1]) end;
13: begin t := t - 1; s[t] := ord(s[t] <= s[t + 1]) end;
end;
lod: begin t := t + 1; s[t] := s[base(l) + a] end;
sto: begin s[base(l)+a] := s[t]; writeln(s[t]); t := t - 1 end;
cal:
begin {generate new block mark}
s[t + 1] := base(l); s[t + 2] := b; s[t + 3] := p;
b := t + 1; p := a
end;
int: t := t + a;
jmp: p := a;
jpc: begin if s[t] = 0 then p := a; t := t - 1 end
end {with, case}
until p = 0;
writeln(' end pl/0');
end {interpret};
Tento stroj byl použit ke spuštění Wirth's PL/0 , kompilátoru podmnožiny Pascal, který se používal k výuce vývoje kompilátoru.
Viz také
- Apple Integer Sweet 16
- Bytový kód
- Joel McCormack , návrhář verze stroje s kódem p NCR Corporation
- LLVM IR
- Microsoft P-Code
- Runtime systém
- Tokenové navlékání
Reference
Další čtení
- Pemberton, Steven ; Danielsi, Martine. Implementace Pascalu: překladač a tlumočník P4 . John Wiley . ISBN 0-13-653031-1.
- Pemberton, Steven , ed. (13. dubna 2011). „Implementace Pascalu: Kniha a zdroje“ .(Pozn. Má zdroje Pascal kompilátoru a tlumočníka P4 , pokyny k použití.)
- Pemberton, Steven , ed. (2011-04-13). „pcode kompilátoru Pascal, jak sám kompilován“ .(Pozn. Má p-kód kompilátoru P4 , generovaný sám.)
- „Stránka Jeffersonova počítačového muzea na p-systému UCSD“ .
- „Implementace open source“ ., včetně balení a předkompilovaných binárních souborů; přátelská vidlice Klebsch. „Klebschova implementace“ .
- Terry, Pat (2005). Kompilace s C# a Java . p. 624. ISBN 0-321-26360-X.
- Wirth, Niklaus (1975). Algoritmy + datové struktury = programy . ISBN 0-13-022418-9.
- Wirth, Niklaus (1996). Konstrukce kompilátoru . ISBN 0-201-40353-6.
- Liffick, Blaise W., ed. (1979). Bajtská kniha Pascala . ISBN 0-07-037823-1.
- Barron, David William , ed. (1981). Pascal: Jazyk a jeho implementace . ISBN 0-471-27835-1.(Pozn. Viz zejména články k poznámkám k implementaci Pascal-P a Pascal-S: podmnožina a její implementace .)