Notiuni generale
Masina virtuala este un calculator imaginar, dotat cu un set de instructiuni ce constituie limbajul (codul) virtual.
Lucrul cu cod virtual decurge astfel: textul sursa este tradus de catre compilator in limbaj virtual; programul rezultat constituie intrare pentru o procedura numita executiv, care este de fapt un interpreter al limbajului virtual. Executivul este scris intr-un limbaj recunoscut de calculatorul tinta (cel pe care urmeaza sa ruleze programul compilat). Rolul executivului este acela de a parcurge codul virtual obtinut de la compilator si de a executa fiecare instructiune, in termenii limbajului masina al calculatorului tinta .
Avantajul acestui mod de lucru este acela ca daca un limbaj
sursa trebuie tradus in mai multe limbaje obiect, compilatorul propriu-zis
se scrie o singura data (el genereaza doar cod virtual), iar pentru fiecare
limbaj obiect se construieste cate un executiv. A scrie un executiv este
un lucru mult mai usor decat a scrie un compilator. Pe de alta parte, programul
generat in cod virtual poate fi transportat pe orice masina dotata cu interpreterul
codului respectiv, deci programul are o portabilitate crescuta.
Compilatoarele de Java, spre exemplu, genereaza cod virtual
(numit byte-code). Astfel, un applet, care este de fapt un program Java
compilat poate fi incarcat si executat de catre un browser de web dotat
cu interpreter de byte-code, chiar in conditiile in care applet-ul si browser-ul
se afla pe calculatoare care functioneaza sub sisteme de operare diferite.
Un dezavantaj al lucrului cu cod virtual este acela ca viteza de
executie a programelor respective este mai mica, deoarece ele sunt
executate "software" (prin intermediul interpreterului) si nu "hardware"
(direct de catre procesor).
Limbajul virtual si structura masinii virtuale sunt stabilite in principiu de catre proiectantul compilatorului, dupa urmatoarele criterii:
Arhitectura masinii virtuale
In cele ce urmeaza vom descrie o masina virtuala simpla (fig.10.1) la a carei conceptie s-a tinut cont de specificul limbajului sursa prezentat in Anexa B. Pentru aceasta masina se propune un limbaj virtual prezentat in Anexa C.
Masina este compusa dintr-o unitate
centrala si o memorie operativa.
Unitatea centrala este dotata cu urmatorii registri:
Memoria operativa cuprinde urma toarele structuri:
Trebuie mentionat faptul ca cele trei tabele enumerate
mai sus reprezinta practic interfata dintre compilator si executiv. Aceste
tabele sunt completate de catre compilator si apoi utilizate de executiv.
Tabela TAB_ERR este completata partial de compilator (prima
parte a tabelei) si partial de executiv. Acest lucru se intampla deoarece
erorile la executie pot fi de doua feluri:
Se poate spune ca cele trei tabele formeaza impreuna programul
obiect.
Functionarea masinii virtuale
Este simulata prin intermediul executivului care este descris mai jos in pseudocod:
procedure EXECUTIV isValorile cu care se initializeaza registrii NI si SP, respectiv indicele primei intrari libere din TAB_ERR se afla memorate la inceputul tabelei de cod, ele fiind depuse acolo de catre compilator (v. Lucrarea nr.11).*completeaza tabela TAB_ERR incepand cu prima intrare liberaend EXECUTIV
NI = *adresa de start a programului principal
SP = *dimensiunea spatiului variabilelor din programul principal
ST = 'activ'
VBAZA = 0, BAZA[0].LEVEL = 1, BAZA[0].BLOC = 0
repeatselectTAB_COD[NI] ofuntil ST <> 'activ'LOD: *interpreteaza LODendselect
LODI: *interpreteaza LODI. . . *se insira toate codurile
default: *eroare la executie 'instructiune nerecunoscuta '
if ST = 'err' then*afiseaza mesajul din TAB_ERR [ IE ]endif
Obs: eroarea de tip 'instructiune nerecunoscuta' face parte din categoria celor detectate de executiv. Ea ar putea sa apara fie din cauza unei functionari incorecte a compilatorului, care ajunge sa completeze TAB_COD in mod necorespunzator, fie ca urmare a coruperii zonei de memorie in care se afla TAB_COD. La detectarea unei erori de executie de catre executiv, se va pozitiona registrul IE astfel incat sa indice un mesaj adecvat, iar registrul ST pe valoarea err, determinandu-se astfel parasirea buclei din procedura EXECUTIV.Pentru a se ilustra modul de implementare in cadrul executivului a executiei unei instructiuni virtuale, se iau ca exemplu instructiunile EQU si CALL:
selectTAB_COD[NI] ofObs: in secventa corespunzatoare instructiunii CALL, elementele de forma TAB_COD[NI + ...] reprezinta argumentele instructiunii.
. . .EQU:endselectSP = SP - 1CALL:
if STIVA[SP + 1] = STIVA[SP] thenSTIVA[SP].INFO = 1elseSTIVA[SP].INFO = 0endif
STIVA[SP].TIP_NOD = 'intreg'
NI = NI + 1VBAZA = VBAZA + 1
BAZA[VBAZA].LEVEL = TAB_COD[NI + 3]
BAZA[VBAZA].BLOC = SP - TAB_COD[NI + 2] + 1
SP = SP + STIVA[BAZA[VBAZA].BLOC -1].INFO
STIVA[BAZA[VBAZA].BLOC - 1].INFO = NI + 4
NI = TAB_COD[NI + 1]
. . .
Desfasurarea lucrarii
Se va proiecta un executiv pentru limbajul virtual propus
in Anexa C. Testarea executivului se va realiza astfel: se completeaza
manual, intr-un fisier, o tabela de constante si o tabela de cod. In aceasta
din urma se pun instructiuni virtuale intr-o ordine oarecare, avand insa
grija la instructiunile de salt, deoarece se poate ajunge in situatii de
buclare infinita .
Executivul va incarca tabela de constante si pe cea de
cod din fisier, apoi va prelucra fiecare instructiune afisand totodata
informatii de control care sa permita urmarirea continutului stivelor (STIVA
si BAZA) si al registrilor masinii.
Se recomanda ca, pentru instructiunile care implica adaugari
de noduri in stivele masinii virtuale sa se prevada verificari privind
depasirea spatiului alocat stivelor. Situatiile de depasire vor constitui
erori de executie.