Bytecode ( bytecode ; engelsk bytecode , også nogle gange p-code , p-code fra bærbar kode ) er en standard mellemrepræsentation , hvortil et computerprogram kan oversættes automatisk. Sammenlignet med kildekode , der kan læses af mennesker, er bytecode en kompakt repræsentation af et program, der allerede er blevet parset og parset . Det koder eksplicit for typer , omfang og andre konstruktioner. Fra et teknisk synspunkt er en bytekode en maskinuafhængig kode på lavt niveau genereret af en oversætter fra en kildekode.
Mange moderne programmeringssprog , især tolkede , bruger bytekode til at lette og fremskynde tolkens arbejde . Oversættelse til bytekode er en metode mellem i effektivitet mellem direkte fortolkning og kompilering til maskinkode.
I form ligner bytecode maskinkode , men er beregnet til ikke at blive udført af en rigtig processor , men af en virtuel maskine . Den virtuelle maskine er normalt en fortolker af det tilsvarende programmeringssprog (nogle gange suppleret med en JIT- eller AOT-kompiler ). Specifikationerne for bytekoden og de virtuelle maskiner , der udfører den, kan variere meget fra sprog til sprog: bytecode består ofte af instruktioner til en stablet maskine [1] , men registermaskiner [2] [3] kan også bruges . De fleste bytekode-instruktioner svarer dog normalt til en eller flere assembly-sprog-instruktioner .
En bytekode hedder sådan, fordi hver opkode traditionelt er en byte lang . Hver instruktion er normalt en en-byte opkode (0 til 255), der kan efterfølges af forskellige parametre, såsom et registernummer eller en hukommelsesadresse .
Et bytekodeprogram udføres normalt af en bytekodefortolker . Fordelen ved bytecode er større effektivitet og portabilitet , det vil sige, at den samme bytekode kan udføres på forskellige platforme og arkitekturer , som fortolkeren er implementeret til. Direkte fortolkede sprog giver den samme fordel, men da bytekode normalt er mindre abstrakt og mere kompakt end kildekode, er bytekodefortolkning normalt mere effektiv end ren kildekodefortolkning eller AST -fortolkning . Derudover er en bytekodefortolker ofte enklere end en kildekodefortolker og er lettere at overføre (porte) til en anden hardwareplatform.
Højtydende implementeringer af virtuelle maskiner kan bruge en kombination af en fortolker og en JIT-kompiler , som oversætter hyppigt anvendte bytekodefragmenter til maskinkode under programafvikling, mens der anvendes forskellige optimeringer. I stedet for JIT-kompilering kan der bruges en AOT -kompiler , som oversætter bytekoden til maskinkode på forhånd, før udførelse.
Samtidig er det muligt at oprette processorer, for hvilke den givne bytekode er direkte maskinkode (sådanne eksperimentelle processorer blev f.eks. oprettet til Java og Forth -sprogene ).
Blandt de første systemer, der brugte bytekode, var O-kode til BCPL (1960'erne), Smalltalk (1976) [4] , SIL (System Implementation Language) for Snobol-4 (1967), p-kode ( p-kode , 1970'erne, med bidrag fra Niklaus Wirth ) til bærbare compilere af programmeringssproget Pascal [5] [6] [7] .
Varianter af p-koden er blevet brugt i vid udstrækning i forskellige implementeringer af Pascal-sproget, såsom UCSD p-systemet ( UCSD Pascal ). [otte]
Fortolkede sprog, der bruger bytekode, inkluderer Perl , PHP (som Zend Engine ), Ruby (siden version 1.9), Python , Erlang og mange flere.
Udbredte platforme, der bruger bytekode [9] :
Clipper - kompileren opretter en eksekverbar fil, der inkluderer bytekoden oversat fra programmets kildekode og en virtuel maskine, der udfører bytekoden.
Java-programmer er normalt kompileret i klassefiler, der indeholder Java bytecode . Disse generiske filer overføres til forskellige målmaskiner.
Tidlige implementeringer af Visual Basic (før version 6) brugte Microsoft p-kode på højt niveau [9]
P-koder og bytekoder på højt niveau blev brugt i DBMS , nogle implementeringer af BASIC og Pascal .
I Open Firmware- standarden fra Sun Microsystems repræsenterer bytekoden Forth- operatører .
Koden:
>>> print ( "Hej, verden!" ) Hej , verden !Bytekode:
>>> import dis #import "dis" modulet - Disassembler af Python byte kode til mnemonics. >>> dis . dis ( 'print("Hej, verden!")' ) 1 0 LOAD_NAME 0 ( print ) 2 LOAD_CONST 0 ( 'Hej, verden!' ) 4 CALL_FUNCTION 1 6 RETURN_VALUEKoden:
ydre : for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 ) fortsæt ydre ; } System . ud . println ( i ); }Bytekode:
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_1_21 : iload_1 21 : iload_1 21 : iload_1 21 : iload_1 21 : iload_1 21 : got 25: iinc 2 , 1 28: goto 11 31: getstatic #84 ; //Field java/lang/System.out:Ljava/io/PrintStream; 34: iload_1 35: invokevirtual #85 ; //Method java/io/PrintStream.println:(I)V 38: iinc 1 , 1 41: goto 2 44: returnTraditionelt er bytekode designet i stil med stablede virtuelle maskiner, hvilket forenkler generering fra AST , giver mulighed for enklere og mere kompakt bytekodekodning, forenkler fortolkeren og reducerer mængden af maskinkode, der kræves for at udføre en enkelt bytekodeinstruktion. På den anden side indeholder sådanne varianter af bytekoden for et givet program flere instruktioner end bytekoderne for virtuelle registermaskiner, på grund af hvilke tolken skal foretage flere indirekte hop, for hvilke grenforudsigelse ikke fungerer godt [3] . Bytekoden til register virtuelle maskiner har en lidt større størrelse af maskinkoder, men antallet af instruktioner sammenlignet med stak-bytekoden er omkring to gange mindre, og tolken er titusindvis af procent hurtigere [3] . Stabelmaskinernes bytekode er også sværere at optimere (udtryk bliver implicitte, relaterede instruktioner grupperes ikke, udtryk er fordelt over flere grundlæggende blokke ) [12] og kræver verifikation af rigtigheden af at bruge stakken [13] .
Fejl ved stabling af bytekode-bekræftelse førte til mange ekstremt farlige sårbarheder, især snesevis i den virtuelle AVM2-maskine, der blev brugt i Adobe Flash til at udføre ActionScript-scripts [14] [15] [16] og flere i de tidlige populære Java-runtime-systemer (JVM) [ 17] [18]
I slutningen af 2000'erne og begyndelsen af 2010'erne satte forfatterne af V8 (til JavaScript, ofte implementeret via bytecode) [19] og Dart [20] kompilatorerne spørgsmålstegn ved behovet for mellemliggende bytekoder til hurtige og effektive virtuelle maskiner. Disse projekter implementerede direkte JIT-kompilering (kompilering ved kørsel) fra kildekoder direkte til maskinkode. [21]