Your SlideShare is downloading. ×
Inferno Limbo Italian
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Inferno Limbo Italian

349
views

Published on

co-authors: Scola Davide and Maia Nicoletta …

co-authors: Scola Davide and Maia Nicoletta

Small workshop on Inferno, Limbo and the Dis virtual machine.
Inferno is a new operative system developped for creation and support of network systems and distribuited services.
There are three fundamental programming principles: all resources are files in a hierarchic file system, the network is a unic namespace like a file system hierarchic, it uses Styx that is a standard protocol of comunication for local and remote resources.
Limbo is the programming language for the Inferno OS.
The language is Object Based, you can compile it or interpret it with the Dis virtual machine (like Java virtual machine with a JIT compiler).
Limbo has a native support for: array, string, int, float, tuple (like record), channel (linda-like), and other...
The Limbo's channels are used to comunicate with other processes or with thread.
The Dis virtual machine is an environment for Limbo programs and it has important features: CISC architecture, memory-to-memory, many high level types, just in time compiler, ecc...
In the end of presentation there is a comparison between Dis, Java VM and C# .Net VM.


0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
349
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Inferno, Limbo e la Dis Virtual Machine Minetti Scola Maia Alberto Davide Nicoletta
  • 2. Inferno: One HOT OS
    • Inferno è un nuovo sistema operativo progettato per la creazione ed il supporto di sistemi di rete e servizi distribuiti.
    Il nome, come anche quello della ditta che lo produce, Vita Nuova Holdings, è stato ispirato dalle opere letterarie di Dante Alighieri, in particolare la Divina Commedia.
  • 3. Inferno
    • Sviluppato dai ricercatori Rob Pike e Phil Winterbottom del Computing Science Resarch of Bell Labs (Lucent Technologies).
    • Nasce nel 1995 da un altro progetto: Plan 9.
    Plan 9 fu plasmato come il successore di Unix nei Bell Labs sotto il supporto di Dennis Ritchie.
  • 4. Inferno: 3 principi di programmazione
    • Le risorse sono File con un fs gerarchico.
    • La visione della rete è un namespace unico e coerente che si presenta come un filesystem gerarchico, ma che può corrispondere a risorse fisicamente distinte, locali o remote che siano.
    • Styx: protocollo standard di comunicazione utilizzato per accedere a tutte le risorse locali o remote.
  • 5. Inferno: scopo
    • Il suo scopo è quello di facilitare la creazione ed il supporto di servizi distribuiti e di applicazioni di rete.
    • In funzione di questo obbiettivo:
    • Semplifica la gestione dei thread e della comunicazione di essi.
    • Indipendente dall’architettura.
    • Può essere eseguito su dispositivi con meno di 1MB di RAM.
    • Le applicazioni sono scritte nel nuovo linguaggio Limbo.
    • Supporta la compilazione Just-In-Time.
    • Kernel e driver scritti in C.
  • 6. Inferno: Tutto è un file!!
    • La particolarità di Inferno è che vede tutto come file ma, diversamente da Unix, sono tutti allo stesso livello. Questo fa si che possono essere esportati non solo file “regolari” ma anche device, affinchè sistemi remoti li vedano come proprie risorse.
  • 7. Inferno: portabilità
    • Può essere eseguito in due modi: Hosted e Nativo.
    • Hosted su:
    • Win95, Win2000, WinNT, WinXP, Solaris, FreeBSD, MacOS X, Irix, Linux, AIX, HP/UX, Plan 9.
    • Nativo su:
    • x86, Intel XScale, Sparc, MIPS, ARM, HP-PA, AMD.
  • 8. Styx
    • Styx è un protocollo di rete sviluppato per Plan 9.
    • I file rappresentano finestre, connessioni, processi e qualsiasi cosa che sia utilizzabile.
    • Tutte le comunicazioni di Inferno, locali e remote, sono compiute utilizzando il protocollo Styx. Tutti i messaggi sono operazioni su file.
    • Permette il caching e supporta file virtuali (per esempio /proc per rappresentare i processi) [diversamente da NFS].
    • Styx è open, sono disponibili implementazioni per diversi linguaggi: C, Lisp, TCL, C#, Java, PHP, Ocaml, Python, Ruby.
  • 9. Styx: operazioni
    • Styx ha solo 14 operazioni:
    • attach, auth – messaggi per stabilire una connessione
    • clunk – libera un descrittore di file
    • error – restituisce un errore
    • flush – elimina un messaggio orfano
    • open, create – prepara un file descriptor per operazioni di I/O
    • read, write – operazioni di lettura e scrittura
    • remove – elimina un file da un server
    • stat, wstat – ottiene/modifica gli attributi di un file
    • version – negozia la versione del protocollo
    • walk – naviga un albero di directory
    http://www.vitanuova.com/inferno/man/5/INDEX.html
  • 10. Styx: connessione remota TCP
    • Dobbiamo stabilire una connessione con un server remoto di cui conosciamo l’indirizzo ip.
    • Apro /net/tcp/clone in lettura e leggo una stringa che specifica una directory che rappresenta un nuovo unico canale TCP/IP (ad esempio /net/tcp/43)
    • Per stabilire la connessione scrivo il messaggio connect “indirizzo!porta” sul control file /net/tcp/43/ctl
    • La connessione e` realizzata leggendo e scrivendo sul file /net/tcp/43/data
    • Ovviamente la connessione al server DNS viene realizzata nello stesso modo.
  • 11. Limbo
    • Limbo è il linguaggio di programmazione per scrivere applicazioni su Inferno.
    • Sviluppato nei Bell Labs disegnato per sistemi distribuiti, è il successore diretto del linguaggio Alef, il linguaggio di Plan 9.
    • Procedurale che usa il concetto dei Moduli (con interfaccie e implementazione separate che aiutano lo sviluppatore a creare applicazioni strutturate).
    • Fortemente type-safe!
  • 12. Limbo (2)
    • Il compilatore Limbo produce codice oggetto (come il BYTECODE di Java o il CIL di C#) multipiattaforma, che viene interpretato dalla macchina virtuale Dis o compilato prima dell'esecuzione per migliorarne le prestazioni.
    • Può essere compilato in codice nativo, senza utilizzare la macchina virtuale
    • Limbo non è un linguaggio OO.
    • È Object Based (come Modula-2)
    • Supporto compilazione separate.
  • 13. Object Based
    • I moduli hanno stesse proprietà degli oggetti (variabili, quindi uno stato, e funzioni) ma senza inheritance ne polimorfismo.
    • La principale differenza tra OO e OB è che il primo prevede anche un meccanismo di delegation , cioè si duplica un oggetto e si aggiungono metodi o campi.
    • La delegation è sinonimo di Inheritance.
    • Il linguaggio Self fa ampio uso di Delegation.
  • 14. Caratterizzazione secondo Cardelli e Wegner
    • Secondo questa caratterizzazione Limbo è Monomorfico .
    • Alcune eccezioni alle regole del monomorfismo sono:
    • Overloading: l’operatore + è applicabile sia ad interi che a float (inoltre concatena 2 stringhe)
    • Coercion: se un’operazione si aspetta un parametro di tipo float e viene passata una variabile di tipo intero, essa viene convertita automaticamente
    • Value sharing: nil è una costante che può essere assegnata a tutti i puntatori
    • Inclusion: è ottenibile dichiarando in un modulo una variabile da cui si vuole “ereditare” e ridefinendone le funzioni (richiamandole su tale variabile)
    • On Understanding Types,Data Abstraction, and Polymorphism (L.Cardelli, P.Wegner) 1985
    • http://www.csc.lsu.edu/~gb/csc7101/Handouts/p471-cardelli.pdf
  • 15. Limbo: come si presenta
    • Dichiarazioni come Pascal.
    • Statement e espressioni come C.
    implement Command; include "sys.m"; sys: Sys; include "draw.m"; include "sh.m"; init(nil: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; sys->print("Hello World!n"); } Hello World in Limbo i, j: int = 1; r, s: real = 1.0; x: int = 1; y := 1; #dichiaraz. e assegnaz. func(radius: int, angle: int): int proc(parameters: string) Declaration Examples in Limbo
  • 16. Limbo: tipi primitivi
    • Diversamente da C ha un’ampia scelta di tipi primitivi:
    • Inoltre:
    • Supporto per thread
    • Supporto per comunicazione
    • Non supporta i puntatori
    Byte (8 bit unsigned) Short word (16 bit ...) Int (32 bit signed) Short float (32 bit floating point) Big (64 bit unsigned) Real (64 bit floating point IEEE) List Array String Tuple (ordered collection of items) Channel (for inter-process communication) Adt (Abstract Data Type like a C record) Pick (discriminated union type) Module Primitive Data in Limbo
  • 17. Limbo: array
    • Allocati dinamicamente sullo heap e referred.
    • Ad ogni assegnamento o ad ogni passaggio come parametro ad una funzione viene passato il reference.
    Slice : sub-array con un index-range e riferimento all’array originale. a : array [4] of int; a[0]=1; a[1]=2; a[2]=3; a[3]=4; slice := a[1:2]; #slice contiene [2; 3] Arrays in Limbo
  • 18. Limbo: Adt
    • Abstract Data Type è simile ad un record del Pascal / struct del C.
    • Molto simile a classi C++.
    • NO Inheritance.
    • NO polimorfismo.
    • NO delegation.
    Riferimento a se stesso, come il this, sintassi simile al Perl Point: adt { x, y: int; add: fn (p: Point, q: Point): Point; eq: fn (p: Point, q: Point): int; }; Rect: adt { min, max: Point; contains: fn(r: self Rect, p: Point): int; }; Rect.contains(r: self Rect, p: Point){...} ... r1: Rect; p1: Point; ... if (r1.contains(p1)) ... Adt in Limbo
  • 19. Limbo: tuple
    • Collezione ordinata di elementi.
    • Simile ad una struct senza nome in C.
    • Sono un tipo primitivo quindi possono essere utilizzate come variabili, parametri di funzione e valori di ritorno di funzione.
    Tuple with functions in Limbo Table: adt { ... lookup: fn(ht: self ref Table, name: string) : (int, string); }; Table.lookup(ht: self ref Table, name: string) : (int, string) { ... if (tname == name) return (1, tval); return (0, ""); } nvtab = Table.alloc(101); # make a Table nvtab.add("Rob", "Pike"); nvtab.add("Howard", "Trickey"); (p, phil) := nvtab.lookup("Phil"); (q, sean) := nvtab.lookup("Sean");
  • 20. Limbo: Liste
    • Linked-type items (simile a Lisp).
    • Operatori per le Liste:
    • hd ritorna il valore del primo membro della lista.
    • tl ritorna la parte della lista dopo il primo membro.
    • :: infisso è usato per costruire la lista.
    sys: Sys = load Sys Sys->PATH; iCount: int = len argv; while( iCount-- > 1 ) { sys->print("%s ", hd( argv = tl argv )); } sys->print("n"); List Operators in Limbo stuff: list of int; ... stuff = 30 :: (20 :: (10 :: stuff)); (head,tail) := (hd stuff, tl stuff); :: operators in Limbo
  • 21. Limbo: chan
    • Un channel è un meccanismo di comunicazione capace di inviare e ricevere oggetti di un tipo specificato ad un altro agente nel sistema.
    • L’operatore <- serve per scrivere / leggere un canale.
    Se il canale è vuoto e si tenta di leggere il programma aspetterà finchè qualcosa non verrà inviato su quel canale. Se non ci sono riceventi e si tenta di scrivere il mittente si blocca. chan utilizzabili per sincronizzare più thread c: chan of (int, string); c <- = (123, “Hello!”); #scrittura (num, stringa) = <- c #lettura chan in Limbo
  • 22. Limbo: chan particolarità L’operatore <- può prendere come argomento un array di canali. Limbo fornisce l’ alt statement, la sua struttura è simile a quella di un case . a: array [2] of chan of string; a[0] = chan of string; a[1] = chan of string; . . . ( i , s) := <- a; # s has now the string from channel a[ i ] array di chan in Limbo outchan := chan of string; inchan := chan of int; ciclo: while(){ alt { i := <-inchan => if(i==0) break ciclo; sys->print(&quot;Received %dn&quot;, i); outchan <- = &quot;message&quot; => sys->print(&quot;Sent the messagen&quot;); } } alt in Limbo
  • 23. Limbo: alt statement Utilizzando * il programma non viene bloccato, se nessun canale è ready viene eseguito lo statement corrispondente a * . Lo statement alt testa la possibilità di leggere o scrivere (dipende dall’operatore) su ogni canale al suo interno, se nessun canale è pronto il programma si blocca e aspetta che un canale sia pronto, poi viene scelto casualmente un canale che è ready e il controllo viene associato al suo statement. Questo statement è simile a select() e a poll() in Unix. alt { (a, b) = <- ch1 => …; (a, b, c) = <- ch2 => …; k = <- ch3 => …; * => …; } alt in Limbo
  • 24. Chan Linda-like
    • L’idea dei canali utilizza il modello di coordinazione Linda:
    • Linda fornisce una memoria associativa di oggetti in cui sono contenuti i dati: il tuple space .
    • I processi, quando hanno informazioni da comunicare, generano oggetti di dati strutturati a tuple (i quali poi vengono memorizzati nel tuple space), mentre, quando devono ricevere informazioni, leggono o consumano gli stessi oggetti dal tuple space.
    • Un tuple space è una specie di file: le tuple sono oggetti persistenti (questi possono essere letti o scritti in un file) e immutabili (sono modificabili solamente rimuovendo una vecchia tupla e aggiungendone una aggiornata ).
    • Le funzioni di lettura e scrittura sono ATOMICHE
    • Linda è adatto ad applicazioni scritte in linguaggi diversi, poiché il suo modello di coordinazione non fa riferimento ad alcun linguaggio in particolare
    • Abbiamo implementazioni in C, C++, Java, Prolog, Ruby, Python, Lisp, Smalltalk
  • 25. Limbo: spawn
    • spawn crea un nuovo thread asincrono, indipendente dal thread creatore che chiama la funzione definita da fn.
    • I due thread, padre e figlio, hanno uno spazio comune di memoria che contiene le variabili globali al modulo corrente.
    spawn function(20, (“nuovo”, 5.2)); function(x :int, (s :string, h :real)) :void{ ... } spawn in Limbo
  • 26. Limbo: module
    • I programmi in Limbo sono organizzati in moduli.
    • Un modulo contiene dichiarazione: tipi esportati, costanti, funzioni e definisce l’implementazione.
    • I moduli sono caricabili a run-time.
    • Quando un modulo viene caricato deve essere assegnato ad una variabile dello stesso tipo.
    • È permesso passare istanze di un modulo ad una funzione.
  • 27. Limbo: modulo di esempio implement Tennis; include &quot;sys.m&quot;; sys: Sys; include &quot;rand.m&quot;; rand: Rand; include &quot;draw.m&quot;; Tennis: module { init: fn (nil: ref Draw->Context, argv: list of string); }; init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; rand = load Rand Rand->PATH; field:= chan of int; gpid := sys->pctl(Sys->NEWPGRP, nil); rand->init( sys->millisec() ); spawn opponent(field, gpid); while( 1 ) { serve(&quot;Nadal&quot;, gpid, field); receive(&quot;Nadal&quot;, gpid, field); } } serve(who: string, gpid: int, field: chan of int) { ball := rand->rand(100); sys->print(&quot;%s[%d]: servo %dn&quot;, who, gpid, ball); field <-= ball; } receive(who: string, gpid: int, field: chan of int) { ball := <-field; sys->print(&quot;%s[%d] ricevo %d &quot;, who, gpid, ball); if( ball > 80 ) { sys->print(&quot;HO PERSO!n&quot;); killpgroup(gpid); } sys->print(&quot;n&quot;); } killpgroup(gpid: int) { sys->fprint( sys->open(&quot;/prog/&quot; + string gpid + &quot;/ctl&quot;, Sys->OWRITE), “killgrp&quot;); exit; } opponent(field: chan of int, gpid: int) { while( 1 ) { receive(&quot;Federer&quot;, gpid, field); serve(&quot;Federer&quot;, gpid, field); } } Due thread che giocano a tennis in Limbo 
  • 28. Limbo: modulo Monitor # Mon.m – Interfaccia al modulo Monitor Mon: module { PATH: con &quot;/dis/lib/Mon.dis&quot;; Monitor: adt { create: fn(): Monitor; lock: fn(m: self Monitor); unlock: fn(m: self Monitor); ch: chan of int; }; }; # Mon.b – Implementazione del Monitor implement Mon; include &quot;Mon.m&quot;; Monitor.create(): Monitor { m := Monitor(chan of int); spawn lockproc(m.ch); return m; } Monitor.lock(m: self Monitor) { m.ch <- = 0; } Monitor.unlock(m: self Monitor) { <- m.ch; } lockproc(ch: chan of int) { for (;;) { <- ch; # wait for someone to lock ch <- = 0; # wait for someone to unlock } } Implementazione di un Monitor per la concorrenza in Limbo
  • 29. Limbo: utilizzo del Monitor
    • Possono essere istanziate multiple istanze di un modulo, ognuna mantiene i propri dati ma condivide il codice con le altre istanze.
    Per utilizzare un modulo è necessario assegnarlo ad una variabile. include &quot;Mon.m&quot;; mp: Mon; Monitor: import mp; mp = load Mon Mon->PATH; l := Monitor.create(); . . . l . lock(); # region of code to be protected; # only one thread can execute here at once. l . unlock(); utilizzo del Monitor in Limbo
  • 30. Limbo: Reference e Indirections
    • Se e è un adt , allora ref e è di tipo ref adt il cui valore referenzia un adt anonimo con valore e .
    • L’operatore * deferenzia un handle.
    L’operatore ref è diverso dall’operatore unario & di C; ref crea un nuovo oggetto e ritorna un handle a quest’ultimo, piuttosto che generare un handle all’oggetto esistente. Point: adt { ... }; p: Point; pp: ref Point; p = Point(1, 2); pp = ref p; # pp is a new Point; *pp has value (1, 2) p = Point(3, 4); # This makes *pp differ from p *pp = Point(4, 5); # This does not affect p Ref e * con un adt in Limbo
  • 31. Limbo: approfondimento ref Non fa quello che ci si aspetta A: adt {n: int;}; f(a: ref A){ a.n = 100; } init(){ a: A; a.n=50; f(ref a); sys->print(&quot;%dn&quot;, a.n); } Questo codice non stampa “100”! Equivale a questo codice C: a = malloc(sizeof(A)); b = malloc(sizeof(A)); memcpy(b, a, sizeof(A)); f(b); Questo codice è giusto A: adt {n: int;}; f(a: ref A){ a.n = 100; } init(){ a:= ref A; a.n = 50; b:= a; f(b); sys->print(&quot;%dn&quot;, a.n); } Questo codice stampa “100”! Implementazione di una semplicissima bash in Limbo
  • 32. Limbo:un interprete dei comandi
    • 1 implement Command;
    • 2 include &quot;sys.m&quot;;
    • 3 include &quot;draw.m&quot;;
    • 4 sys: Sys;
    • 5 stdin: ref Sys->FD;
    • 6 Command: module
    • { init: fn(nil: ref Draw->Context,
    • nil: list of string);};
    • init(ctx: ref Draw->Context,
    • nil: list of string){
    • 14 buf := array[256] of byte;
    • 15 sys = load Sys Sys->PATH;
    • 16 stdin = sys->fildes(0);
    • 17 for(;;) {
    • 18 sys->print(&quot;$ &quot;);
    • 19 n := sys->read(stdin, buf, len buf);
    • if(n <= 0) break;
    • 22 (nw, arg) :=
    • sys->tokenize(string buf[0:n], &quot; tn&quot;);
    • 23 if(nw != 0)
    • 24 exec(ctx, arg);
    • 25 }
    • 26 }
    • exec(ctx: ref Draw->Context,
    • args: list of string)
    • 28 {
    • 29 c: Command;
    • 30 cmd, file: string;
    • 31 cmd = hd args;
    • 32 file = cmd + &quot;.dis&quot;;
    • 33 c = load Command file;
    • 34 if(c == nil)
    • 35 c = load Command &quot;/dis/&quot;+file;
    • 36 if(c == nil) {
    • 37 sys->print(&quot;%s: not foundn&quot;, cmd);
    • 38 return;
    • 39 }
    • 40 c->init(ctx, args);
    • 41 }
    Implementazione di una semplicissima bash in Limbo
  • 33. Limbo: librerie standard
    • Sys (for system functions)
    • Draw (for graphics types and functions)
    • Tk (for interface toolkit)
    • Bufio (buffered I/O package)
    • Regex (for Regular Expression)
    • Math (for mathematical functions)
  • 34. Limbo: Codice e sintassi importazione di moduli Definizione dell’interfaccia del modulo Hello Contesto grafico command-line arguments Impl del metodo Per convenzione ogni dichiarazione di modulo include un Pathname costante che punta al codice per il modulo implement Hello; include &quot;sys.m&quot;; sys: Sys; include &quot;draw.m&quot;; Hello: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; sys->print(&quot;hello, worldn&quot;); } File .b => “Hello World” Limbo di esempio
  • 35. Limbo: Hello World grafico implement Hello2; include &quot;sys.m&quot;; sys: Sys; include &quot;draw.m&quot;; draw: Draw; include &quot;tk.m&quot;; tk: Tk; Hello2: module{ init: fn(ctxt: ref Draw->Context, argv: list of string);}; init(ctxt: ref Draw->Context, argv: list of string){ sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; t := tk->toplevel(ctxt.screen, &quot;&quot;); tk->cmd(t, &quot;button .b -text {hello, world}&quot;); tk->cmd(t, &quot;pack .b&quot;); tk->cmd(t, &quot;update&quot;); sys->sleep(10000); # wait 10 seconds} File .b => “Hello World” grafico Limbo
  • 36. Limbo: altri esempi
    • Altri Esempi si trovano qui:
    • http://www.vitanuova.com/inferno/papers/descent.html
    • Manuale e Esempi Limbo:
    • http://www.cs.rit.edu/~ats/inferno/
  • 37. Conclusioni su Limbo
    • Limbo ha importato tecniche già presenti in altri linguaggi:
    • Lisp ( McCarthy ‘59) per le liste
    • Pascal ( Wirth ‘73) per le dichiarazioni
    • C ( Ritchie & Thompson ‘83) per gli statements
    • Modula-2 ( Wirth, ‘85) per il concetto di modulo
    • Linda per i channel
    • Alef ( Winterbottom, ’92 ) è il linguaggio di Plan 9
    • A sua volta Alef deriva da Newsqueak che deriva dal linguaggio formale CSP (Hoare ‘78) che descrive le interazioni tra processi concorrenti.
    • Alef vanta di essere il linguaggio preferito di Ritchie (fonte: Wikipedia).
  • 38. Dis Virtual Machine
    • Ambiente di esecuzione dei programmi scritti in Limbo.
    • Rappresentazione architettura-indipendente del codice.
    • Memory-to-memory.
    • Modella architettura CISC.
    • Macchina a tre operandi.
    • Supporta grande varietà di tipi ad alto livello.
    • Quando il codice deve essere eseguito può essere convertito in un formato più efficiente.
  • 39. Dis: memory-to-memory
    • Conservazione dei registri general purpose nella memoria esterna anzichè all'interno della CPU.
    • Un unico registro &quot;workspace&quot; (WP) punta al set di registri memorizzato nella RAM cosicchè l'esecuzione di una subroutine o di un interrupt comporta l'aggiornamento del solo registro WP.
    • Su altre VM è necessario il salvataggio dell'intero set di registri per compiere un context switch.
    • Tale caratteristica era sensata un tempo negli anni 70-80 in quanto le memorie RAM erano spesso più veloci delle CPU. Il risultato finale si traduceva in una più veloce risposta agli interrupt, così come la gestione delle subroutine.
    • Nel caso di una macchina astratta i registri sono comunque mappati in RAM.
  • 40. Esempio: memory-to-memory PC = 17 old_WP = 0x03 FP = 0x95 MP = 0xB0 0x1C 0x1B 0x1A 0x19 0x18 0x17 0x16 0x15 0x14 0x13 0x12 0x11 0x10 CPU 0x1C WP: PC = 86 old_WP = 0x1C FP = 0x88 MP = 0xB0 0x18 PC = 95 PC = 18 ... 17: a:= function(x, y, z); 18: ... ... 85: function(x, y, z: int): Point { 86: if(...) ... ... 95: return p; } Adt in Limbo WP
  • 41. Dis e altre VM Caratteristiche Dis Java C# .Net Codice oggetto BYTECODE BYTECODE CLI Virtual Machine Reg-Based Stack-based Stack-based Obj-Oriented No, ma OB si si Tipi di base tanti pochi pochi Concetto thread nativo java.lang.Thread System.Threading Carica/Scarica modulo dinamicamente si no no Garbage Collector
    • solo RF
    • solo MS
    • RF+MS
    Scelto dall’ implementazione Mark and sweep
  • 42. Dis: Garbage Collector
    • Ogni implementazione ha la possibilità di scegliere se usare il reference counter o il mark and sweep.
    • Quando si usa il reference counter i puntatori sono un tipo speciale di operandi e dovrebbero essere manipolati solo usando apposite istruzioni per evitare difetti nella gestione della memoria. Ogni locazione di memoria che mantiene un puntatore deve essere conosciuta, solo così l’interprete può inizialiare e deallocare correttamente.
  • 43. Dis: struttura del codice
    • Il codice non è accessibile dalle istruzioni.
    • PC sono offset contati in istruzioni dall’inizio.
    Dis: struttura della memoria Indirizzata come bytes. I dati che non occupano esattamente un multiplo di un byte vengono riepiti con padding.
  • 44. Dis: indirizzamento
    • Un thread ha accesso a due regioni di memoria dati indirizzabile:
    • Module pointer : punta ad una locazione del global storage per il modulo.
    • Frame pointer : punta al record di attivazione o al frame per il thread.
    • mp e fp possono venire modificate solo dalle istruzioni call e return.
  • 45. Dis: istruzioni
    • Macchina a tre operandi
    • op src1 , src2 , dst
    • Ogni operando* può indirizzare i dati in tre modi diversi:
    • Indiretto
    • Immediato
    • Doppia Indirezione
    • * src2 non può utilizzare la doppia indirezione
    10(fp) indirect dal registro fp 20(mp) indirect da mp $0x123 immediate value 10(20(fp)) double indirect rispetto a fp 10(20(mp)) double indirect rispetto a mp
  • 46. Dis: dimensione degli operandi La dimensione e il tipo degli operandi sono specificati dall’ultimo carattere dell’istruzione. carattere dimensione W Word (32 bit) B Byte (8 bit) F Float (64 bit) L LongInt (64 bit) P puntatore addx - Add Syntax: addb src1, src2, dst addf src1, src2, dst addw src1, src2, dst addl src1, src2, dst Function: dst = src1 + src2 Istruzione ADD in Dis
  • 47. Dis: Add strings
    • Poichè Limbo manipola tipi complessi come tipi primitivi la macchina virtuale ha bisogno di istruzioni ad hoc.
    • Per esempio la addc concatena due stringhe:
    addc - Add strings Syntax: addc src1, src2, dst L’istruzione addc concatena le due stringhe Unicode puntate da src1 e src2; il risultato è puntato da dst. Istruzione di concatenamento di stringhe in Dis
  • 48. Ulteriore confronto tra JVM e Dis
    • JVM è una stack-based virtual machine.
    • ADD
    • Dis è una register-based virtual machine.
    • ADD src1, src2, dest
  • 49. Architettura a stack
    • HW: prima degli anni 80.
    • VM: JVM, .NET, Pascal P-machine, ecc...
    • Le istruzioni non hanno operandi.
    • Operandi impliciti presi dallo stack.
    • esempio: Istruzione ADD
    Somma i primi due dati nello stack e memorizza il risultato in cima allo stack o fa lo store in un’altra posizione x = a + b + c LOAD a  # push a onto stack LOAD b ADD      # pop 2 elements, add them, push the result LOAD c ADD STORE x ADD in VM stack-based
  • 50. Architettura a registri
    • HW: dopo gli anni 80.
    • VM: Dis, Lua5, Parrot (Perl6, Perl, ...), ecc...
    • Operandi espliciti i cui valori sono nei registri.
    • esempio: Istruzione ADD
    Somma due registri e salva il risultato in un nuovo registro x = a + b + c ADD temp, a, b   # temp = a + b ADD x, temp, c ADD in VM register-based
  • 51. VM stack-based
    • L’Algoritmo che genera il bytecode è semplice.
    • Bytecode piccolo (perchè non abbiamo gli operandi).
    • Bisogna manipolare gli operandi impliciti (es. Incrementare e decrementare TOS) .
    • Si presta poco ad essere implementata efficacemente su macchine a registri:
    • Lo stack deve essere simulato tramite un buffer in memoria
    • Ogni accesso allo stack corrisponde ad un accesso a memoria
    • Per ogni istruzione abbiamo più istruzioni di lettura/scrittura nello stack (come nel esempio precedente).
  • 52. VM register-based
    • Algoritmo più complicato, si deve preoccupare di accedere alla memoria per recuperare le variabili da inserire nei registri.
    • Bytecode più piccolo (perchè no operazioni stack aggiuntive).
    • Compilatori JIT possono mappare il bytecode in istruzioni hw native senza molti sforzi** quindi il processo di JITting richiede meno tempo ed è importante poichè la compilazione avviene durante l’esecuzione, ogni millisecondo è prezioso!
    • Dopo aver compilato just-in-time una procedura non è necessario ricompilarla, alla seconda chiamata verrà eseguito il codice compilato.
    • **sopratutto se l’architettura della macchina è CISC.
  • 53. Bytecode RB vs Bytecode SB High-level linguage: c = a + b; d = a + 4; e = b * 3; 5 variabili e 3 statement REG-BASED 1:getvar R1, &quot;a&quot; 2:getvar R2, &quot;b&quot; 3:getvar R3, &quot;c&quot; 4:getvar R4, &quot;d&quot; 5:getvar R5, &quot;e&quot; 6:add R3, R1, R2 7:add R4, R1, 4 8:mul R5, R2, 3 8 ops, 9 parameters 11:add 12:push 'd' 13:storevar 14:push 'b' 15:getvar 16:push 3 17:multiply 18:push 'e' 19:storevar BYTECODE register-based e BYTECODE stack-based STACK-BASED 1:push 'a' 2:getvar 3:push b' 4:getvar 5:add 6:push 'c' 7:storevar 8:push 'a' 9:getvar 10:push 4 19 ops, 9 parameters
  • 54. Dis: Compilazione Separata
    • Un file .sbl (symbol table) fornisce le informazioni sui tipi utilizzati in un file eseguibile Dis e puo' essere usato dai debuggers.
    • Viene costruita dal compilatore.
    • Il file .sbl è formato da un header seguito da 5 tabelle. Ogni tabella inizia con 1 linea che contiene il numero di elementi di quella tabella.
  • 55. Dis: Elementi della symbol table Header File table PC table Adt table Fn table Data table
  • 56. Conclusioni su Dis
    • Dis si ispira a:
    • Pascal P-machine per architettura register-based
    • Smalltalk per il bytecode
    • Smalltalk (impl VisualWorks) per il compilatore JIT
    • Lisp per il concetto di GC
  • 57. Bibliografia
    • Manuale Inferno e Limbo via Web:
    • http://www.cs.rit.edu/~ats/inferno/
    • Vita Nuova Holdings
    • http://www.vitanuova.com/
    • Download Inferno 4th Edition
    • http://www.vitanuova.com/inferno/downloads.html
    • Inferno Tutorial
    • http://www.resc.rdg.ac.uk/twiki/bin/view/Resc/InfernoTutorial