hyväksymispäivä arvosana arvostelija Java-virtuaalikone Heikki Korhola Helsinki 24.4.2009 HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos
HELSINGIN YLIOPISTO HELSINGFORS UNIVERSITET UNIVERSITY OF HELSINKI Tiedekunta Fakultet Faculty Laitos Institution Department Matemaattis-luonnontieteellinen tiedekunta Tekijä Författare Author Heikki Korhola Työn nimi Arbetets titel Title Tietojenkäsittelytieteen laitos Java-virtuaalikone Oppiaine Läroämne Subject Tietojenkäsittelytiede Työn laji Arbetets art Level Aika Datum Month and year Sivumäärä Sidoantal Number of pages Kandidaatintutkielma 24.4.2009 20 sivua Tiivistelmä Referat Abstract Sun Microsystemsin Java on 1990-luvun alussa kehitetty uudenaikainen ohjelmointi- ja ohjelmien suoritusympäristö, jonka sydämessä on Java-virtuaalikone, abstrakti tietokone, jonka konekieli on Java-tavukoodi. Virtuaalikoneteknologian ansiosta Java-ympäristölle laaditut sovellusohjelmat ovat siirrettäviä, turvallisia ja kohtuullisen suorituskykyisiä. Java-tavukoodi on laitteistoriippumaton välikieli. Java-tavukoodiohjelmat esitetään laitteistoja käyttöjärjestelmäriippumattomassa class-tiedostomuodossa. Java-tavukoodiohjelmia suoritetaan tavallisimmin ohjelmallisella Java-virtuaalikonetoteutuksella. Java-virtuaalikonetoteutus on olemassa useille erilaisille laitteisto- ja käyttöjärjestelmäympäristöille, mukaan lukien kaikki yleisimmät nykyiset kotitietokoneet. Java-tavukoodiohjelmat toimivat millä tahansa Java-virtuaalikoneella samalla tavalla. Virtuaalikoneteknologia mahdollistaa myös sovellusohjelmien luotettavuus- ja turvallisuusominaisuuksien parantamisen. Keskeinen virtuaalikoneen määritelmään kuuluva ominaisuus on, että virtuaalikoneen sisällä suorittavien ohjelmien käytettävissä on ainoastaan virtuaalikoneen itsensä määrittelemät toiminnot. Java-virtuaalikoneen rakenne ja toiminnot on määritelty etenkin ohjelmien turvallisuutta silmälläpitäen. Tämä on tärkeää erityisesti verkkosivuille sulautettujen sovelmien (applet) tapauksessa, jossa suoritettavaa koodia ladataan tietoliikenneverkon ylitse mahdollisesti epäluotettavista lähteistä. Java-tavukoodin suorittaminen ohjelmallisesti on luonnollisesti konekielisten ohjelmien suorittamista raskaampaa. Nykyaikaiset Java-virtuaalikonetoteutukset nykyaikaisilla tietokoneilla saavuttavat kuitenkin jo niin korkean suorituskyvyn, ettei erolla ole useimmissa sovelluksissa merkitystä. ACM Computing Classification System (CCS): C.1.3 [Other Architecture Styles], D.3.4 [Processors] Avainsanat Nyckelord Keywords java, virtuaalikone Säilytyspaikka Förvaringsställe Where deposited Muita tietoja övriga uppgifter Additional information
Sisältö ii 1 Johdanto 1 2 Java-virtuaalikoneen rakenne ja toiminta 3 3 Class-tiedostomuoto 7 4 Suoritusaikaiset tapahtumat 11 5 Verifikaatio ja poikkeukset 12 6 Esimerkki: Hello, world! 15 7 Yhteenveto 18 Lähteet 19
1 Johdanto 1 Termillä virtuaalikone tarkoitetaan joko abstraktia tietokonetta yleensä tai sellaisen toteutusta, eli ohjelmaa, joka jäljittelee (emuloi) abstraktin koneen toimintoja. Abstraktin koneen toiminnot voidaan määritellä samoiksi kuin jollakin todellisella koneella, mutta nykyinen virtuaalikoneen määritelmä kattaa myös koneet, joilla ei ole mitään suoraa vastaavuutta todellisiin koneisiin [SmN05, s. 35]. Jälkimmäiseen ryhmään kuuluu Sun Microsystemsin Java-teknologian kulmakivi, Java-virtuaalikone (Java Virtual Machine, JVM). Java-teknologian alkuperäisenä ja pääasiallisena tarkoituksena on mahdollistaa sovellusohjelmien laatiminen Java-ohjelmointikielellä ja niiden suorittaminen turvallisesti ja kohtuullisen tehokkaasti monissa erilaisissa laitteisto- ja käyttöjärjestelmäympäristöissä. Tyypillisesti Java-lähdekieliset ohjelmat käännetään välikielelle, Java-tavukoodiksi (Java bytecode), jota suoritetaan ohjelmallisesti Java-virtuaalikonetoteutuksella. Tämä poikkeaa perinteisestä ohjelmien levitysmallista, jossa loppukäyttäjälle tarkoitetut ohjelmat ovat jonkin tietyn käyttöjärjestelmän binääriformaatissa ja jonkin tietyn todellisen suorittimen konekielellä. Selkeänä etuna virtuaalikonemallissa on paitsi ohjelmien huomattavasti korkeampi siirrettävyys, myös mahdollisuus parantaa niiden luotettavuus- ja turvallisuusominaisuuksia. Virtuaalikoneen malli lainattiin Java-teknologiaan aikaisemmasta UCSD p-system -järjestelmästä [All04, s. 26]. P-System oli kokonainen käyttöjärjestelmä, joka oli helposti siirrettävissä eri laitteistoalustoille. Sen ytimessä oli virtuaalikone, joka suoritti p-koodia, kuvitellun koneen konekieltä, ohjelmallisesti. P-systemin ytimen ulkopuoliset osat oli kirjoitettu UCSD:n omalla Pascal-kielen muunnelmalla ja käännetty p-koodiksi. Uudelle laitteistoalustalle tarvitsi siis laatia vain pieni p-kooditulkki ja muut järjestelmän osat toimivat sen kanssa muokkaamattomina. P-system ei koskaan levinnyt akateemisen yhteisön ulkopuolelle. Java-toteutus sen sijaan löytyy nykyään yli 4,5 miljardista laitteesta [Sun09a]. Näiden laitteiden joukkoon kuuluu tavanomaisten pöytäkoneiden ja palvelimien lisäksi matkapuhelimia, sirukortteja ja jopa lääketieteellisiä koneita [Sun09a]. Selkein ero Java-tavukoodiohjelmien ja perinteisten konekielisten ohjelmien välillä on Java-tavukoodiohjelmien laitteisto- ja käyttöjärjestelmäriippumattomuus. Javatavukoodiohjelmat on tarkoitettu jollekin tietylle (yleensä taaksepäin yhteensopivalle) Java-ympäristön standardille. Java-ympäristön standardiin kuuluu virtuaalikoneen lisäksi oleellisena osana standardikirjasto. Yleisin Java-ympäristön standardi
2 on Java SE (Standard Edition). Kutsutaan virtuaalikoneen ja standardikirjaston toteutusta yhdessä Java-toteutukseksi. Sunin oma Java-toteutus (Java SE Runtime Environment 6u13) on saatavilla Windowsille (x86, x64, Itanium), Linuxille (x86, x64, Itanium) ja Solarikselle (x86, x64 ja SPARC) [Sun09b]. Apple ylläpitää Mac OS X:lle omaa Java-toteutustaan [App09]. Nämä kattavat yli 95% Internetiin kytketyistä tietokoneista [Usa09]. Java-virtuaalikoneita on laadittu myös useille muille eri laitteisto- ja käyttöjärjestelmäympäristöille muiden instituutioiden toimesta [Lis09]. Suuri osa Javan ydinteknologioiden lähdekoodista on nykyään vapaasti saatavilla GPL-lisenssin alaisena [Sun09c]. Tämä helpottaa tarvittaessa oman Java-toteutuksen laatimista myös mille tahansa muulle halutulle laitteistolle tai käyttöjärjestelmälle. Tavukoodiohjelmien suorittaminen ohjelmallisesti virtuaalikonetoteutuksella on selkeästi raskaampaa kuin konekielisten ohjelmien suorittaminen suoraan laitteistolla. Alkuaikojen virtuaalikoneet saattoivat olla 1000 kertaa vastaavaa oikeaa konetta hitaampia [Gol74, s. 35]. On selvää, ettei oikeiden, isojen ohjelmien suorittaminen tällä tavoin ole kovin mielekästä. Nykyaikaiset tietokoneet ja nykyaikaiset virtuaalikoneet sen sijaan ovat jo niin tehokkaita, ettei virtuaalikoneen lisärasite ole enää ratkaisevan suuri. Java-tavukoodiohjelmien suorituskyky nykyaikaisilla virtuaalikonetoteutuksilla on jo samassa suuruusluokassa vastaavien konekielelle käännettyjen C++-ohjelmien kanssa [Cow04]. Javan luotettavuus ja turvallisuus ovat seurausta virtuaalikoneen mahdollistamasta tavasta suorittaa sovellusohjelmia hiekkalaatikossa (sandbox), eristyksissä virtuaalikoneen ulkopuolisesta ympäristöstä. Java-virtuaalikonetta voisi sanoa oliopohjaiseksi tietokoneeksi. Java-tavukoodi ei oikeista matalan tason konekielistä poiketen tarjoa mahdollisuuksia eksplisiittiseen muistinhallintaan tai osoitinaritmetiikkaan. Tämä estää esimerkiksi osoittimien väärentämisen (pointer forging) [Eis97, 2]. Java-virtuaalikoneen staattinen verifikaatiomekanismi varmistaa class-tiedostojen osittaisen turvallisuuden jo ennen suoritusta. Myös suoritusaikaisten virheiden vaikutusalue pyritään rajaamaan virtuaalikoneen sisälle, siten että Java-tavukoodiohjelmat eivät koskaan kaataisi isäntäkonetta.
2 Java-virtuaalikoneen rakenne ja toiminta 3 Nykyaikaisia yleiskäyttöisiä tietokoneita (mukaanlukien IBM-PC -yhteensopivat) voidaan tarkastella hierarkisina järjestelmien järjestelminä [Sta06, 1.2]. Niistä voidaan korkealla tasolla erotella komponentteja kuten suoritin, keskusmuisti ja lisälaiteväylä. Suoritinta itseään voidaan puolestaan tarkastella järjestelmänä josta voidaan erottaa komponentteja kuten kontrolliyksikkö ja aritmeettis-looginen yksikkö. Asioiden tarkasteleminen tällä tavalla ylhäältä alaspäin helpottaa asiakokonaisuuksien ymmärtämistä perustuen tapaan, jossa tarkoituksella pyritään unohtamaan kulloinkin epäolennaiset yksityiskohdat. The Java T M Virtual Machine Specification [LiY97] määrittelee abstraktin tietokoneen, Java-virtuaalikoneen (Java Virtual Machine, JVM). Tässä luvussa käytän termiä Java-virtuaalikone tarkoittamaan vain tätä abstraktia konetta, jonkin tietyn toteutuksen sijaan. Java-virtuaalikoneella on paljon yhteistä oikeiden tietokoneiden kanssa. Sitä voidaan luontevasti tarkastella hyvin samaan tapaan kuin oikeita tietokoneita. Esittelen seuraavassa lyhyesti Java-virtuaalikoneen rakennetta osoittamalla sen yhtäläisyydet ja eroavaisuudet oikeisiin tietokoneisiin. Oikeiden tietokoneiden tärkeimpinä komponentteina voidaan pitää suoritinta ja keskusmuistia. Suoritin kykenee lukemaan ja kirjoittamaan keskusmuistiin tallennettua tietoa ja suorittamaan aritmeettisia ja loogisia toimituksia. Suorittimessa on sisäinen pc-rekisteri (program counter), joka osoittaa keskusmuistissa olevaan konekäskyyn (pc-rekisteri voi osoittaa myös muistipaikkaan jonka sisältöä ei ole tarkoitettu tulkittavaksi käskyksi). Suorittimen käskykanta-arkkitehtuuri (instruction set architecture, ISA) määrittelee minkä muotoinen tieto voidaan tulkita käskyksi ja millä tavalla. Tietokoneen toiminta perustuu yksinkertaistettuna nouda-ja-suorita -sykliin, jossa suoritin toistuvasti noutaa pc-rekisterin osoittamasta muistipaikasta sanan tietoa, tulkitsee sen koodaaman käskyn (purkaa siitä operaatiokoodin ja operandit), suorittaa kyseisen operaatiokoodin määräämät toimenpiteet ja (poislukien hyppykäskyt) kasvattaa pc:n arvoa yhdellä. Näin suoritin siis toistuvasti suorittaa käskyjä peräkkäisistä muistipaikoista, ellei hyppykäskyillä toisin määrätä. Nykyaikaiset suorittimet ovat yleensä arkkitehtuuriltaan rekisteripohjaisia. Tämä tarkoittaa tässä yhteydessä sitä, että esimerkiksi laskutoimitusten suorittaminen perustuu tapaan, jossa keskusmuistista noudetaan konekäskyillä dataa suorittimen ulkoisiin (konekäskyillä manipuloitaviin) rekistereihin, laskutoimitukset suoritetaan
prosessorin sisällä ja lopputulos tallennetaan ulkoiseen rekisteriin (josta se voidaan tarvittaessa tallentaa taas keskusmuistiin erillisellä käskyllä). Java-virtuaalikone on pinokone. Tämä tarkoittaa, että laskutoimitukset tapahtuvat operandipinon välityksellä. Esimerkiksi yhteenlasku koostuu kahden luvun asettamisesta operandipinoon push-käskyillä ja add-käskyn suorittamisesta. Add-käsky poimii operandipinon päältä kaksi lukua, laskee niiden summan ja asettaa sen operandipinon päälle. Pinopohjaisen arkkitehtuurin ansiosta koodista tulee hieman tiivimpää, joka on eduksi esimerkiksi siirrettäessä koodia tietoliikenneverkon ylitse (esimerkiksi verkkosivuille sulautettujen sovelmien tapauksessa). Operandipinolla ja pinopohjaisilla arkkitehtuureilla ei ole mitään tekemistä myöhemmin esiteltävän kehyspinon kanssa. Java-virtuaalikoneen konekieli on Java-tavukoodi (Java bytecode). Tavukoodia kutsutaan välikieleksi, koska se on abstraktiotasoltaan korkean tason kielten (kuten Java) ja oikeiden konekielten välissä. Se on riittävän korkealla tasolla mahdollistaakseen turvallisen oliopohjaisuuden ja riittävän matalalla tasolla, jotta sitä voidaan tehokkaasti suorittaa oikeilla koneilla. Tavukoodi-nimitys juontuu operaatiokoodien pituudesta. Ne ovat 8-bittisiä tavuja, ja mahdollisia operaatiokoodeja on siis 256. Käskykannassa on paljon erilaisia vakionlatauskäskyjä (kuten iconst_1, joka asettaa pinon päälle kokonaisluvun 1), jotka ovat olemassa vain tehokkuussyistä. Niissä jonkin tyyppinen vakio (esimerkiksi 1, 0 ja -1) on ilmaistu kiinteästi käskyssä itsessään. Tällä tavoin vältetään tällaisten usein käytettyjen vakioiden välittäminen operandeina (iconst 1 ilman alaviivaa on toiminnallisesti sama käsky kuin iconst_1, mutta siinä 1 on välitetty operandina). Java-virtuaalikoneen tyypitettyjen operaatioiden vuoksi useimmille alkeistyypeille on omat, sinänsä toisteiset, vastaavat käskynsä. Java-virtuaalikoneen alkeistyypit ovat enimmäkseen samat kuin Java-kielen. Ne ovat [LiY97, 3.2]: byte: 8-bittinen etumerkillinen kokonaisluku kahden komplementti -muodossa. Ei voida käyttää operandina aritmeettisissa operaatioissa. short: 16-bittinen etumerkillinen kokonaisluku kahden komplementti -muodossa. Ei voida käyttää operandina aritmeettisissa operaatioissa. int: 32-bittinen etumerkillinen kokonaisluku kahden komplementti -muodossa. long: 64-bittinen etumerkillinen kokonaisluku kahden komplementti -muodossa. char: 16-bittinen etumerkitön kokonaisluku, joka esittää Unicode-merkkiä. 4
float: 32-bittinen IEEE 754-standardin mukainen (pienin poikkeuksin) liukuluku double: 64-bittinen IEEE 754-standardin mukainen (pienin poikkeuksin) kaksoistarkkuuden liukuluku boolean: totuusarvotyyppi, jonka arvo on joko tosi tai epätosi. Ei voida käyttää operandina aritmeettisissa operaatioissa. JVM ei sisällä erikoisoperaatioita boolean-tyyppisiä muuttujia varten joten lausekkeissa esiintyvät totuusarvot on koodattava esimerkiksi int-tyypin arvoiksi 1 (tosi) ja 0 (epätosi). Booleantyyppiset taulukot on toteutettu byte-taulukoina käyttäen edellämainittua 1-0 -koodausta. reference: viittaustyyppi jonka arvo on viittaus keosta varattuun luokkatyyppiseen, rajapintatyyppiseen tai taulukkotyyppiseen olioon tai erityinen nullarvo, joka merkitsee viittausta ei-mihinkään. Ei voida muokata suorituksen aikana tavukoodikäskyillä. Ei voida käyttää operandina aritmeettisissa operaatioissa. returnaddress: viittaustyyppi, joka osoittaa tavukoodikäskyyn. Ei voida muokata suorituksen aikana tavukoodikäskyillä. Ei voida käyttää operandina aritmeettisissa operaatioissa. 5 Java-tavukoodi on staattisesti (tyypit ovat muuttujien, eivät arvojen ominaisuuksia) ja vahvasti tyypitetty kieli. Java-tavukoodin vahva tyypitys ilmenee edellämainituissa vakionlatauskäskyissä ja aritmeettisissa käskyissä. Eri alkeistyypeille on omat käskynsä, jotka periaatteessa eroavat toisistaan vain operandiensa tyypissä. Esimerkiksi iadd-käsky ei merkitse ainoastaan, että operandeilla suoritetaan kokonaislukuyhteenlasku, vaan operandien on todella oltava kokonaislukuja. Vastaavasti fadd-käsky laskee yhteen kaksi yksöistarkkuuden liukulukua. Yritykset käyttää operandeille väärän tyyppisiä käskyjä havaitaan koodin verifikaatiovaiheessa [LiY97, 4.9.2]. Byte-, short- ja char-tyyppiset arvot laajennetaan automaattisesti int-tyyppisiksi jos ne esiintyvät aritmeettisten operaatioiden operandeina [LiY97, 3.11.3]. Viittaustyyppisillä (reference) arvoilla ei voi suorittaa laskutoimituksia, eikä niille siksi tarvita tyypitettyjä operaatioita siinä missä kokonaisluvuille tai liukuluvuille. Tyypitettyjen käskyjen toteuttaminen kaikille luokkatyypeille ei ole käytännössä mahdollista. Luokkatyyppiset arvot eivät kuitenkaan jää tyyppijärjestelmän ulkopuolelle. Kaikkia luokkatyyppisiä arvoja käsitellään a-alkuisilla operaatioilla (esimerkiksi aload i lataa operandipinon päälle viittauksen aktiivisen kehyksen paikallisten muuttujien taulukon indeksistä i). Luokkatyyppisten arvojen oikea käyttö varmistetaan osittain staattisella verifikaatiolla ja osittain suorituksen aikana poikkeusten avulla.
6 Java-virtuaalikoneen tärkeimmät komponentit ylimmällä abstraktiotasolla ovat säie (thread), luokka-alue (method area) ja keko (heap). Säikeen tärkeimmät komponentit puolestaan ovat pc-rekisteri ja kehyspino (Java Virtual Machine stack). Luokka-alueen komponentit ovat luokkia. Keon komponentit ovat olioita. Eritellään seuraavassa hieman tarkemmin näiden komponenttien koostumusta ja tarkoitusta. Java-virtuaalikoneen suoritin on säie, joita voi olla useampia kuin yksi (verrattavissa monisuoritinkoneisiin ja/tai moniydinprosessoreihin). Koska Java-virtuaalikone on abstrakti kone, sen kuvaamiseen voidaan käyttää (ja on käytetty) abstraktimpeja käsitteitä kuin mitä oikeiden, käsinkosketeltavien tietokoneiden tekniseen kuvaamiseen vaaditaan. Yksittäinen säie pitää sisällään paitsi pc-rekisterin, jolla on suhteellisen suora vastaavuus samannimiseen oikeiden suorittimien komponenttiin, myös kehyspinon, joka on käsitteellisesti huomattavasti korkeammalla tasolla. Pc-rekisteri osoittaa luokka-alueelle, suorituksessa olevan metodin luokan metodialueelle suorituksessa olevaan tavukoodikäskyyn. Pc-rekisteri ei koskaan osoita minnekään muualle kuin jonkin metodin tavukoodikäskyyn, esimerkiksi sattumanvaraiseen tietoon jota ei ole tarkoitettu tulkittavaksi käskyksi. Kehyspinon tarkoitus on metodikutsujen toteuttaminen. Se vastaa pitkälti lohkorakenteisten kielten kutsupinoa. Kehyspino sisältää kehyksiä, joista kerrallaan yksi, pinon päällimmäinen, on aktiivinen. Yksittäinen kehys sisältää metodin suorittamista varten tarvittavia tietoja, erityisesti operandipinon, metodin paikalliset muuttujat sisältävän taulukon, ja viittauksen metodin sisältävän luokan vakioalueelle. Pinon päälle luodaan uusi kehys metodia kutsuttaessa ja se tuhotaan metodin suorituksen loputtua joko normaalisti tai poikkeuksen kautta. Luokka-alue sisältää luokkakohtaisia tietoja. Käsitteellisesti voi olla helpompaa ajatella sen sisältävän luokkia, vaikka tämä ei täysin pitäisikään paikkaansa. Java-virtuaalikoneen luokka sisältää vakiotaulukon ja metodien suoritettavan tavukoodin. Vakiotaulukko sisältää suoritusaikana tarvittavia vakioita (esimerkiksi koodissa viitattujen muiden luokkien symbolisia tai konkreettisia tunnisteita). Keko on muistialue, josta kaikki tavukoodiohjelmien ohjaamat muistinvaraukset tehdään. Muistia voidaan varata keosta ainoastaan luomalla sinne olio tai taulukko newoperaatiolla. Keon komponentit ovat luokkien ilmentymiä, olioita, jotka sisältävät vain ilmentymäkohtaisia tietoja. Esimerkiksi (sekä staattisten että ei-staattisten) metodien koodi sijaitsee luokka-alueella kyseessä olevan luokan metodialueella, ei monistettuna jokaiseen kyseisen luokan ilmentymään keossa. Java-virtuaalikoneessa on automaattinen muistinhallinta, eli se käyttää roskienke-
7 rääjää (garbage collector) vapauttamaan tarpeettomaksi jääneet muistialueet sopivaksi katsomanaan ajankohtana. Tämä voidaan katsoa sekä hyödyksi että haitaksi. Automaattinen muistinhallinta vapauttaa ohjelmoijan (tai kääntäjän) tarpeesta pitää kirjaa muistinvarauksista ja tekee muistivuodot käytännössä mahdottomiksi. Haittaa tästä voi olla ympäristöissä, joissa käytettävissä oleva muistin määrä on vähäinen ja ohjelmoija voisi eksplisiittisellä muistinhallinnalla käyttää sen paremmin hyödyksi. 3 Class-tiedostomuoto Java-virtuaalikoneelle tarkoitetut ohjelmat esitetään class-tiedostomuodossa. Classtiedosto sisältää täydellisen kuvauksen yksittäisestä luokasta tai rajapinnasta. Varsinaisen luokkamäärittelyn lisäksi class-tiedosto sisältää myös muuta tarpeellista informaatiota, kuten vakiotietuetaulukon (constant pool table). Java-virtuaalikone rakentaa annetun class-tiedoston perusteella itselleen sisäisen, suoritusaikaisen esityksen tiedoston kuvaamasta luokasta. Class-tiedosto on 8-bittisten tavujen sarja. Esittelen tässä class-tiedoston rakennetta käyttäen samaa pseudotietue -merkintätapaa kuin The Java T M Virtual Machine Specificationissa [LiY97]. Tyypit u1, u2 ja u4 määritellään tarkoittamaan etumerkittömiä yhden, kahden ja neljän tavun suuruuksia, tässä järjestyksessä. Useamman kuin yhden tavun suuruudet on koodattu big-endian -järjestyksessä. Tyyppinimet cp_info, field_info, method_info ja attribute_info määritellään tarkemmin myöhemmin (sanottakoon tässä vaiheessa, että ne ovat tietueita). Class-tiedosto on seuraavan muotoinen [LiY97, 4.1]: ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count - 1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count];
8 } u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; Tutkitaan seuraavassa hieman tarkemmin tämän tietueen sisältöä. Kenttä magic on taikaluku, joka identifioi class-tiedostomuodon. Sen arvo on heksadesimaaliluku CAFEBABE. Taikaluvun olemassaoloa voidaan perustella sillä, että esimerkiksi virtuaalikoneelle tarjotut muut kuin class-tiedostot tai korruptoituneet tiedostot voidaan hylätä heti kättelyssä. Kentät minor_version (m) ja major_version (M) yhdessä tulkitaan versionumeroksi M.m. Versionumeron tarkoitus on ilmaista mille Java-ympäristön versiolle tiedosto on tarkoitettu. Java-ympäristön ja siihen kuuluvan virtuaalikoneen tukemien class-tiedostojen versionumeroiden arvoalue on erikseen määritelty kyseessä olevan Java-ympäristön julkaisuversion standardissa. Kenttä constant_pool_count on kokonaisluku, joka on (harhaanjohtavasti) yhtä suurempi kuin tiedostossa seuraavan constant_pool-taulukon alkioiden lukumäärä. Taulukossa constant_pool on alkioita siis constant_pool_count - 1 kappaletta. Taulukko constant_pool sisältää cp_info-tyyppisiä tietueita, jotka kuvaavat erilaisia merkkijonoja, luokkien ja kenttien nimiä ja muita vakioita joihin muualla tiedostossa viitataan. Nämä cp_info-tietueet ovat seuraavan muotoisia: cp_info { u1 tag; u1 info[]; } Tietueen cp_info kenttä tag on kokonaisluku, joka koodaa kyseessä olevan vakion tyypin, esimerkiksi CONSTANT_FieldRef (kenttä) tai CONSTANT_String (merkkijono). Taulukko info tulkitaan kentän tag ilmaisemalla tavalla. Seuraavana tiedostossa on kenttä access_flags, joka koodaa luokan näkyvyysmääreet rajattuna yhdistelmänä seuraavista arvoista: public, final, super, interface, abstract. Kentät this_class ja super_class tulkitaan indekseiksi constant_pool-taulukkoon. Kyseessä olevan indeksin on osoitettava tietueeseen, joka ensimmäisessä tapauksessa
9 on tämän luokan kuvaus ja jälkimmäisessä tämän luokan yliluokan kuvaus. Mikäli tiedoston kuvaama luokka on Object, super_classin arvo on 0 (nolla). Kenttä interfaces_count on kokonaisluku, joka ilmaisee tämän luokan toteuttamien rajapintojen lukumäärän ja siten seuraavan interfaces-taulukon alkioiden lukumäärän. Taulukon interfaces alkiot ovat kokonaislukuja, joiden on oltava indeksejä constant_pool-taulukkoon ja constant_pool-taulukon kyseisessä indeksissä sijaitsevan tietueen on kuvattava kulloinkin kyseessä oleva rajapinta. Kenttä fields_count on kokonaisluku, joka ilmaisee tämän luokan kenttien lukumäärän ja siten seuraavan fields-taulukon field_info-tyyppisten tietueiden lukumäärän. Näiden field_info-tietueiden muoto on seuraava: field_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } Tietue field_info kuvaa siis kentän nimen, näkyvyysmääreet, kuvauksen (descriptor) ja kentän attribuutit. Kentän attribuutit eli ominaisuudet on kuvattu attribute_info-tietueissa, joiden muoto on seuraava: attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; } Kenttä attribute_name_index on kokonaisluku, joka tulkitaan indeksiksi tämän tiedoston constant_pool-taulukkoon. Taulukon constant_pool kyseisessä indeksissä oleva cp_info-tyyppinen tietue kuvaa attribuutin nimen. Osa attribuuteista (tarkalleen ottaen attribuuttien nimistä) on ennalta määriteltyjä osana classtiedostomuodon standardia. Kentille määriteltyjä attribuutteja ovat ConstantValue (kenttä on staattinen), Synthetic (kenttä on kääntäjän generoima eikä esiinny lähdetiedostossa) ja Deprecated (kenttä on vanhentunut). Seuraavana tiedostossa tuleva kenttä methods_count on kokonaisluku, joka ilmaisee tämän luokan metodien lukumäärän ja siten seuraavan methods-taulukon
method_info-tyyppisten tietueiden lukumäärän. Näiden method_info-tietueiden muoto on seuraava: method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } 10 Tietue method_info kuvaa siis metodin nimen, näkyvyysmääreet, kuvauksen ja attribuutit. Metodeille määriteltyjä attribuutteja ovat Code, Exceptions (kuvaa metodin aiheuttamat tarkistetut poikkeukset), Synthetic ja Deprecated. Code-nimisten attribuuttien info-taulukko tulkitaan Code_attribute-tyyppiseksi tietueeksi. Näiden Code_attribute-tietueiden muoto on seuraava: Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } Tämän tietueen tarkka muoto ja yksityiskohdat eivät ole tämän tutkielman kannalta kovin kiinnostavia. Tässä vaiheessa riittää tietää, että luokan metodien tavukoodi on luettavissa methods-taulukon method_info-tietueiden attributes-taulukon attribute_info-tietueiden info-taulukoista. Lopuksi class-tiedostosta luetaan tämän luokan attribuutit taulukosta attributes. Luokan attribuuttien muoto on sama kuin edellä kuvatuilla kentillä ja metodeilla,
11 mutta ainoat luokille määritellyt attribuuttityypit (nimet) ovat SourceFile (kuvaa lähdetiedoston josta tämä class-tiedosto on käännetty) ja Deprecated. Taikaluvun analogia class-tiedoston häntäpäässä on tiedoston loppuminen oikeassa kohdassa. Mikäli tiedosto loppuu kesken tai sen lopussa on ylimääräisiä bittejä, tiedostoa ei tulkita korrektiksi class-tiedostoksi. 4 Suoritusaikaiset tapahtumat Tyypillisessä nykyaikaisessa käyttöjärjestelmässä, johon on asennettu Java-ympäristön toteutus, esimerkiksi komentorivi java HelloWorld aiheuttaa Java-virtuaalikoneen käynnistymisen. Tämä virtuaalikone suorittaa toimet, jotka johtavat HelloWorldluokan paikallistamiseen, lataamiseen (loading), linkitykseen (linking), alustukseen (initialization) ja sen main(string[])-metodin kutsumiseen. Java-virtuaalikone aloittaa luomalla toteutuskohtaisen aloitusluokan (initial class), lataamalla sen bootstrap-lataimella ja linkittämällä sen [LiY97, 5.2]. Virtuaalikone käynnistää ensimmäisen säikeen ja kutsuu aloitusluokan main-metodia, jonka suoritus ohjaa virtuaalikoneen toimintaa tästä eteenpäin. Erityisesti se voi siis aiheuttaa muiden luokkien lataamisen, linkityksen ja niiden metodien suorittamisen. Kun jonkin luokan jotakin metodia kutsutaan, virtuaalikone tarkistaa, että kyseessä oleva luokka on ladattu, eli että virtuaalikoneella on siitä sisäinen, suoritusaikainen esitys. Jos näin ei ole, luokka on ladattava. Luokan lataaminen koostuu luokan kuvaavan class-tiedoston paikallistamisesta ja luokan suoritusaikaisen esityksen johtamisesta siitä tulkitsemalla se class-tiedostomuodon määrittelemällä tavalla. Luokka voidaan ladata joko virtuaalikoneen sisäisellä bootstrap-lataimella tai käyttäjän määrittelemällä lataimella. Käyttäjän määrittelemät lataimet ovat ClassLoaderluokan perillisiä, ja ne mahdollistavat luokkien lataamisen epätavallisilla tavoilla, esimerkiksi purkamalla ne kryptatuista tiedostoista tai lataamalla ne suoraan verkosta. Linkitys koostuu luokan verifikaatiosta (verification) ja valmistelusta (preparation). Verifikaatiolla pyritään varmistamaan luokan turvallisuus, ja se on kuvattu tarkemmin seuraavassa luvussa. Valmistelussa luokan staattiset kentät luodaan ja niiden alkuarvot asetetaan. Selvitys (resolution) voi olla osa linkitysvaihetta tai se voi tapahtua vasta suorituksen aikana. Tavukoodissa viitataan muihin luokkiin vakiotaulukossa sijaitsevien
12 viittauksien avulla. Kaikki viittaukset ovat aluksi symbolisia. Viittauksien selvityksellä tarkoitetaan prosessia, jossa symboliset viittaukset muunnetaan konkreettisiksi viittauksiksi [LiY97, 5.4.3]. 5 Verifikaatio ja poikkeukset Verifikaatio tarkoittaa suomeksi tarkistusta ja/tai varmistusta. Java-virtuaalikoneen verifikaatioalgoritmin tarkoituksena on varmistaa class-tiedostojen turvallisuus. Se pyrkii havaitsemaan potentiaalisesti vahingolliset ohjelmat ennen suoritusta ja estämään niiden suorituksen. Tämä on tärkeää etenkin verkkosivuille upotettujen sovelmien tapauksessa, jossa suoritettavaa koodia ladataan tietoliikenneverkon ylitse mahdollisesti epäluotettavista lähteistä. Java-virtuaalikone verifioi kaikki ladattavaksi tarjotut class-tiedostot ennen suoritusta, riippumatta siitä kuka sen on kirjoittanut tai millä kääntäjällä se on tuotettu. Jos kyseessä oleva tiedosto ei noudata tarkoin kaikkia class-tiedostomuodon sääntöjä, se hylätään. Kaikkien oikein toimivien ohjelmien erottaminen ennalta on ratkeamaton ongelma. Java-virtuaalikoneen verifikaatioalgoritmi ratkaisee rajatumman ongelman hylkäämällä virheellisten ohjelmien lisäksi myös osan oikein toimivista ohjelmista [Eng99, 6.5] Verifikaatioalgoritmin tehtävä on karkeasti ottaen kaksijakoinen: class-tiedoston rakenteen tarkistaminen ja tavukoodin verifikaatio. Ensimmäisessä vaiheessa varmistetaan, että tiedosto on ulkoisesti class-tiedostomuodon mukainen, eli muun muassa, että se alkaa heksadesimaaliluvulla CAFEBABE, sen versionumero on tuettu, se sisältää kaiken vaaditun informaation eikä se lopu kesken tai sen lopussa ole ylimääräisiä bittejä. Toisessa vaiheessa tutkitaan luokan metodien tavukoodia ensin pinnallisesti ja sitten tietovuoanalyysin (data-flow analysis) keinoin [LiY97, 4.9.2]. Pinnallisiin tarkistuksiin kuuluu esimerkiksi se, että hyppykäskyt eivät hyppää kyseessä olevan metodin ulkopuolelle tai jonkin käskyn keskelle. Tietovuoanalysoija tulkitsee jokaisen käskyn ja mallintaa niiden vaikutuksen operandipinolle. Esimerkiksi mikäli tarkasteltava käsky käyttää operandipinon päällä olevia operandeja, tarkistetaan, että operandipinossa olisi tällöin riittävän monta operandia ja että ne olisivat oikean tyyppisiä. Käytetyille paikallisille muuttujille tehdään vastaava tarkistus. Mikäli operandipinon tai paikallisten muuttujien taulukon viitattua arvoa ei ole olemassa tai se on väärän tyyppinen, koodi hylätään. Muutoin käskyn tila, eli operandipinon ja paikallisten muuttujien taulukon tila merkitään muistiin.
13 Seuraavaksi määritetään tarkasteltavan käskyn mahdollisten seuraajakäskyjen (successor instruction) joukko, johon kuuluu koodin järjestyksessä seuraava käsky, ehdollisen tai ehdottoman hyppykäskyn kohde tai poikkeuskäsittelijän osoite, jonka tapauksen jätän tässä käsittelemättä. Nykyisen käskyn ja jokaisen sen mahdollisen seuraajakäskyn (paitsi poikkeuskäsittelijän tapauksessa) kanssa toimitaan seuraavasti: Mikäli seuraajakäskyä ei ole vielä tarkasteltu merkitään muistiin, että käskyn tila on sama kuin edellisen käskyn tila. Muutoin nykyisen käskyn tila ja seuraajakäskyn tila yhdistetään (merge). Jotta kahden operandipinon tilat voidaan yhdistää, on niissä oltava yhtä monta arvoa ja vastaavien arvojen on oltava yhteensopivia, eli identtisiä poislukien reference-tyyppiset arvot. Muuten operandipinojen tiloja ei voida yhdistää. Paikallisten muuttujien taulukot yhdistetään vertaamalla niiden vastaavia alkioita toisiinsa. Poislukien reference-tyyppiset arvot, mikäli vastaavat alkiot eivät ole identtisiä merkitään muistiin, että kyseinen alkio on käyttökelvoton. Sekä operandipinon että paikallisten muuttujien tapauksessa reference-tyyppisten arvojen yhdiste on viittaus kyseessä olevien arvojen ensimmäiseen yhteiseen yliluokkaan, jollainen on aina olemassa (Object). Mikäli operandipinojen tiloja ei voida yhdistää, koodi hylätään. Tässä vaiheessa koodi on periaatteessa läpäissyt staattisen verifikaation. Lopuksi suoritetaan muutamia virtuaalisia (virtuaalikonekäskyillä suoritettavia) tarkistuksia, kuten kutsutun metodin olemassaolo, jotka voidaan suorittaa staattisesti tai vasta suorituksen aikana [LiY97, 4.9.1]. Kun kaikki edellä kuvatut (ja muut, The Java T M Virtual Machine Specificationissa [LiY97] kuvatut) tarkistukset on läpäisty, luokan käyttö ja sen metodien suoritus voidaan sallia. Verifikaation jälkeen koodin turvallisuudesta voidaan vetää jo melko pitkälle vieviä johtopäätöksiä. Esimerkiksi verifikaation läpäisevä tavukoodi ei voi aiheuttaa operandipinon yli- tai alivuotoa [LiY97, 4.9]. Niitä seikkoja, jotka jo tiedetään, ei tarvitse enää varmistaa suoritusaikaisilla tarkistuksilla. Virtuaalikoneen JIT-kääntäjä voi tällöin generoida suorituskykyisempää natiivikoodia. Virhetilanteet, joita ei voida havaita staattisen verifikaation keinoin käsitellään suorituksen aikana poikkeusten (exception) avulla. Esimerkki tällaisesta virhetilanteesta on indeksointi taulukon ulkopuolelle. Poikkeukset voidaan jakaa kahteen ryhmään: Tavukoodin (käyttäjän tai kirjastojen koodin) aiheuttamat poikkeukset tai virtuaalikoneen suoraan aiheuttamat poikkeukset. Poikkeukset ovat Throwable-luokan perillisiä. Luokalla Throwable on kaksi aliluokkaa, Exception ja Error. Jälkimmäisen luokan ja sen perillisten ilmentymät esittävät virheitä, joista tavallisten ohjel-
14 mien ei oleteta pystyvän toipumaan. Tämä jako on tehty siksi, että ohjelmissa olisi mahdollista käyttää catch(exception e)-rakennetta sieppaamaan kaikki virheet, joista on mahdollista toipua. Java-virtuaalikoneen suoraan aiheuttamia poikkeuksia ovat RunTimeException-, Error- tai VirtualMachineError-luokkien aliluokkia [LiY97, 2.16]. Ne kuvaavat lataus-, linkitys- ja suoritusaikaisia poikkeustilanteita ja virheitä. Luokan RunTimeException aliluokkia ovat seuraavat: ArithmeticException ArrayStoreException ClassCastException IllegalMonitorStateException IndexOutOfBoundsException NegativeArraySizeException NullPointerException SecurityException Luokan Error aliluokkia ovat seuraavat: luokan LinkageError aliluokat: ClassFormatError ClassCircularityError NoClassDefFoundError UnsupportedClassVersionError AbstractMethodError UnsatisfiedLinkError NoSuchFieldError NoSuchMethodError InstantiationError IllegalAccessError VerifyError ExceptionInInitializerError
15 luokan VirtualMachineError aliluokat: InternalError OutOfMemoryError StackOverflowError UnknownError 6 Esimerkki: Hello, world! Useimmat aloittelevat ohjelmoijat kirjoittavat ensi töikseen jonkin muunnelman Hello, world! -ohjelmasta, jonka tehtävänä on tulostaa standarditulostusvirtaan tervehdys koko maailmalle. Siitä voidaan hyvin aloittaa myös Java-tavukoodin opiskelu. Tutkitaan seuraavassa Java-kielistä Hello, world -ohjelmaa ja siitä käännettyä symbolista tavukoodia. Class-tiedoston voi purkaa symboliseksi tavukoodiksi Java Development Kitin javap-työkalulla komennolla javap -c [luokan nimi]. Java-kielinen lähdekoodi: public class HelloWorld { public static void main(string args[]) { System.out.println("Hello, world!"); } } javac HelloWorld.java -komennolla tuotettu HelloWorld.class -tiedosto näyttää heksadesimaaleina esitettynä seuraavalta: CA FE BA BE 00 00 00 32 00 1D 0A 00 06 00 0F 09 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 17 0C 00 18 00 19 01 00 0D 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53
16 79 73 74 65 6D 01 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 00 21 00 05 00 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 10 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B 00 0C 00 01 00 09 00 00 00 25 00 02 00 01 00 00 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 01 00 0A 00 00 00 0A 00 02 00 00 00 05 00 08 00 06 00 01 00 0D 00 00 00 02 00 0E Pinnallisessa tarkastelussa tiedostosta havaitaan, että se alkaa class-tiedostomuodon määrittelyn mukaisesti tunnisteella CAFEBABE ja sen versionumero on 32.0 16, joka vastaa Java-ympäristön (SE) julkaisuversiota 6.0. javap -c HelloWorld -komennoilla tuotettu symbolinen tavukoodi: public HelloWorld(); Code: 0: aload_0 1: invokespecial #1; // java/lang/object.<init> 4: return public static void main(java.lang.string[]); Code: 0: getstatic #2; // java/lang/system.out 3: ldc #3; // "Hello, world!" 5: invokevirtual #4; // java/io/printstream.println 8: return Ensimmäinen silmiinpistävä asia tavukoodissa on konstruktori public HelloWorld(), jota ei ole lähdekielisessä luokassa määritelty. Kyseessä on oletuskonstruktori, jonka kääntäjä generoi automaattisesti, sillä Java-luokalla on oltava konstruktori [LiY97, 2.12]. Main-metodin koodi ja sen selvitys: 0: getstatic #2. Tällä käskyllä noudetaan (kopioidaan) pinon päälle staattisen kentän arvo. Operandi 2 tulkitaan indeksiksi suorituksessa olevan metodin luokan vakiotaulukkoon. Kyseisen indeksin osoittamassa kohdassa olevan alkion on oltava symbolinen viittaus kenttään. Symbolinen viittaus kenttään sisältää myös viittauksen luokkaan, jossa kenttä sijaitsee. Tässä tapauksessa
kyseessä on viittaus java/lang/system-luokan java/io/printstream-tyyppiseen kenttään java/lang/system.out. Java-tavukoodissa luokkiin viitataan aina niiden koko nimellä, jotta nimiristiriidoilta vältyttäisiin. Luokan nimen perusteella Java-virtuaalikone pystyy paikallistamaan kyseisen luokan kuvaavan class-tiedoston. Jos kyseessä olevaa luokkaa ei ole vielä virtuaalikoneen tämän instanssin aikana käytetty, se täytyy ladata ja linkittää (virtuaalikoneen toimesta). 3: ldc #3. Tällä käskyllä noudetaan (kopioidaan) pinon päälle viittaus merkkijonoon Hello world!. Operandi 3 tulkitaan indeksiksi suorituksessa olevan metodin luokan vakiotaulukkoon. Kyseisen indeksin osoittamassa kohdassa olevan alkion on oltava joko int- tai float-tyyppinen arvo tai symbolinen reference-tyyppinen viittaus merkkijonovakioon. Tässä tapauksessa kyseessä on symbolinen viittaus merkkijonovakioon. Symboliset viittaukset on ennen käyttöä muunnettava konkreettisiksi viittauksiksi [LiY97, 5.4.3]. Virtuaalikone luo String-luokan ilmentymän, joka esittää Hello, world! -merkkijonoa [LiY97, 5.1]. Operandipinon päälle asetetaan konkreettinen viittaus tähän olioon. 5: invokevirtual #4. Tällä käskyllä kutsutaan metodia println(string). Operandi 4 tulkitaan indeksiksi suorituksessa olevan metodin luokan vakiotaulukkoon. Kyseisen indeksin osoittamassa kohdassa oleva alkio on symbolinen viittaus metodiin. Symbolinen viittaus muunnetaan konkreettiseksi viittaukseksi [LiY97, 5.4.3.3]. Operandipinossa on edellisten käskyjen jäljiltä päällimmäisenä viittaus metodin String-tyyppiseen argumenttiin ja sen alla viittaus luokkaan, johon metodikutsu kohdistuu. Lopuke virtual merkitsee (eistaattisten metodien tapauksessa), että metodikutsu on polymorfinen. Tämä voidaan tavukoodiohjelmissa (mutta ei Java-ohjelmissa) kiertää käskyllä invokespecial. 8: return. Tämä käsky palauttaa suorituksen kutsuneelle metodille. Javavirtuaalikoneen return-käskyt on tyypitetty metodin palautusarvon tyypin mukaan. Esimerkiksi kokonaisluvun palauttavan metodin palautuskäskyn on oltava ireturn (ja sen operandin on oltava int-tyyppiä). Return-käskyä voidaan käyttää ainoastaan metodin palautusarvon tyypin ollessa void. 17
7 Yhteenveto 18 Java-virtuaalikone on pinopohjainen abstrakti tietokone, joka suorittaa Java-tavukoodia. Se on keskeinen osa Java-ympäristöä. Se on vastuussa Java-tavukoodiohjelmien luotettavuudesta, turvallisuudesta, koodin pienestä koosta ja silti kohtuullisen suuresta suorituskyvystä. Java-tavukoodi on laitteistoriippumaton välikieli. Java-tavukoodiohjelmat esitetään laitteisto- ja käyttöjärjestelmäriippumattomassa class-tiedostomuodossa. Java-tavukoodiohjelmia suoritetaan tavallisimmin ohjelmallisella Java-virtuaalikonetoteutuksella. Java-virtuaalikonetoteutus on olemassa useille erilaisille laitteisto- ja käyttöjärjestelmäympäristöille. Java-tavukoodiohjelmat toimivat millä tahansa Java-virtuaalikoneella samalla tavalla. Ne toimivat siis perinteisistä konekielisistä ohjelmista poiketen sellaisenaan useissa erilaisissa laitteisto- ja käyttöjärjestelmäympäristöissä. Java-virtuaalikone on pinokone, mutta muuten sillä on paljon yhteistä oikeiden tietokoneiden kanssa. Java-virtuaalikoneen suoritin on säie, joita voi olla useampia kuin yksi. Java-virtuaalikoneen keskusmuistin virkaa toimittaa useampi erillinen tietoalue, joilla on omat käyttörajoitteensa. Merkittävästi oikeista tietokoneista ja niiden konekielistä poiketen Java-virtuaalikone ei tarjoa mahdollisuuksia minkä tahansa muistialueen eksplisiittiseen käsittelyyn. Esimerkiksi suorituksessa olevan ohjelman koodia ei voi millään keinolla muokata suorituksen aikana. Java-tavukoodin suorittaminen ohjelmallisella virtuaalikonetoteutuksella on konekielisten ohjelmien suorittamista raskaampaa. Nykyaikaiset Java-virtuaalikonetoteutukset nykyaikaisilla tietokoneilla saavuttavat kuitenkin jo niin korkean suorituskyvyn, ettei erolla ole useimmissa sovelluksissa merkitystä. Java-virtuaalikoneen implisiittiisiin turvallisuusmekanismeihin kuuluu sen oliopohjaisuus ja automaattinen muistinhallinta. Lisäksi Java-virtuaalikoneessa on staattinen verifikaatioalgoritmi, joka varmistaa class-tiedostojen turvallisuuden osittain jo ennen suoritusta. Java-tavukoodiohjelmat ovat siis perinteisiä konekielisiä ohjelmia luotettavampia ja turvallisempia.
Lähteet 19 All04 Allman, E., A conversation with James Gosling. App09 Java, 2009. www.apple.com/java/. [23.04.2009] Cow04 Cowell-Shah, C. W., Nine Language Performance Round-up: Benchmarking Math & File I/O, 2004. http://www.osnews.com/story/ 5602/Nine_Language_Performance_Round-up_Benchmarking_Math_ File_I_O. [23.04.2009] Eis97 Eisen, J., Executing Java Applets Using Trusted Hosts, 1997. http://www.ibm.com/developerworks/lotus/library/ls-java_ Applets_Using_Trusted_Hosts/index.html. [23.04.2009] Eng99 Engel, J., Programming for the Java T M virtual machine. Addison- Wesley, 1999. Gol74 Lis09 Goldberg, R., A survey of virtual machine research. List of Java virtual machines, 2009. http://en.wikipedia.org/wiki/ List_of_Java_virtual_machines. [23.04.2009] LiY97 Lindholm, T. ja Yellin, F., The Java T M Virtual Machine Specification, Second Edition. Tekninen raportti, Sun Microsystems, Inc., 1997. URL http://java.sun.com/docs/books/jvms/second_ edition/html/vmspectoc.doc.html. SmN05 Sta06 Smith, J. ja Nair, R., The Architecture of Virtual Machines. Stallings, W., Computer Organization & Architecture - Designing for Performance. Prentice Hall, 2006. Sun09b Java SE Downloads, 2009. http://java.sun.com/javase/ downloads/index.jsp. [23.04.2009] Sun09a Learn About Java Technology, 2009. http://java.com/en/about/. [23.04.2009] Sun09c What components of the JDK software have been open sourced?, 2009. http://www.sun.com/software/opensource/java/faq.jsp# b2. [23.04.2009]
20 Usa09 Usage share of desktop operating systems, 2009. http: //en.wikipedia.org/wiki/usage_share_of_desktop_operating_ systems. [23.04.2009]