Bytecode ( bytecode ; anglicky bytecode , také někdy p-code , p-code z přenosného kódu ) je standardní přechodná reprezentace , do které lze automaticky přeložit počítačový program . Ve srovnání se zdrojovým kódem čitelným člověkem je bytecode kompaktní reprezentací programu, který již byl analyzován a analyzován . Explicitně kóduje typy , obory a další konstrukce. Z technického hlediska je bytecode nízkoúrovňový strojově nezávislý kód generovaný překladačem ze zdrojového kódu.
Mnoho moderních programovacích jazyků , zvláště těch interpretovaných , používá bytecode k usnadnění a urychlení práce interpreta . Překlad do bajtového kódu je metoda, která se z hlediska účinnosti nachází mezi přímou interpretací a kompilací do strojového kódu.
Ve formě je bytecode podobný strojovému kódu , ale není určen ke spuštění skutečným procesorem , ale virtuálním strojem . Virtuální stroj je obvykle interpretem odpovídajícího programovacího jazyka (někdy doplněný o kompilátor JIT nebo AOT ). Specifikace bajtového kódu a virtuálních strojů, které jej spouštějí, se mohou jazyk od jazyka značně lišit: bajtový kód se často skládá z instrukcí pro skládaný stroj [1] , ale lze použít i registrační stroje [2] [3] . Většina instrukcí bajtového kódu je však obvykle ekvivalentní jedné nebo více instrukcím v jazyce symbolických instrukcí .
Bytový kód je tak pojmenován, protože každý operační kód je tradičně jeden bajt dlouhý . Každá instrukce je obvykle jednobajtový operační kód (0 až 255), který může být následován různými parametry, jako je číslo registru nebo adresa paměti .
Program bajtového kódu je obvykle prováděn interpretem bajtového kódu . Výhodou bajtkódu je větší efektivita a přenositelnost , to znamená, že stejný bajtový kód lze spustit na různých platformách a architekturách , pro které je interpret implementován. Přímo interpretované jazyky poskytují stejnou výhodu, ale protože bajtkód je obvykle méně abstraktní a kompaktnější než zdrojový kód, je interpretace bajtkódu obvykle efektivnější než čistá interpretace zdrojového kódu nebo interpretace AST . Interpret bajtového kódu je navíc často jednodušší než interpret zdrojového kódu a snáze se přenáší (portuje) na jinou hardwarovou platformu.
Vysoce výkonné implementace virtuálních strojů mohou využívat kombinaci tlumočníka a JIT kompilátoru , který převádí často používané fragmenty bajtového kódu do strojového kódu během provádění programu, přičemž aplikuje různé optimalizace. Namísto kompilace JIT lze použít kompilátor AOT , který před spuštěním přeloží bajtový kód do strojového kódu.
Zároveň je možné vytvářet procesory, pro které je daný bytekód přímo strojovým kódem (takové experimentální procesory vznikly např. pro jazyky Java a Forth ).
Mezi první systémy, které používaly bytecode, byly O-kód pro BCPL (60. léta), Smalltalk (1976) [4] , SIL (System Implementation Language) pro Snobol-4 (1967), p-kód ( p-code , 70. léta, s příspěvky od Niklause Wirtha ) pro přenosné kompilátory programovacího jazyka Pascal [5] [6] [7] .
Varianty p-kódu byly široce používány v různých implementacích jazyka Pascal, jako je UCSD p-System ( UCSD Pascal ). [osm]
Mezi interpretované jazyky, které používají bytecode, patří Perl , PHP (jako Zend Engine ), Ruby (od verze 1.9), Python , Erlang a mnoho dalších.
Rozšířené platformy využívající bajtkód [9] :
Kompilátor Clipper vytvoří spustitelný soubor, který obsahuje bajtový kód přeložený ze zdrojového kódu programu a virtuální stroj, který bajtový kód spustí.
Java programy jsou obvykle kompilovány do souborů třídy, obsahující Java bytecode . Tyto obecné soubory jsou přenášeny do různých cílových počítačů.
První implementace jazyka Visual Basic (před verzí 6) používaly Microsoft p-code na vysoké úrovni [9]
Vysokoúrovňové p-kódy a bajtové kódy byly použity v DBMS , některých implementacích BASICu a Pascalu .
Ve standardu Open Firmware společnosti Sun Microsystems představuje bytecode operátory Forth .
Kód:
>>> tisk ( "Ahoj, světe! " ) Ahoj světe !Bytecode:
>>> import dis #import modulu "dis" - Disassembler bajtového kódu Pythonu do mnemotechnických pomůcek. >>> dis . dis ( 'print("Ahoj, světe!")' ) 1 0 LOAD_NAME 0 ( tisk ) 2 LOAD_CONST 0 ( 'Ahoj, světe!' ) 4 CALL_FUNCTION 1 6 RETURN_VALUEKód:
vnější : for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 ) pokračovat vnější ; } Systém . ven . println ( i ); }Bytecode:
0: iconst_2 1: istore_1 2: iload_1 3: sipush 1000 6: if_icmpge 44 9: iconst_2 10: istore_2 11: iload_2 12 : iload_1 13 : if_icmpge 31 16 : iload iload : 3 i2 : 2 17 25: iinc 2 , 1 28: goto 11 31: getstatic #84 ; //Pole java/lang/System.out:Ljava/io/PrintStream; 34: iload_1 35: invokevirtual #85 ; //Metoda java/io/PrintStream.println:(I)V 38: iinc 1 , 1 41: goto 2 44: returnTradičně je bajtkód navržen ve stylu skládaných virtuálních strojů, což zjednodušuje generování z AST , umožňuje jednodušší a kompaktnější kódování bajtového kódu, zjednodušuje interpret a snižuje množství strojového kódu potřebného k provedení jedné instrukce bajtového kódu. Na druhou stranu takové varianty bajtkódu pro daný program obsahují více instrukcí než bajtkódy registrových virtuálních strojů, kvůli čemuž musí interpret provádět více nepřímých skoků, u kterých nefunguje dobře predikce větví [3] . Bytový kód pro registry virtuálních strojů má o něco větší velikost strojových kódů, ale počet instrukcí ve srovnání s bajtkódem zásobníku je asi dvakrát menší a interpret je o desítky procent rychlejší [3] . Také bajtový kód zásobníkových strojů je obtížnější optimalizovat (výrazy se stávají implicitními, související instrukce nejsou seskupeny, výrazy jsou distribuovány do několika základních bloků ) [12] a vyžaduje ověření správnosti použití zásobníku [13] .
Chyby ověření bajtkódu stohovaného stroje vedly k mnoha extrémně nebezpečným zranitelnostem, zejména desítkám ve virtuálním stroji AVM2 používaném v Adobe Flash ke spouštění skriptů ActionScript [14] [15] [16] a několika v raných populárních Java runtime systémech (JVM) [ 17] [18]
Na konci roku 2000 a na začátku roku 2010 autoři kompilátorů V8 (pro JavaScript, často implementovaný prostřednictvím bajtkódu) [19] a Dart [20] zpochybnili potřebu přechodných bajtkódů pro rychlé a efektivní virtuální stroje. Tyto projekty implementovaly přímou kompilaci JIT (kompilaci za běhu) ze zdrojových kódů přímo do strojového kódu. [21]